Panda3D
dxTextureContext9.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file dxTextureContext9.cxx
10  * @author georges
11  * @date 2002-02-02
12  */
13 
14 #include "config_dxgsg9.h"
16 #include "pStatTimer.h"
17 #include "dxTextureContext9.h"
18 #include "bamCache.h"
19 #include "graphicsEngine.h"
20 #include <d3dx9tex.h>
21 #include <assert.h>
22 #include <time.h>
23 
24 #define DEBUG_SURFACES false
25 #define DEBUG_TEXTURES true
26 
27 using std::endl;
28 using std::max;
29 using std::min;
30 
31 TypeHandle DXTextureContext9::_type_handle;
32 
33 static const DWORD g_LowByteMask = 0x000000FF;
34 
35 /**
36  *
37  */
38 DXTextureContext9::
39 DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
40  TextureContext(pgo, tex, view) {
41 
42  if (dxgsg9_cat.is_spam()) {
43  dxgsg9_cat.spam()
44  << "Creating DX texture [" << tex->get_name() << "], minfilter(" << tex->get_minfilter() << "), magfilter(" << tex->get_magfilter() << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n";
45  }
46 
47  _d3d_texture = nullptr;
48  _d3d_2d_texture = nullptr;
49  _d3d_volume_texture = nullptr;
50  _d3d_cube_texture = nullptr;
51  _has_mipmaps = false;
52  _is_render_target = false;
53  _managed = -1;
54 }
55 
56 /**
57  *
58  */
59 DXTextureContext9::
60 ~DXTextureContext9() {
62 }
63 
64 /**
65  * Evicts the page from the LRU. Called internally when the LRU determines
66  * that it is full. May also be called externally when necessary to
67  * explicitly evict the page.
68  *
69  * It is legal for this method to either evict the page as requested, do
70  * nothing (in which case the eviction will be requested again at the next
71  * epoch), or requeue itself on the tail of the queue (in which case the
72  * eviction will be requested again much later).
73  */
76  if (get_texture()->get_render_to_texture()) {
77  // Don't evict the result of render-to-texture.
78  mark_used_lru();
79  return;
80  }
81  if (dxgsg9_cat.is_debug()) {
82  dxgsg9_cat.debug()
83  << "Evicting " << *get_texture() << "\n";
84  }
85 
86  dequeue_lru();
88 
90  mark_unloaded();
91 }
92 
93 /**
94  * Use panda texture's pixelbuffer to create a texture for the specified
95  * device. This code gets the attributes of the texture from the bitmap,
96  * creates the texture, and then copies the bitmap into the texture. The
97  * return value is true if the texture is successfully created, false
98  * otherwise.
99  */
102 
103  // check if the texture has already been created
104  if (_d3d_2d_texture || _d3d_cube_texture || _d3d_volume_texture) {
105  // texture already created, no need to create
106  return true;
107  }
108 
109  HRESULT hr;
110  int num_alpha_bits; // number of alpha bits in texture pixfmt
111  D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
112  bool needs_luminance = false;
113  bool needs_depth = false;
114  bool needs_stencil = false;
115  bool compress_texture = false;
116 
117  Texture *tex = get_texture();
118  nassertr(IS_VALID_PTR(tex), false);
119 
120  // Ensure the ram image is loaded, if available.
121  tex->get_ram_image();
122 
123  DWORD orig_width = (DWORD)tex->get_x_size();
124  DWORD orig_height = (DWORD)tex->get_y_size();
125  DWORD orig_depth = (DWORD)tex->get_z_size();
126 
127  // check for texture compression
128  bool texture_wants_compressed = false;
129  Texture::CompressionMode compression_mode = tex->get_ram_image_compression();
130  bool texture_stored_compressed = compression_mode != Texture::CM_off;
131 
132  if (texture_stored_compressed) {
133  texture_wants_compressed = true;
134  } else {
135  if (tex->get_compression() == Texture::CM_off) {
136  // no compression
137  } else {
138  if (tex->get_compression() == Texture::CM_default) {
139  // default = use "compressed-textures" config setting
140  if (compressed_textures) {
141  texture_wants_compressed = true;
142  }
143  } else {
144  texture_wants_compressed = true;
145  }
146  }
147  }
148 
149  switch (tex->get_texture_type()) {
150  case Texture::TT_1d_texture:
151  case Texture::TT_2d_texture:
152  case Texture::TT_cube_map:
153  // no compression for render target textures, or very small textures
154  if (!tex->get_render_to_texture() &&
155  orig_width >= 4 && orig_height >= 4) {
156  if (texture_wants_compressed){
157  compress_texture = true;
158  }
159  }
160  break;
161  case Texture::TT_3d_texture:
162  // compression of 3d textures not supported by all video chips
163  break;
164  }
165 
166  if (texture_stored_compressed && !compress_texture) {
167  // If we're going to need to reload the texture to get its uncompressed
168  // image, we'd better do so now, *before* we figure out the source format.
169  // We have to do this early, even though we're going to do it again in
170  // fill_d3d_texture_pixels(), because sometimes reloading the original ram
171  // image will change the texture's apparent pixel format (the compressed
172  // form may have a different format than the uncompressed form).
174 
175  orig_width = (DWORD)tex->get_x_size();
176  orig_height = (DWORD)tex->get_y_size();
177  orig_depth = (DWORD)tex->get_z_size();
178  }
179 
180  // bpp indicates requested fmt, not texture fmt
181  DWORD target_bpp = get_bits_per_pixel(tex->get_format(), &num_alpha_bits);
182  DWORD num_color_channels = tex->get_num_components();
183 
184  // figure out what 'D3DFMT' the Texture is in, so D3DXLoadSurfFromMem knows
185  // how to perform copy
186  switch (tex->get_format()) {
187  case Texture::F_depth_stencil:
188  _d3d_format = D3DFMT_D24S8;
189  needs_depth = true;
190  needs_stencil = true;
191  break;
192 
193  case Texture::F_depth_component:
194  case Texture::F_depth_component16:
195  _d3d_format = D3DFMT_D16;
196  needs_depth = true;
197  break;
198 
199  case Texture::F_depth_component24:
200  _d3d_format = D3DFMT_D24X8;
201  needs_depth = true;
202  break;
203 
204  case Texture::F_depth_component32:
205  _d3d_format = D3DFMT_D32;
206  needs_depth = true;
207  break;
208 
209  case Texture::F_luminance:
210  case Texture::F_sluminance:
211  _d3d_format = D3DFMT_L8;
212  needs_luminance = true;
213  break;
214 
215  case Texture::F_luminance_alpha:
216  case Texture::F_luminance_alphamask:
217  case Texture::F_sluminance_alpha:
218  _d3d_format = D3DFMT_A8L8;
219  needs_luminance = true;
220  break;
221 
222  default:
223  if (num_alpha_bits > 0) {
224  if (num_color_channels == 3) {
225  dxgsg9_cat.error()
226  << "texture " << tex->get_name()
227  << " has no inherent alpha channel, but alpha format is requested!\n";
228  }
229  }
230 
231  _d3d_format = D3DFMT_UNKNOWN;
232 
233  switch (num_color_channels) {
234  case 1:
235  if (num_alpha_bits > 0) {
236  _d3d_format = D3DFMT_A8;
237  } else {
238  _d3d_format = D3DFMT_L8;
239  }
240  break;
241  case 2:
242  _d3d_format = D3DFMT_A8L8;
243  break;
244  case 3:
245  _d3d_format = D3DFMT_R8G8B8;
246  break;
247  case 4:
248  _d3d_format = D3DFMT_A8R8G8B8;
249  break;
250  }
251 
252  // make sure we handled all the possible cases
253  nassertr(_d3d_format != D3DFMT_UNKNOWN, false);
254  }
255 
256  DWORD target_width = orig_width;
257  DWORD target_height = orig_height;
258  DWORD target_depth = orig_depth;
259 
260  DWORD filter_caps;
261 
262  switch (tex->get_texture_type()) {
263  case Texture::TT_1d_texture:
264  case Texture::TT_2d_texture:
265  filter_caps = scrn._d3dcaps.TextureFilterCaps;
266 
267  if (target_width > scrn._d3dcaps.MaxTextureWidth) {
268  target_width = scrn._d3dcaps.MaxTextureWidth;
269  }
270  if (target_height > scrn._d3dcaps.MaxTextureHeight) {
271  target_height = scrn._d3dcaps.MaxTextureHeight;
272  }
273 
274  if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_POW2) {
275  if (!ISPOW2(target_width)) {
276  target_width = down_to_power_2(target_width);
277  }
278  if (!ISPOW2(target_height)) {
279  target_height = down_to_power_2(target_height);
280  }
281  }
282  break;
283 
284  case Texture::TT_3d_texture:
285  if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0) {
286  dxgsg9_cat.warning()
287  << "3-d textures are not supported by this graphics driver.\n";
288  return false;
289  }
290 
291  filter_caps = scrn._d3dcaps.VolumeTextureFilterCaps;
292 
293  if (target_width > scrn._d3dcaps.MaxVolumeExtent) {
294  target_width = scrn._d3dcaps.MaxVolumeExtent;
295  }
296  if (target_height > scrn._d3dcaps.MaxVolumeExtent) {
297  target_height = scrn._d3dcaps.MaxVolumeExtent;
298  }
299  if (target_depth > scrn._d3dcaps.MaxVolumeExtent) {
300  target_depth = scrn._d3dcaps.MaxVolumeExtent;
301  }
302 
303  if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) {
304  if (!ISPOW2(target_width)) {
305  target_width = down_to_power_2(target_width);
306  }
307  if (!ISPOW2(target_height)) {
308  target_height = down_to_power_2(target_height);
309  }
310  if (!ISPOW2(target_depth)) {
311  target_depth = down_to_power_2(target_depth);
312  }
313  }
314  break;
315 
316  case Texture::TT_cube_map:
317  if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) == 0) {
318  dxgsg9_cat.warning()
319  << "Cube map textures are not supported by this graphics driver.\n";
320  return false;
321  }
322 
323  filter_caps = scrn._d3dcaps.CubeTextureFilterCaps;
324 
325  if (target_width > scrn._d3dcaps.MaxTextureWidth) {
326  target_width = scrn._d3dcaps.MaxTextureWidth;
327  }
328 
329  if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) {
330  if (!ISPOW2(target_width)) {
331  target_width = down_to_power_2(target_width);
332  }
333  }
334 
335  target_height = target_width;
336  break;
337  }
338 
339  // checks for SQUARE reqmt (nvidia riva128 needs this)
340  if ((target_width != target_height) &&
341  (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0) {
342  // assume pow2 textures. sum exponents, divide by 2 rounding down to get
343  // sq size
344  int i, width_exp, height_exp;
345  for (i = target_width, width_exp = 0; i > 1; width_exp++, i >>= 1) {
346  }
347  for (i = target_height, height_exp = 0; i > 1; height_exp++, i >>= 1) {
348  }
349  target_height = target_width = 1<<((width_exp+height_exp)>>1);
350  }
351 
352  bool shrink_original = false;
353 
354  if (orig_width != target_width || orig_height != target_height ||
355  orig_depth != target_depth) {
356  if (tex->get_texture_type() == Texture::TT_3d_texture) {
357  dxgsg9_cat.info()
358  << "Reducing size of " << tex->get_name()
359  << " from " << orig_width << "x" << orig_height << "x" << orig_depth
360  << " to " << target_width << "x" << target_height
361  << "x" << target_depth << "\n";
362  } else {
363  dxgsg9_cat.info()
364  << "Reducing size of " << tex->get_name()
365  << " from " << orig_width << "x" << orig_height
366  << " to " << target_width << "x" << target_height << "\n";
367  }
368 
369  shrink_original = true;
370  }
371 
372  if (target_width == 0 || target_height == 0) {
373  // We can't create a zero-sized texture, so change it to 1x1.
374  target_width = 1;
375  target_height = 1;
376  }
377 
378  const char *error_message;
379 
380  error_message = "create_texture failed: couldn't find compatible device Texture Pixel Format for input texture";
381 
382  if (dxgsg9_cat.is_spam()) {
383  dxgsg9_cat.spam()
384  << "create_texture handling target bitdepth: " << target_bpp
385  << " alphabits: " << num_alpha_bits << endl;
386  }
387 
388  // I could possibly replace some of this logic with
389  // D3DXCheckTextureRequirements(), but it wouldn't handle all my specialized
390  // low-memory cases perfectly
391 
392 #define CHECK_FOR_FMT(FMT) \
393  if (scrn._supported_tex_formats_mask & FMT##_FLAG) { \
394  target_pixel_format = D3DFMT_##FMT; \
395  goto found_matching_format; }
396 
397  if (texture_stored_compressed && compress_texture) {
398  // if the texture is already compressed, we need to choose the
399  // corresponding format, otherwise we might end up cross-compressing from
400  // e.g. DXT5 to DXT3
401  switch (compression_mode){
402  case Texture::CM_dxt1:
403  CHECK_FOR_FMT(DXT1);
404  break;
405  case Texture::CM_dxt2:
406  CHECK_FOR_FMT(DXT2);
407  break;
408  case Texture::CM_dxt3:
409  CHECK_FOR_FMT(DXT3);
410  break;
411  case Texture::CM_dxt4:
412  CHECK_FOR_FMT(DXT4);
413  break;
414  case Texture::CM_dxt5:
415  CHECK_FOR_FMT(DXT5);
416  break;
417  case Texture::CM_rgtc:
418  if (num_color_channels == 1) {
419  CHECK_FOR_FMT(ATI1);
420  } else {
421  CHECK_FOR_FMT(ATI2);
422  }
423  break;
424  }
425 
426  // We don't support the compressed format. Fall through.
427  }
428 
429  if (compress_texture) {
430  if (num_color_channels == 1) {
431  CHECK_FOR_FMT(ATI1);
432  } else if (num_alpha_bits == 0 && num_color_channels == 2) {
433  CHECK_FOR_FMT(ATI2);
434  }
435  if (num_alpha_bits <= 1) {
436  CHECK_FOR_FMT(DXT1);
437  } else if (num_alpha_bits <= 4) {
438  CHECK_FOR_FMT(DXT3);
439  } else {
440  CHECK_FOR_FMT(DXT5);
441  }
442  }
443 
444  // We can't compress for some reason, so ensure the uncompressed image is
445  // ready to load.
446  if (texture_stored_compressed) {
448  compression_mode = tex->get_ram_image_compression();
449  texture_stored_compressed = compression_mode != Texture::CM_off;
450  compress_texture = false;
451  }
452 
453  // handle each target bitdepth separately. might be less confusing to reorg
454  // by num_color_channels (input type, rather than desired 1st target)
455  switch (target_bpp) {
456 
457  // IMPORTANT NOTE: target_bpp is REQUESTED bpp, not what exists in the
458  // texture array (the texture array contains num_color_channels*8bits)
459 
460  case 128:
461  // check if format is supported
462  if (scrn._supports_rgba32_texture_format) {
463  target_pixel_format = D3DFMT_A32B32G32R32F;
464  }
465  else {
466  target_pixel_format = scrn._render_to_texture_d3d_format;
467  }
468  goto found_matching_format;
469 
470  case 64:
471  // check if format is supported
472  if (scrn._supports_rgba16f_texture_format) {
473  target_pixel_format = D3DFMT_A16B16G16R16F;
474  }
475  else {
476  target_pixel_format = scrn._render_to_texture_d3d_format;
477  }
478  goto found_matching_format;
479 
480  case 32:
481  if (needs_depth) {
482  nassertr(num_alpha_bits == 0, false);
483  nassertr(num_color_channels == 1, false);
484 
485  CHECK_FOR_FMT(D32);
486  break;
487  }
488 
489  if (!((num_color_channels == 3) || (num_color_channels == 4)))
490  break; //bail
491 
492  CHECK_FOR_FMT(A8R8G8B8);
493 
494  if (num_alpha_bits>0) {
495  nassertr(num_color_channels == 4, false);
496 
497  // no 32-bit fmt, look for 16 bit walpha (1-15)
498 
499  // 32 bit RGBA was requested, but only 16 bit alpha fmts are avail. By
500  // default, convert to 4-4-4-4 which has 4-bit alpha for blurry edges.
501  // If we know tex only needs 1 bit alpha (i.e. for a mask), use 1555
502  // instead.
503 
504 
505  // ConversionType ConvTo1 = Conv32to16_4444, ConvTo2 = Conv32to16_1555;
506  // DWORD dwAlphaMask1 = 0xF000, dwAlphaMask2 = 0x8000;
507 
508  // assume ALPHAMASK is x8000 and RGBMASK is x7fff to simplify 32->16
509  // conversion. This should be true on most cards.
510 
511  if (num_alpha_bits == 1) {
512  CHECK_FOR_FMT(A1R5G5B5);
513  }
514 
515  // normally prefer 4444 due to better alpha channel resolution
516  CHECK_FOR_FMT(A4R4G4B4);
517  CHECK_FOR_FMT(A1R5G5B5);
518 
519  // At this point, bail. Don't worry about converting to non-alpha
520  // formats yet, I think this will be a very rare case.
521  error_message = "create_texture failed: couldn't find compatible Tex DDPIXELFORMAT! no available 16 or 32-bit alpha formats!";
522  } else {
523  // convert 3 or 4 channel to closest 16bpp color fmt
524 
525  if (num_color_channels == 3) {
526  CHECK_FOR_FMT(R5G6B5);
527  CHECK_FOR_FMT(X1R5G5B5);
528  } else {
529  CHECK_FOR_FMT(R5G6B5);
530  CHECK_FOR_FMT(X1R5G5B5);
531  }
532  }
533  break;
534 
535  case 24:
536  if (needs_depth) {
537  nassertr(num_alpha_bits == 0, false);
538  nassertr(num_color_channels == 1, false);
539 
540  // In DirectX 9, all built-in depth formats use shadow map filtering.
541  // Some drivers (GeForce 8000+, Radeon HD 4000+, Intel G45+) expose a
542  // FourCC format called "INTZ" that allows access to the actual depth.
543  if (tex->get_minfilter() == Texture::FT_shadow) {
544  if (needs_stencil) {
545  CHECK_FOR_FMT(D24S8);
546  }
547  CHECK_FOR_FMT(D24X8);
548  CHECK_FOR_FMT(D32);
549  CHECK_FOR_FMT(D16);
550  } else {
551  if (scrn._supported_tex_formats_mask & INTZ_FLAG) {
552  target_pixel_format = D3DFMT_INTZ;
553  goto found_matching_format;
554  }
555 
556  // We fall back to a depth format. Chances are that it is going to be
557  // used for shadow mapping, in which case the depth comparison will
558  // probably still result in a useful value.
559  CHECK_FOR_FMT(D24X8);
560  }
561  } else {
562  nassertr(num_color_channels == 3, false);
563 
564  CHECK_FOR_FMT(R8G8B8);
565 
566  // no 24-bit fmt. look for 32 bit fmt (note: this is memory-hogging
567  // choice instead I could look for memory-conserving 16-bit fmt).
568 
569  CHECK_FOR_FMT(X8R8G8B8);
570  CHECK_FOR_FMT(A8R8G8B8);
571 
572  // no 24-bit or 32 fmt. look for 16 bit fmt (higher res 565 1st)
573  CHECK_FOR_FMT(R5G6B5);
574  CHECK_FOR_FMT(X1R5G5B5);
575  CHECK_FOR_FMT(A1R5G5B5);
576  }
577  break;
578 
579  case 16:
580  if (needs_depth) {
581  nassertr(num_alpha_bits == 0, false);
582  nassertr(num_color_channels == 1, false);
583 
584  // In DirectX 9, all built-in depth formats use shadow map filtering.
585  // Some drivers (GeForce 8000+, Radeon HD 4000+, Intel G45+) expose a
586  // FourCC format called "INTZ" that allows access to the actual depth.
587  if (tex->get_minfilter() == Texture::FT_shadow) {
588  if (needs_stencil) {
589  CHECK_FOR_FMT(D24S8);
590  }
591  CHECK_FOR_FMT(D16);
592  CHECK_FOR_FMT(D24X8);
593  CHECK_FOR_FMT(D32);
594  } else {
595  if (scrn._supported_tex_formats_mask & INTZ_FLAG) {
596  target_pixel_format = D3DFMT_INTZ;
597  goto found_matching_format;
598  }
599 
600  // We fall back to a depth format. Chances are that it is going to be
601  // used for shadow mapping, in which case the depth comparison will
602  // probably still result in a useful value.
603  CHECK_FOR_FMT(D24X8);
604  }
605 
606  } else if (needs_luminance) {
607  nassertr(num_alpha_bits > 0, false);
608  nassertr(num_color_channels == 2, false);
609 
610  CHECK_FOR_FMT(A8L8);
611  CHECK_FOR_FMT(A8R8G8B8);
612 
613  if (num_alpha_bits == 1) {
614  CHECK_FOR_FMT(A1R5G5B5);
615  }
616 
617  // normally prefer 4444 due to better alpha channel resolution
618  CHECK_FOR_FMT(A4R4G4B4);
619  CHECK_FOR_FMT(A1R5G5B5);
620  } else {
621  nassertr((num_color_channels == 3)||(num_color_channels == 4), false);
622  // look for compatible 16bit fmts, if none then give up (don't worry
623  // about other bitdepths for 16 bit)
624  switch(num_alpha_bits) {
625  case 0:
626  if (num_color_channels == 3) {
627  CHECK_FOR_FMT(R5G6B5);
628  CHECK_FOR_FMT(X1R5G5B5);
629  } else {
630  nassertr(num_color_channels == 4, false);
631  // it could be 4 if user asks us to throw away the alpha channel
632  CHECK_FOR_FMT(R5G6B5);
633  CHECK_FOR_FMT(X1R5G5B5);
634  }
635  break;
636  case 1:
637  // app specifically requests 1-5-5-5 F_rgba5 case, where you
638  // explicitly want 1-5-5-5 fmt, as opposed to F_rgbm, which could use
639  // 32bpp ARGB. fail if this particular fmt not avail.
640  nassertr(num_color_channels == 4, false);
641  CHECK_FOR_FMT(X1R5G5B5);
642  break;
643  case 4:
644  // app specifically requests 4-4-4-4 F_rgba4 case, as opposed to
645  // F_rgba, which could use 32bpp ARGB
646  nassertr(num_color_channels == 4, false);
647  CHECK_FOR_FMT(A4R4G4B4);
648  break;
649  default:
650  nassertr(false, false); // problem in get_bits_per_pixel()?
651  }
652  }
653  case 8:
654  if (needs_luminance) {
655  // don't bother handling those other 8bit lum fmts like 4-4, since 16
656  // 8-8 is usually supported too
657  nassertr(num_color_channels == 1, false);
658 
659  // look for native lum fmt first
660  CHECK_FOR_FMT(L8);
661  CHECK_FOR_FMT(L8);
662 
663  CHECK_FOR_FMT(R8G8B8);
664  CHECK_FOR_FMT(X8R8G8B8);
665 
666  CHECK_FOR_FMT(R5G6B5);
667  CHECK_FOR_FMT(X1R5G5B5);
668 
669  } else if (num_alpha_bits == 8) {
670  // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444.
671 
672  // skip 8bit alpha only (D3DFMT_A8), because I think only voodoo
673  // supports it and the voodoo support isn't the kind of blending model
674  // we need somehow (is it that voodoo assumes color is white? isnt that
675  // what we do in ConvAlpha8to32 anyway?)
676 
677  CHECK_FOR_FMT(A8L8);
678  CHECK_FOR_FMT(A8R8G8B8);
679  CHECK_FOR_FMT(A4R4G4B4);
680  }
681  break;
682 
683  default:
684  error_message = "create_texture failed: unhandled pixel bitdepth in DX loader";
685  }
686 
687  // if we've gotten here, haven't found a match
688  dxgsg9_cat.error()
689  << error_message << ": " << tex->get_name() << endl
690  << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: "
691  << num_alpha_bits << "; targetbpp: " <<target_bpp
692  << "; _supported_tex_formats_mask: 0x"
693  << std::hex << scrn._supported_tex_formats_mask << std::dec
694  << "; NeedLuminance: " << needs_luminance << endl;
695  goto error_exit;
696 
697 
698  found_matching_format:
699  // We found a suitable format that matches the texture's format.
700 
701  if (tex->get_match_framebuffer_format()) {
702  // Instead of creating a texture with the found format, we will need to
703  // make one that exactly matches the framebuffer's format. Look up what
704  // that format is.
705  IDirect3DSurface9 *render_target;
706 
707  if (needs_depth) {
708  hr = scrn._d3d_device->GetDepthStencilSurface(&render_target);
709  } else {
710  hr = scrn._d3d_device->GetRenderTarget(0, &render_target);
711  }
712  if (FAILED(hr)) {
713  dxgsg9_cat.error()
714  << "GetRenderTgt failed in create_texture: " << D3DERRORSTRING(hr);
715  } else {
716  D3DSURFACE_DESC surface_desc;
717  hr = render_target->GetDesc(&surface_desc);
718  if (FAILED(hr)) {
719  dxgsg9_cat.error()
720  << "GetDesc failed in create_texture: " << D3DERRORSTRING(hr);
721  } else {
722  if (target_pixel_format != surface_desc.Format &&
723  target_pixel_format != D3DFMT_INTZ) {
724  if (dxgsg9_cat.is_debug()) {
725  dxgsg9_cat.debug()
726  << "Chose format " << D3DFormatStr(surface_desc.Format)
727  << " instead of " << D3DFormatStr(target_pixel_format)
728  << " for texture to match framebuffer.\n";
729  }
730  target_pixel_format = surface_desc.Format;
731  }
732  }
733  SAFE_RELEASE(render_target);
734  }
735  }
736 
737  // validate magfilter setting degrade filtering if no HW support
738 
739  SamplerState::FilterType ft;
740 
741  ft = tex->get_magfilter();
742  if ((ft != SamplerState::FT_linear) && ft != SamplerState::FT_nearest) {
743  // mipmap settings make no sense for magfilter
744  if (ft == SamplerState::FT_nearest_mipmap_nearest) {
745  ft = SamplerState::FT_nearest;
746  } else {
747  ft = SamplerState::FT_linear;
748  }
749  }
750 
751  if (ft == SamplerState::FT_linear &&
752  (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) {
753  ft = SamplerState::FT_nearest;
754  }
755  tex->set_magfilter(ft);
756 
757  // figure out if we are mipmapping this texture
758  ft = tex->get_minfilter();
759  _has_mipmaps = false;
760 
761  if (!dx_ignore_mipmaps) { // set if no HW mipmap capable
762  switch(ft) {
763  case SamplerState::FT_nearest_mipmap_nearest:
764  case SamplerState::FT_linear_mipmap_nearest:
765  case SamplerState::FT_nearest_mipmap_linear: // pick nearest in each, interpolate linearly b/w them
766  case SamplerState::FT_linear_mipmap_linear:
767  _has_mipmaps = true;
768  }
769 
770  if (dx_mipmap_everything) { // debug toggle, ok to leave in since its just a creation cost
771  _has_mipmaps = true;
772  if (dxgsg9_cat.is_spam()) {
773  if (ft != SamplerState::FT_linear_mipmap_linear) {
774  dxgsg9_cat.spam()
775  << "Forcing trilinear mipmapping on DX texture ["
776  << tex->get_name() << "]\n";
777  }
778  }
779  ft = SamplerState::FT_linear_mipmap_linear;
780  tex->set_minfilter(ft);
781  }
782 
783  } else if ((ft == SamplerState::FT_nearest_mipmap_nearest) || // cvt to no-mipmap filter types
784  (ft == SamplerState::FT_nearest_mipmap_linear)) {
785  ft = SamplerState::FT_nearest;
786 
787  } else if ((ft == SamplerState::FT_linear_mipmap_nearest) ||
788  (ft == SamplerState::FT_linear_mipmap_linear)) {
789  ft = SamplerState::FT_linear;
790  }
791 
792  nassertr((filter_caps & D3DPTFILTERCAPS_MINFPOINT) != 0, false);
793 
794 #define TRILINEAR_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MINFLINEAR)
795 
796  // do any other filter type degradations necessary
797  switch(ft) {
798  case SamplerState::FT_linear_mipmap_linear:
799  if ((filter_caps & TRILINEAR_MIPMAP_TEXFILTERCAPS) != TRILINEAR_MIPMAP_TEXFILTERCAPS) {
800  if (filter_caps & D3DPTFILTERCAPS_MINFLINEAR) {
801  ft = SamplerState::FT_linear_mipmap_nearest;
802  } else {
803  // if you cant do linear in a level, you probably cant do linear bw
804  // levels, so just do nearest-all
805  ft = SamplerState::FT_nearest_mipmap_nearest;
806  }
807  }
808  break;
809 
810  case SamplerState::FT_nearest_mipmap_linear:
811  // if we don't have bilinear, do nearest_nearest
812  if (!((filter_caps & D3DPTFILTERCAPS_MIPFPOINT) &&
813  (filter_caps & D3DPTFILTERCAPS_MINFLINEAR))) {
814  ft = SamplerState::FT_nearest_mipmap_nearest;
815  }
816  break;
817 
818  case SamplerState::FT_linear_mipmap_nearest:
819  // if we don't have mip linear, do nearest_nearest
820  if (!(filter_caps & D3DPTFILTERCAPS_MIPFLINEAR)) {
821  ft = SamplerState::FT_nearest_mipmap_nearest;
822  }
823  break;
824 
825  case SamplerState::FT_linear:
826  if (!(filter_caps & D3DPTFILTERCAPS_MINFLINEAR)) {
827  ft = SamplerState::FT_nearest;
828  }
829  break;
830  }
831 
832  tex->set_minfilter(ft);
833 
834  uint aniso_degree;
835 
836  aniso_degree = 1;
837  if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) {
838  aniso_degree = tex->get_anisotropic_degree();
839  if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) ||
840  dx_force_anisotropic_filtering) {
841  aniso_degree = scrn._d3dcaps.MaxAnisotropy;
842  }
843  }
844  tex->set_anisotropic_degree(aniso_degree);
845 
846 #ifdef _DEBUG
847  dxgsg9_cat.spam()
848  << "create_texture: setting aniso degree for " << tex->get_name()
849  << " to: " << aniso_degree << endl;
850 #endif
851 
852  UINT mip_level_count;
853 
854  if (_has_mipmaps) {
855  tex->get_ram_image();
856  mip_level_count = tex->get_num_loadable_ram_mipmap_images();
857  if (mip_level_count < 2) {
858  // tell CreateTex to alloc space for all mip levels down to 1x1
859  mip_level_count = 0;
860 
861  if (dxgsg9_cat.is_debug()) {
862  dxgsg9_cat.debug()
863  << "create_texture: generating mipmaps for " << tex->get_name()
864  << endl;
865  }
866  }
867 
868  // DirectX will corrupt memory if we try to load mipmaps smaller than 4x4
869  // for ATI1 or ATI2 textures.
870  if (target_pixel_format == D3DFMT_ATI1 ||
871  target_pixel_format == D3DFMT_ATI2) {
872 
873  UINT dimension = min(target_height, target_width);
874  mip_level_count = 0;
875  while (dimension >= 4) {
876  ++mip_level_count;
877  dimension >>= 1;
878  }
879 
880  if ((UINT)tex->get_num_ram_mipmap_images() < mip_level_count) {
881  // We also have to generate mipmaps on the CPU for these.
883  mip_level_count = min(mip_level_count, (UINT)tex->get_num_ram_mipmap_images());
884  }
885  }
886  } else {
887  mip_level_count = 1;
888  }
889 
890  DWORD usage;
891  D3DPOOL pool;
892 
893  if (tex->get_render_to_texture ( )) {
894  // REQUIRED PARAMETERS
895  _managed = false;
896  _is_render_target = true;
897 
898  pool = D3DPOOL_DEFAULT;
899  if (needs_depth) {
900  usage = D3DUSAGE_DEPTHSTENCIL;
901  } else {
902  usage = D3DUSAGE_RENDERTARGET;
903  }
904  // if (target_bpp <= 32) { target_pixel_format =
905  // scrn._render_to_texture_d3d_format; }
906 
907  dxgsg9_cat.debug ()
908  << "*** RENDER TO TEXTURE ***: format "
909  << D3DFormatStr(target_pixel_format)
910  << " "
911  << target_pixel_format
912  << "\n";
913  }
914  else {
915  _managed = scrn._managed_textures;
916  if (_managed) {
917  pool = D3DPOOL_MANAGED;
918  usage = 0;
919  }
920  else {
921  if (scrn._supports_automatic_mipmap_generation) {
922  pool = D3DPOOL_DEFAULT;
923  usage = D3DUSAGE_AUTOGENMIPMAP;
924  }
925  else {
926  if (dx_use_dynamic_textures) {
927  if (scrn._supports_dynamic_textures) {
928  pool = D3DPOOL_DEFAULT;
929  usage = D3DUSAGE_DYNAMIC;
930  }
931  else {
932  // can't lock textures so go back to managed for now need to use
933  // UpdateTexture or UpdateSurface
934  _managed = true;
935  pool = D3DPOOL_MANAGED;
936  usage = 0;
937  }
938  }
939  else {
940  pool = D3DPOOL_DEFAULT;
941  usage = 0;
942  }
943  }
944  }
945  }
946 
947  PN_stdfloat bytes_per_texel;
948 
949  bytes_per_texel = this -> d3d_format_to_bytes_per_pixel (target_pixel_format);
950  if (bytes_per_texel == 0.0f) {
951  dxgsg9_cat.error()
952  << "D3D create_texture ( ) unknown texture format\n";
953  }
954 
955  int data_size;
956 
957  data_size = target_width * target_height * target_depth;
958  if (_has_mipmaps) {
959  data_size = (int) ((PN_stdfloat) data_size * 1.3333333);
960  }
961  data_size = (int) ((PN_stdfloat) data_size * bytes_per_texel);
962  if (tex->get_texture_type() == Texture::TT_cube_map) {
963  data_size *= 6;
964  }
965  update_data_size_bytes(data_size);
966 
967  int attempts;
968 
969  if (dxgsg9_cat.is_debug()) {
970  dxgsg9_cat.debug()
971  << "Creating " << *tex << ", " << data_size << " bytes, "
972  << scrn._d3d_device->GetAvailableTextureMem()
973  << " reported available.\n";
974  dxgsg9_cat.debug()
975  << " size is " << target_width << " w * " << target_height << " h * "
976  << target_depth << " d";
977  if (_has_mipmaps) {
978  dxgsg9_cat.debug(false)
979  << " * 1.3333333 mipmaps";
980  }
981  dxgsg9_cat.debug(false)
982  << " * " << bytes_per_texel << " bpt";
983  if (tex->get_texture_type() == Texture::TT_cube_map) {
984  dxgsg9_cat.debug(false)
985  << " * 6 faces";
986  }
987  dxgsg9_cat.debug(false)
988  << "\n";
989  }
990 
991  attempts = 0;
992  do
993  {
994  switch (tex->get_texture_type()) {
995  case Texture::TT_1d_texture:
996  case Texture::TT_2d_texture:
997  hr = scrn._d3d_device->CreateTexture
998  (target_width, target_height, mip_level_count, usage,
999  target_pixel_format, pool, &_d3d_2d_texture, nullptr);
1000  _d3d_texture = _d3d_2d_texture;
1001  break;
1002 
1003  case Texture::TT_3d_texture:
1004  hr = scrn._d3d_device->CreateVolumeTexture
1005  (target_width, target_height, target_depth, mip_level_count, usage,
1006  target_pixel_format, pool, &_d3d_volume_texture, nullptr);
1007  _d3d_texture = _d3d_volume_texture;
1008  break;
1009 
1010  case Texture::TT_cube_map:
1011  hr = scrn._d3d_device->CreateCubeTexture
1012  (target_width, mip_level_count, usage,
1013  target_pixel_format, pool, &_d3d_cube_texture, nullptr);
1014  _d3d_texture = _d3d_cube_texture;
1015 
1016  target_height = target_width;
1017  break;
1018  }
1019 
1020  attempts++;
1021  } while (scrn._dxgsg9 -> check_dx_allocation (hr, data_size, attempts));
1022 
1023  if (FAILED(hr)) {
1024  dxgsg9_cat.error()
1025  << "D3D create_texture failed!" << D3DERRORSTRING(hr);
1026  dxgsg9_cat.error()
1027  << " width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n";
1028 
1029  goto error_exit;
1030  }
1031 
1032  if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) {
1033  dxgsg9_cat.debug()
1034  << "create_texture: " << tex->get_name()
1035  << " converting panda equivalent of " << D3DFormatStr(_d3d_format)
1036  << " => " << D3DFormatStr(target_pixel_format) << endl;
1037  }
1038 
1039  hr = fill_d3d_texture_pixels(scrn, compress_texture);
1040  if (FAILED(hr)) {
1041 
1042  dxgsg9_cat.debug ()
1043  << "*** fill_d3d_texture_pixels failed ***: format "
1044  << target_pixel_format
1045  << "\n";
1046 
1047  goto error_exit;
1048  }
1049 
1050  if (tex->get_post_load_store_cache()) {
1051  tex->set_post_load_store_cache(false);
1052  // OK, get the RAM image, and save it in a BamCache record.
1053  if (extract_texture_data(scrn)) {
1054  if (tex->has_ram_image()) {
1056  PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo");
1057  if (record != nullptr) {
1058  record->set_data(tex, tex);
1059  cache->store(record);
1060  }
1061  }
1062  }
1063  }
1064 
1065  // must not put render to texture into LRU
1066  if (!_managed && !tex->get_render_to_texture()) {
1067  scrn._dxgsg9->get_engine()->texture_uploaded(tex);
1068  }
1069  mark_loaded();
1070 
1071  return true;
1072 
1073  error_exit:
1074 
1075  RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
1076  _d3d_2d_texture = nullptr;
1077  _d3d_volume_texture = nullptr;
1078  _d3d_cube_texture = nullptr;
1079  return false;
1080 }
1081 
1082 /**
1083  *
1084  */
1085 bool DXTextureContext9::
1086 create_simple_texture(DXScreenData &scrn) {
1087  nassertr(IS_VALID_PTR(get_texture()), false);
1088 
1089  HRESULT hr;
1090 
1091  delete_texture();
1092 
1093  _d3d_format = D3DFMT_A8R8G8B8;
1094  D3DFORMAT target_pixel_format = D3DFMT_A8R8G8B8;
1095  DWORD target_bpp = 32;
1096  DWORD num_color_channels = 4;
1097 
1098  DWORD target_width = (DWORD)get_texture()->get_simple_x_size();
1099  DWORD target_height = (DWORD)get_texture()->get_simple_y_size();
1100  DWORD mip_level_count = 1;
1101  DWORD usage = 0;
1102  D3DPOOL pool = D3DPOOL_MANAGED;
1103 
1104  int data_size = target_width * target_height * 4;
1105 
1106  hr = scrn._d3d_device->CreateTexture
1107  (target_width, target_height, mip_level_count, usage,
1108  target_pixel_format, pool, &_d3d_2d_texture, nullptr);
1109  _d3d_texture = _d3d_2d_texture;
1110  if (FAILED(hr)) {
1111  dxgsg9_cat.error()
1112  << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr);
1113  dxgsg9_cat.error()
1114  << " width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n";
1115 
1116  goto error_exit;
1117  }
1118 
1119  if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) {
1120  dxgsg9_cat.debug()
1121  << "create_simple_texture: " << get_texture()->get_name()
1122  << "\n";
1123  }
1124 
1125  {
1127 
1128  hr = -1;
1129  // hr = fill_d3d_texture_pixels(scrn);
1130 
1131  IDirect3DSurface9 *surface = nullptr;
1132  _d3d_2d_texture->GetSurfaceLevel(0, &surface);
1133 
1134  RECT source_size;
1135  source_size.left = source_size.top = 0;
1136  source_size.right = target_width;
1137  source_size.bottom = target_height;
1138 
1139  DWORD mip_filter = D3DX_FILTER_LINEAR;
1140 
1141  hr = D3DXLoadSurfaceFromMemory
1142  (surface, nullptr, nullptr, (LPCVOID)image.p(),
1143  target_pixel_format, target_width * 4, nullptr,
1144  &source_size, mip_filter, (D3DCOLOR)0x0);
1145 
1146  RELEASE(surface, dxgsg9, "create_simple_texture Surface", RELEASE_ONCE);
1147  }
1148 
1149  if (FAILED(hr)) {
1150  dxgsg9_cat.debug ()
1151  << "*** fill_d3d_texture_pixels failed ***: format "
1152  << target_pixel_format
1153  << "\n";
1154 
1155  goto error_exit;
1156  }
1157 
1159  return true;
1160 
1161  error_exit:
1162  RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
1163  _d3d_2d_texture = nullptr;
1164  _d3d_volume_texture = nullptr;
1165  _d3d_cube_texture = nullptr;
1166  return false;
1167 }
1168 
1169 /**
1170  * Release the surface used to store the texture
1171  */
1174 
1175  if (_d3d_texture == nullptr) {
1176  // don't bother printing the msg below, since we already released it.
1177  return;
1178  }
1179 
1180  RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
1181  _d3d_2d_texture = nullptr;
1182  _d3d_volume_texture = nullptr;
1183  _d3d_cube_texture = nullptr;
1184 }
1185 
1186 /**
1187  * This method will be called in the draw thread to download the texture
1188  * memory's image into its ram_image value. It returns true on success, false
1189  * otherwise.
1190  */
1193  bool state;
1194  HRESULT hr;
1195 
1196  state = false;
1197  Texture *tex = get_texture();
1198  if (tex->get_texture_type() != Texture::TT_2d_texture) {
1199  dxgsg9_cat.error()
1200  << "Not supported: extract_texture_data for " << tex->get_texture_type()
1201  << "\n";
1202  return state;
1203  }
1204  nassertr(IS_VALID_PTR(_d3d_2d_texture), false);
1205 
1206  D3DSURFACE_DESC desc;
1207  hr = _d3d_2d_texture->GetLevelDesc(0, &desc);
1208  if (FAILED(hr)) {
1209  dxgsg9_cat.error()
1210  << "Texture::GetLevelDesc() failed!" << D3DERRORSTRING(hr);
1211  return state;
1212  }
1213 
1214  int div = 1;
1215  Texture::Format format = Texture::F_rgba;
1216  Texture::CompressionMode compression = Texture::CM_off;
1217 
1218  switch (desc.Format) {
1219  case D3DFMT_R8G8B8:
1220  format = Texture::F_rgb;
1221  break;
1222 
1223  case D3DFMT_A8R8G8B8:
1224  case D3DFMT_X8R8G8B8:
1225  break;
1226 
1227  case D3DFMT_L8:
1228  format = Texture::F_luminance;
1229  break;
1230 
1231  case D3DFMT_A8L8:
1232  format = Texture::F_luminance_alpha;
1233  break;
1234 
1235  case D3DFMT_D24S8:
1236  format = Texture::F_depth_stencil;
1237  break;
1238 
1239  case D3DFMT_D16:
1240  format = Texture::F_depth_component16;
1241  break;
1242 
1243  case D3DFMT_D24X8:
1244  format = Texture::F_depth_component24;
1245  break;
1246 
1247  case D3DFMT_D32:
1248  format = Texture::F_depth_component32;
1249  break;
1250 
1251  case D3DFMT_DXT1:
1252  compression = Texture::CM_dxt1;
1253  div = 4;
1254  break;
1255  case D3DFMT_DXT2:
1256  compression = Texture::CM_dxt2;
1257  div = 4;
1258  break;
1259  case D3DFMT_DXT3:
1260  compression = Texture::CM_dxt3;
1261  div = 4;
1262  break;
1263  case D3DFMT_DXT4:
1264  compression = Texture::CM_dxt4;
1265  div = 4;
1266  break;
1267  case D3DFMT_DXT5:
1268  compression = Texture::CM_dxt5;
1269  div = 4;
1270  break;
1271  case D3DFMT_ATI1:
1272  case D3DFMT_ATI2:
1273  compression = Texture::CM_rgtc;
1274  div = 4;
1275  break;
1276 
1277  default:
1278  dxgsg9_cat.error()
1279  << "Cannot extract texture data: unhandled surface format "
1280  << desc.Format << "\n";
1281  return state;
1282  }
1283 
1284  int num_levels = _d3d_2d_texture->GetLevelCount();
1285 
1286  tex->set_x_size(desc.Width);
1287  tex->set_y_size(desc.Height);
1288  tex->set_z_size(1);
1289  tex->set_component_type(Texture::T_unsigned_byte);
1290  tex->set_format(format);
1291  tex->clear_ram_image();
1292 
1293  if (_is_render_target) {
1294  IDirect3DSurface9* source_surface;
1295  IDirect3DSurface9* destination_surface;
1296 
1297  source_surface = 0;
1298  destination_surface = 0;
1299 
1300  hr = _d3d_2d_texture -> GetSurfaceLevel (0, &source_surface);
1301  if (hr == D3D_OK) {
1302 
1303  D3DPOOL pool;
1304  D3DSURFACE_DESC surface_description;
1305 
1306  pool = D3DPOOL_SYSTEMMEM;
1307  source_surface -> GetDesc (&surface_description);
1308 
1309  hr = screen._d3d_device->CreateOffscreenPlainSurface (
1310  surface_description.Width,
1311  surface_description.Height,
1312  surface_description.Format,
1313  pool,
1314  &destination_surface,
1315  nullptr);
1316  if (hr == D3D_OK) {
1317  if (source_surface && destination_surface) {
1318  hr = screen._d3d_device -> GetRenderTargetData (source_surface, destination_surface);
1319  if (hr == D3D_OK) {
1320 
1321  D3DLOCKED_RECT rect;
1322 
1323  hr = destination_surface -> LockRect (&rect, nullptr, D3DLOCK_READONLY);
1324  if (hr == D3D_OK) {
1325 
1326  unsigned int y;
1327  int size;
1328  int bytes_per_line;
1329 
1330  int surface_bytes_per_line;
1331  unsigned char *surface_pointer;
1332 
1333  bytes_per_line = surface_description.Width * this -> d3d_format_to_bytes_per_pixel (surface_description.Format);
1334  size = bytes_per_line * surface_description.Height;
1335 
1336  surface_bytes_per_line = rect.Pitch;
1337  surface_pointer = (unsigned char *) rect.pBits;
1338 
1339  PTA_uchar image = PTA_uchar::empty_array(size);
1340 
1341  int offset;
1342 
1343  offset = 0;
1344  for (y = 0; y < surface_description.Height; y++)
1345  {
1346  memcpy (&image [offset], surface_pointer, bytes_per_line);
1347 
1348  offset += bytes_per_line;
1349  surface_pointer += surface_bytes_per_line;
1350  }
1351 
1352  tex->set_ram_image(image, Texture::CM_off);
1353 
1354  state = true;
1355 
1356  destination_surface -> UnlockRect();
1357  }
1358  }
1359  }
1360 
1361  destination_surface -> Release ( );
1362  }
1363  else {
1364  dxgsg9_cat.error()
1365  << "CreateImageSurface failed in extract_texture_data()"
1366  << D3DERRORSTRING(hr);
1367  }
1368  source_surface -> Release ( );
1369  }
1370  }
1371  else {
1372  for (int n = 0; n < num_levels; ++n) {
1373  D3DLOCKED_RECT rect;
1374  hr = _d3d_2d_texture->LockRect(n, &rect, nullptr, D3DLOCK_READONLY);
1375  if (FAILED(hr)) {
1376  dxgsg9_cat.error()
1377  << "Texture::LockRect() failed! level = " << n << " " << D3DERRORSTRING(hr);
1378  return state;
1379  }
1380 
1381  int x_size = tex->get_expected_mipmap_x_size(n);
1382  int y_size = tex->get_expected_mipmap_y_size(n);
1383  PTA_uchar image;
1384 
1385  if (compression == Texture::CM_off) {
1386  // Uncompressed, but we have to respect the pitch.
1387  int pitch = x_size * tex->get_num_components() * tex->get_component_width();
1388  pitch = min(pitch, (int)rect.Pitch);
1389  int size = pitch * y_size;
1390  image = PTA_uchar::empty_array(size);
1391  if (pitch == rect.Pitch) {
1392  // Easy copy.
1393  memcpy(image.p(), rect.pBits, size);
1394  } else {
1395  // Harder copy: we have to de-interleave DirectX's extra bytes on
1396  // the end of each row.
1397  unsigned char *dest = image.p();
1398  unsigned char *source = (unsigned char *)rect.pBits;
1399  for (int yi = 0; yi < y_size; ++yi) {
1400  memcpy(dest, source, pitch);
1401  dest += pitch;
1402  source += rect.Pitch;
1403  }
1404  }
1405 
1406  } else {
1407  // Compressed; just copy the data verbatim.
1408  int size = rect.Pitch * (y_size / div);
1409  image = PTA_uchar::empty_array(size);
1410  memcpy(image.p(), rect.pBits, size);
1411  }
1412 
1413  _d3d_2d_texture->UnlockRect(n);
1414  if (n == 0) {
1415  tex->set_ram_image(image, compression);
1416  } else {
1417  tex->set_ram_mipmap_image(n, image);
1418  }
1419  }
1420 
1421  state = true;
1422  }
1423 
1424  return state;
1425 }
1426 
1427 /**
1428  * copies source_rect in pD3DSurf to upper left of texture
1429  */
1430 HRESULT DXTextureContext9::
1431 d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface,
1432  bool inverted, Texture *result, int view, int z) {
1433 
1434  // still need custom conversion since d3dd3dx has no way to convert
1435  // arbitrary fmt to ARGB in-memory user buffer
1436 
1437  HRESULT hr;
1438  DWORD num_components = result->get_num_components();
1439 
1440  nassertr(result->get_component_width() == sizeof(BYTE), E_FAIL); // cant handle anything else now
1441  nassertr(result->get_component_type() == Texture::T_unsigned_byte, E_FAIL); // cant handle anything else now
1442  nassertr((num_components == 3) || (num_components == 4), E_FAIL); // cant handle anything else now
1443  nassertr(IS_VALID_PTR(d3d_surface), E_FAIL);
1444 
1445  BYTE *buf = result->modify_ram_image();
1446  if (z >= 0) {
1447  nassertr(z < result->get_z_size(), E_FAIL);
1448  buf += z * result->get_expected_ram_page_size();
1449  }
1450  if (view > 0) {
1451  buf += (view * result->get_z_size()) * result->get_expected_ram_page_size();
1452  }
1453 
1454  if (IsBadWritePtr(d3d_surface, sizeof(DWORD))) {
1455  dxgsg9_cat.error()
1456  << "d3d_surface_to_texture failed: bad pD3DSurf ptr value ("
1457  << ((void*)d3d_surface) << ")\n";
1458  exit(1);
1459  }
1460 
1461  DWORD x_window_offset, y_window_offset;
1462  DWORD copy_width, copy_height;
1463 
1464  D3DLOCKED_RECT locked_rect;
1465  D3DSURFACE_DESC surface_desc;
1466 
1467  hr = d3d_surface->GetDesc(&surface_desc);
1468 
1469  x_window_offset = source_rect.left, y_window_offset = source_rect.top;
1470  copy_width = RECT_XSIZE(source_rect);
1471  copy_height = RECT_YSIZE(source_rect);
1472 
1473  // make sure there's enough space in the texture, its size must match
1474  // (especially xsize) or scanlines will be too long
1475 
1476  if (!((copy_width == result->get_x_size()) && (copy_height <= (DWORD)result->get_y_size()))) {
1477  dxgsg9_cat.error()
1478  << "d3d_surface_to_texture, Texture size (" << result->get_x_size()
1479  << ", " << result->get_y_size()
1480  << ") too small to hold display surface ("
1481  << copy_width << ", " << copy_height << ")\n";
1482  nassertr(false, E_FAIL);
1483  return E_FAIL;
1484  }
1485 
1486  hr = d3d_surface->LockRect(&locked_rect, nullptr, (D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE));
1487  if (FAILED(hr)) {
1488  dxgsg9_cat.error()
1489  << "d3d_surface_to_texture LockRect() failed!" << D3DERRORSTRING(hr);
1490  return hr;
1491  }
1492 
1493  // ones not listed not handled yet
1494  nassertr((surface_desc.Format == D3DFMT_A8R8G8B8) ||
1495  (surface_desc.Format == D3DFMT_X8R8G8B8) ||
1496  (surface_desc.Format == D3DFMT_R8G8B8) ||
1497  (surface_desc.Format == D3DFMT_R5G6B5) ||
1498  (surface_desc.Format == D3DFMT_X1R5G5B5) ||
1499  (surface_desc.Format == D3DFMT_A1R5G5B5) ||
1500  (surface_desc.Format == D3DFMT_A4R4G4B4), E_FAIL);
1501 
1502  // buf contains raw ARGB in Texture byteorder
1503 
1504  int byte_pitch = locked_rect.Pitch;
1505  BYTE *surface_bytes = (BYTE *)locked_rect.pBits;
1506 
1507  if (inverted) {
1508  surface_bytes += byte_pitch * (y_window_offset + copy_height - 1);
1509  byte_pitch = -byte_pitch;
1510  } else {
1511  surface_bytes += byte_pitch * y_window_offset;
1512  }
1513 
1514  // writes out last line in DDSurf first in PixelBuf, so Y line order
1515  // precedes inversely
1516 
1517  if (DEBUG_SURFACES && dxgsg9_cat.is_debug()) {
1518  dxgsg9_cat.debug()
1519  << "d3d_surface_to_texture converting "
1520  << D3DFormatStr(surface_desc.Format)
1521  << " DDSurf to " << num_components << "-channel panda Texture\n";
1522  }
1523 
1524  DWORD *dest_word = (DWORD *)buf;
1525  BYTE *dest_byte = (BYTE *)buf;
1526 
1527  switch(surface_desc.Format) {
1528  case D3DFMT_A8R8G8B8:
1529  case D3DFMT_X8R8G8B8: {
1530  if (num_components == 4) {
1531  DWORD *source_word;
1532  BYTE *dest_line = (BYTE*)dest_word;
1533 
1534  for (DWORD y = 0; y < copy_height; y++) {
1535  source_word = ((DWORD*)surface_bytes) + x_window_offset;
1536  memcpy(dest_line, source_word, byte_pitch);
1537  dest_line += byte_pitch;
1538  surface_bytes += byte_pitch;
1539  }
1540  } else {
1541  // 24bpp texture case (numComponents == 3)
1542  DWORD *source_word;
1543  for (DWORD y = 0; y < copy_height; y++) {
1544  source_word = ((DWORD*)surface_bytes) + x_window_offset;
1545 
1546  for (DWORD x = 0; x < copy_width; x++) {
1547  BYTE r, g, b;
1548  DWORD pixel = *source_word;
1549 
1550  r = (BYTE)((pixel>>16) & g_LowByteMask);
1551  g = (BYTE)((pixel>> 8) & g_LowByteMask);
1552  b = (BYTE)((pixel ) & g_LowByteMask);
1553 
1554  *dest_byte++ = b;
1555  *dest_byte++ = g;
1556  *dest_byte++ = r;
1557  source_word++;
1558  }
1559  surface_bytes += byte_pitch;
1560  }
1561  }
1562  break;
1563  }
1564 
1565  case D3DFMT_R8G8B8: {
1566  BYTE *source_byte;
1567 
1568  if (num_components == 4) {
1569  for (DWORD y = 0; y < copy_height; y++) {
1570  source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE);
1571  for (DWORD x = 0; x < copy_width; x++) {
1572  DWORD r, g, b;
1573 
1574  b = *source_byte++;
1575  g = *source_byte++;
1576  r = *source_byte++;
1577 
1578  *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b;
1579  dest_word++;
1580  }
1581  surface_bytes += byte_pitch;
1582  }
1583  } else {
1584  // 24bpp texture case (numComponents == 3)
1585  for (DWORD y = 0; y < copy_height; y++) {
1586  source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE);
1587  memcpy(dest_byte, source_byte, byte_pitch);
1588  dest_byte += byte_pitch;
1589  surface_bytes += byte_pitch;
1590  }
1591  }
1592  break;
1593  }
1594 
1595  case D3DFMT_R5G6B5:
1596  case D3DFMT_X1R5G5B5:
1597  case D3DFMT_A1R5G5B5:
1598  case D3DFMT_A4R4G4B4: {
1599  WORD *source_word;
1600  // handle 0555, 1555, 0565, 4444 in same loop
1601 
1602  BYTE redshift, greenshift, blueshift;
1603  DWORD redmask, greenmask, bluemask;
1604 
1605  if (surface_desc.Format == D3DFMT_R5G6B5) {
1606  redshift = (11-3);
1607  redmask = 0xF800;
1608  greenmask = 0x07E0;
1609  greenshift = (5-2);
1610  bluemask = 0x001F;
1611  blueshift = 3;
1612  } else if (surface_desc.Format == D3DFMT_A4R4G4B4) {
1613  redmask = 0x0F00;
1614  redshift = 4;
1615  greenmask = 0x00F0;
1616  greenshift = 0;
1617  bluemask = 0x000F;
1618  blueshift = 4;
1619  } else { // 1555 or x555
1620  redmask = 0x7C00;
1621  redshift = (10-3);
1622  greenmask = 0x03E0;
1623  greenshift = (5-3);
1624  bluemask = 0x001F;
1625  blueshift = 3;
1626  }
1627 
1628  if (num_components == 4) {
1629  // Note: these 16bpp loops ignore input alpha completely (alpha is set
1630  // to fully opaque in texture!)
1631 
1632  // if we need to capture alpha, probably need to make separate loops for
1633  // diff 16bpp fmts for best speed
1634 
1635  for (DWORD y = 0; y < copy_height; y++) {
1636  source_word = ((WORD*)surface_bytes) + x_window_offset;
1637  for (DWORD x = 0; x < copy_width; x++) {
1638  WORD pixel = *source_word;
1639  BYTE r, g, b;
1640 
1641  b = (pixel & bluemask) << blueshift;
1642  g = (pixel & greenmask) >> greenshift;
1643  r = (pixel & redmask) >> redshift;
1644 
1645  // alpha is just set to 0xFF
1646 
1647  *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b;
1648  source_word++;
1649  dest_word++;
1650  }
1651  surface_bytes += byte_pitch;
1652  }
1653  } else {
1654  // 24bpp texture case (numComponents == 3)
1655  for (DWORD y = 0; y < copy_height; y++) {
1656  source_word = ((WORD*)surface_bytes) + x_window_offset;
1657  for (DWORD x = 0; x < copy_width; x++) {
1658  WORD pixel = *source_word;
1659  BYTE r, g, b;
1660 
1661  b = (pixel & bluemask) << blueshift;
1662  g = (pixel & greenmask) >> greenshift;
1663  r = (pixel & redmask) >> redshift;
1664 
1665  *dest_byte++ = b;
1666  *dest_byte++ = g;
1667  *dest_byte++ = r;
1668 
1669  source_word++;
1670  }
1671  surface_bytes += byte_pitch;
1672  }
1673  }
1674  break;
1675  }
1676 
1677  default:
1678  dxgsg9_cat.error()
1679  << "d3d_surface_to_texture: unsupported D3DFORMAT!\n";
1680  }
1681 
1682  d3d_surface->UnlockRect();
1683  return S_OK;
1684 }
1685 
1686 /**
1687  * local helper function, which calculates the 'row_byte_length' or 'pitch'
1688  * needed for calling D3DXLoadSurfaceFromMemory. Takes compressed formats
1689  * (DXTn) into account.
1690  */
1691 static UINT calculate_row_byte_length (int width, int num_color_channels, D3DFORMAT tex_format)
1692 {
1693  UINT source_row_byte_length = 0;
1694 
1695  // check for compressed textures and adjust source_row_byte_length and
1696  // source_format accordingly
1697  switch (tex_format) {
1698  case D3DFMT_DXT1:
1699  case D3DFMT_ATI1:
1700  // for dxt1 compressed textures, the row_byte_lenght is "the width
1701  // of one row of cells, in bytes" cells are 4 pixels wide, take up 8
1702  // bytes, and at least 1 cell has to be there.
1703  source_row_byte_length = max(1,width / 4)*8;
1704  break;
1705  case D3DFMT_DXT2:
1706  case D3DFMT_DXT3:
1707  case D3DFMT_DXT4:
1708  case D3DFMT_DXT5:
1709  case D3DFMT_ATI2:
1710  // analogue as above, but cells take up 16 bytes
1711  source_row_byte_length = max(1,width / 4)*16;
1712  break;
1713  default:
1714  // no known compression format.. usual calculation
1715  source_row_byte_length = width*num_color_channels;
1716  break;
1717  }
1718  return source_row_byte_length;
1719 }
1720 
1721 /**
1722  * Called from fill_d3d_texture_pixels, this function fills a single mipmap
1723  * with texture data. Takes care of all necessary conversions and error
1724  * handling.
1725  */
1726 HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format)
1727 {
1728  // This whole function was refactored out of fill_d3d_texture_pixels to make
1729  // the code more readable and to avoid code duplication.
1730  IDirect3DSurface9 *mip_surface = nullptr;
1731  bool using_temp_buffer = false;
1732  HRESULT hr = E_FAIL;
1733  CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
1734  BYTE *pixels = (BYTE*) image.p();
1735  DWORD width = (DWORD) get_texture()->get_expected_mipmap_x_size(mip_level);
1736  DWORD height = (DWORD) get_texture()->get_expected_mipmap_y_size(mip_level);
1737  int component_width = get_texture()->get_component_width();
1738 
1739  size_t page_size = get_texture()->get_expected_ram_mipmap_page_size(mip_level);
1740  size_t view_size;
1741  vector_uchar clear_data;
1742  if (page_size > 0) {
1743  if (image.is_null()) {
1744  // Make an image, filled with the texture's clear color.
1745  image = get_texture()->make_ram_mipmap_image(mip_level);
1746  nassertr(!image.is_null(), E_FAIL);
1747  pixels = (BYTE *)image.p();
1748  }
1749  view_size = image.size();
1750  pixels += view_size * get_view();
1751  pixels += page_size * depth_index;
1752  } else {
1753  // This is a 0x0 texture, which gets loaded as though it were 1x1.
1754  width = 1;
1755  height = 1;
1756  clear_data = get_texture()->get_clear_data();
1757  pixels = clear_data.data();
1758  view_size = clear_data.size();
1759  }
1760 
1761  if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
1762  nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
1763  hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)depth_index, mip_level, &mip_surface);
1764  } else {
1765  nassertr(IS_VALID_PTR(_d3d_2d_texture), E_FAIL);
1766  hr = _d3d_2d_texture->GetSurfaceLevel(mip_level, &mip_surface);
1767  }
1768 
1769  if (FAILED(hr)) {
1770  dxgsg9_cat.error()
1771  << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
1772  << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
1773  return E_FAIL;
1774  }
1775 
1776  RECT source_size;
1777  source_size.left = source_size.top = 0;
1778  source_size.right = width;
1779  source_size.bottom = height;
1780 
1781  UINT source_row_byte_length = calculate_row_byte_length(width, get_texture()->get_num_components(), source_format);
1782 
1783  DWORD mip_filter;
1784  // need filtering if size changes, (also if bitdepth reduced (need
1785  // dithering)??)
1786  mip_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures
1787 
1788  if (Texture::is_srgb(get_texture()->get_format())) {
1789  mip_filter |= D3DX_FILTER_SRGB;
1790  }
1791 
1792  // D3DXLoadSurfaceFromMemory will load black luminance and we want full
1793  // white, so convert to explicit luminance-alpha format
1794  if (_d3d_format == D3DFMT_A8) {
1795  // alloc buffer for explicit D3DFMT_A8L8
1796  USHORT *temp_buffer = new USHORT[width * height];
1797  if (!IS_VALID_PTR(temp_buffer)) {
1798  dxgsg9_cat.error()
1799  << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
1800  goto exit_FillMipmapSurf;
1801  }
1802  using_temp_buffer = true;
1803 
1804  USHORT *out_pixels = temp_buffer;
1805  BYTE *source_pixels = pixels + component_width - 1;
1806  for (UINT y = 0; y < height; y++) {
1807  for (UINT x = 0; x < width; x++, source_pixels += component_width, out_pixels++) {
1808  // add full white, which is our interpretation of alpha-only (similar
1809  // to default adding full opaque alpha 0xFF to RGB-only textures)
1810  *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
1811  }
1812  }
1813 
1814  source_format = D3DFMT_A8L8;
1815  source_row_byte_length = width * sizeof(USHORT);
1816  pixels = (BYTE*)temp_buffer;
1817  }
1818  else if (component_width != 1) {
1819  // Convert from 16-bit per channel (or larger) format down to 8-bit per
1820  // channel. This throws away precision in the original image, but dx8
1821  // doesn't support high-precision images anyway.
1822 
1823  int num_components = get_texture()->get_num_components();
1824  int num_pixels = width * height * num_components;
1825  BYTE *temp_buffer = new BYTE[num_pixels];
1826  if (!IS_VALID_PTR(temp_buffer)) {
1827  dxgsg9_cat.error() << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
1828  goto exit_FillMipmapSurf;
1829  }
1830  using_temp_buffer = true;
1831 
1832  BYTE *source_pixels = pixels + component_width - 1;
1833  for (int i = 0; i < num_pixels; i++) {
1834  temp_buffer[i] = *source_pixels;
1835  source_pixels += component_width;
1836  }
1837  pixels = (BYTE*)temp_buffer;
1838  }
1839 
1840  // filtering may be done here if texture if targetsize != origsize
1841 #ifdef DO_PSTATS
1842  GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * height);
1843 #endif
1844  if (source_format == D3DFMT_ATI1 || source_format == D3DFMT_ATI2) {
1845  // These formats are not supported by D3DXLoadSurfaceFromMemory.
1846  D3DLOCKED_RECT rect;
1847  _d3d_2d_texture->LockRect(mip_level, &rect, 0, D3DLOCK_DISCARD);
1848 
1849  unsigned char *dest = (unsigned char *)rect.pBits;
1850  memcpy(dest, pixels, view_size);
1851 
1852  _d3d_2d_texture->UnlockRect(mip_level);
1853 
1854  } else {
1855  hr = D3DXLoadSurfaceFromMemory
1856  (mip_surface, nullptr, nullptr, (LPCVOID)pixels,
1857  source_format, source_row_byte_length, nullptr,
1858  &source_size, mip_filter, (D3DCOLOR)0x0);
1859  if (FAILED(hr)) {
1860  dxgsg9_cat.error()
1861  << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
1862  << ", mip_level " << mip_level
1863  << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
1864  }
1865  }
1866 
1867 exit_FillMipmapSurf:
1868  if (using_temp_buffer) {
1869  SAFE_DELETE_ARRAY(pixels);
1870  }
1871 
1872  RELEASE(mip_surface, dxgsg9, "FillDDTextureMipmapPixels MipSurface texture ptr", RELEASE_ONCE);
1873  return hr;
1874 }
1875 
1876 /**
1877  *
1878  */
1879 HRESULT DXTextureContext9::
1880 fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
1881  IDirect3DDevice9 *device = scrn._d3d_device;
1882  Texture *tex = get_texture();
1883  nassertr(IS_VALID_PTR(tex), E_FAIL);
1884  if (tex->get_texture_type() == Texture::TT_3d_texture) {
1885  return fill_d3d_volume_texture_pixels(scrn);
1886  }
1887 
1888  HRESULT hr = E_FAIL;
1889 
1890  CPTA_uchar image;
1891  Texture::CompressionMode image_compression = Texture::CM_off;
1892  if (compress_texture) {
1893  // If we are to be compressing this texture, accept a pre-compressed ram
1894  // image if it is already so.
1895  image = tex->get_ram_image();
1896  if (!image.is_null()) {
1897  image_compression = tex->get_ram_image_compression();
1898  }
1899  } else {
1900  // If we are not to be compressing this texture, we can only accept an
1901  // uncompressed ram image. Ask the texture to give us one, so that
1902  // there's no danger of accidentally getting a pre-compressed image.
1903  image = tex->get_uncompressed_ram_image();
1904  }
1905 
1906  if (image.is_null()) {
1907  // The texture doesn't have an image to load. That's ok; it might be a
1908  // texture we've rendered to by frame buffer operations or something.
1909  if (tex->get_render_to_texture()) {
1910  HRESULT result;
1911 
1912  if (_d3d_2d_texture) {
1913  // clear render to texture
1914  IDirect3DSurface9 *surface;
1915 
1916  result = _d3d_2d_texture -> GetSurfaceLevel (0, &surface);
1917  if (result == D3D_OK) {
1918  D3DSURFACE_DESC surface_description;
1919 
1920  if (surface -> GetDesc (&surface_description) == D3D_OK) {
1921  IDirect3DSurface9 *current_render_target;
1922 
1923  if (device -> GetRenderTarget (0, &current_render_target) == D3D_OK) {
1924  IDirect3DSurface9 *depth_stencil_surface;
1925 
1926  // turn off depth stencil when clearing texture if it exists
1927  depth_stencil_surface = 0;
1928  if (device -> GetDepthStencilSurface (&depth_stencil_surface) == D3D_OK) {
1929  if (device -> SetDepthStencilSurface (nullptr) == D3D_OK) {
1930 
1931  }
1932  }
1933 
1934  if (device -> SetRenderTarget (0, surface) == D3D_OK) {
1935  DWORD flags;
1936  D3DCOLOR color;
1937 
1938  LColor scaled = tex->get_clear_color().fmin(LColor(1)).fmax(LColor::zero());
1939  scaled *= 255;
1940  color = D3DCOLOR_RGBA((int)scaled[0], (int)scaled[1], (int)scaled[2], (int)scaled[3]);
1941  flags = D3DCLEAR_TARGET;
1942  if (device -> Clear (0, nullptr, flags, color, 0.0f, 0) == D3D_OK) {
1943  }
1944  }
1945 
1946  // restore depth stencil
1947  if (depth_stencil_surface) {
1948  device -> SetDepthStencilSurface (depth_stencil_surface);
1949  depth_stencil_surface -> Release();
1950  }
1951 
1952  // restore render target
1953  device -> SetRenderTarget (0, current_render_target);
1954  current_render_target -> Release();
1955  }
1956  }
1957 
1958  surface -> Release();
1959  }
1960  }
1961 
1962  return S_OK;
1963  }
1964  }
1965  //nassertr(IS_VALID_PTR((BYTE*)image.p()), E_FAIL);
1966  nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
1967 
1968  PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
1969 
1970  DWORD orig_depth = (DWORD) tex->get_z_size();
1971  D3DFORMAT source_format = _d3d_format;
1972 
1973  // check for compressed textures and adjust source_format accordingly
1974  switch (image_compression) {
1975  case Texture::CM_dxt1:
1976  source_format = D3DFMT_DXT1;
1977  break;
1978  case Texture::CM_dxt2:
1979  source_format = D3DFMT_DXT2;
1980  break;
1981  case Texture::CM_dxt3:
1982  source_format = D3DFMT_DXT3;
1983  break;
1984  case Texture::CM_dxt4:
1985  source_format = D3DFMT_DXT4;
1986  break;
1987  case Texture::CM_dxt5:
1988  source_format = D3DFMT_DXT5;
1989  break;
1990  case Texture::CM_rgtc:
1991  if (tex->get_num_components() == 1) {
1992  source_format = D3DFMT_ATI1;
1993  } else {
1994  source_format = D3DFMT_ATI2;
1995  }
1996  break;
1997  default:
1998  // no known compression format.. no adjustment
1999  break;
2000  }
2001 
2002  for (unsigned int di = 0; di < orig_depth; di++) {
2003 
2004  // fill top level mipmap
2005  hr = fill_d3d_texture_mipmap_pixels(0, di, source_format);
2006  if (FAILED(hr)) {
2007  return hr; // error message was already output in fill_d3d_texture_mipmap_pixels
2008  }
2009 
2010  if (_has_mipmaps) {
2011  // if we have pre-calculated mipmap levels, use them, otherwise generate
2012  // on the fly
2013  int miplevel_count = _d3d_texture->GetLevelCount();
2014  if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
2015  dxgsg9_cat.debug()
2016  << "Using pre-calculated mipmap levels for texture " << tex->get_name() << "\n";
2017 
2018  for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) {
2019  hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
2020  if (FAILED(hr)) {
2021  return hr; // error message was already output in fill_d3d_texture_mipmap_pixels
2022  }
2023  }
2024  }
2025  else {
2026  // mipmaps need to be generated, either use autogen or d3dx functions
2027 
2028  if (_managed == false && scrn._supports_automatic_mipmap_generation) {
2029  if (false)
2030  {
2031  // hr = _d3d_texture -> SetAutoGenFilterType
2032  // (D3DTEXF_PYRAMIDALQUAD); hr = _d3d_texture ->
2033  // SetAutoGenFilterType (D3DTEXF_GAUSSIANQUAD); hr = _d3d_texture
2034  // -> SetAutoGenFilterType (D3DTEXF_ANISOTROPIC);
2035  hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_LINEAR);
2036  if (FAILED(hr)) {
2037  dxgsg9_cat.error() << "SetAutoGenFilterType failed " << D3DERRORSTRING(hr);
2038  }
2039 
2040  _d3d_texture -> GenerateMipSubLevels ( );
2041  }
2042  }
2043  else {
2044  DWORD mip_filter_flags;
2045  if (!dx_use_triangle_mipgen_filter) {
2046  mip_filter_flags = D3DX_FILTER_BOX;
2047  } else {
2048  mip_filter_flags = D3DX_FILTER_TRIANGLE;
2049  }
2050 
2051  if (Texture::is_srgb(tex->get_format())) {
2052  mip_filter_flags |= D3DX_FILTER_SRGB;
2053  }
2054 
2055  // mip_filter_flags |= D3DX_FILTER_DITHER;
2056  hr = D3DXFilterTexture(_d3d_texture, nullptr, 0,
2057  mip_filter_flags);
2058 
2059  if (FAILED(hr)) {
2060  dxgsg9_cat.error()
2061  << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
2062  << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
2063  }
2064  }
2065  }
2066  }
2067  }
2068 
2069  return hr;
2070 }
2071 
2072 
2073 /**
2074  *
2075  */
2076 HRESULT DXTextureContext9::
2077 fill_d3d_volume_texture_pixels(DXScreenData &scrn) {
2078  Texture *tex = get_texture();
2079  HRESULT hr = E_FAIL;
2080  nassertr(IS_VALID_PTR(tex), E_FAIL);
2081 
2082  CPTA_uchar image;
2083  if (scrn._dxgsg9->get_supports_compressed_texture()) {
2084  image = tex->get_ram_image();
2085  } else {
2086  image = tex->get_uncompressed_ram_image();
2087  }
2088 
2089  Texture::CompressionMode image_compression;
2090  if (image.is_null()) {
2091  image_compression = Texture::CM_off;
2092  } else {
2093  image_compression = tex->get_ram_image_compression();
2094  }
2095 
2096  if (!scrn._dxgsg9->get_supports_compressed_texture_format(image_compression)) {
2097  image = tex->get_uncompressed_ram_image();
2098  image_compression = Texture::CM_off;
2099  }
2100 
2101  if (image.is_null()) {
2102  // The texture doesn't have an image to load. That's ok; it might be a
2103  // texture we've rendered to by frame buffer operations or something.
2104  return S_OK;
2105  }
2106 
2107  PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
2108 
2109  nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
2110  nassertr(tex->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
2111 
2112  DWORD orig_width = (DWORD) tex->get_x_size();
2113  DWORD orig_height = (DWORD) tex->get_y_size();
2114  DWORD orig_depth = (DWORD) tex->get_z_size();
2115  DWORD num_color_channels = tex->get_num_components();
2116  D3DFORMAT source_format = _d3d_format;
2117  BYTE *image_pixels = (BYTE*)image.p();
2118  int component_width = tex->get_component_width();
2119 
2120  nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
2121 
2122  size_t view_size = tex->get_ram_mipmap_view_size(0);
2123  image_pixels += view_size * get_view();
2124 
2125  IDirect3DVolume9 *mip_level_0 = nullptr;
2126  bool using_temp_buffer = false;
2127  BYTE *pixels = image_pixels;
2128 
2129  nassertr(IS_VALID_PTR(_d3d_volume_texture), E_FAIL);
2130  hr = _d3d_volume_texture->GetVolumeLevel(0, &mip_level_0);
2131 
2132  if (FAILED(hr)) {
2133  dxgsg9_cat.error()
2134  << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
2135  << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
2136  return E_FAIL;
2137  }
2138 
2139  D3DBOX source_size;
2140  source_size.Left = source_size.Top = source_size.Front = 0;
2141  source_size.Right = orig_width;
2142  source_size.Bottom = orig_height;
2143  source_size.Back = orig_depth;
2144 
2145  UINT source_row_byte_length = orig_width * num_color_channels;
2146  UINT source_page_byte_length = orig_height * source_row_byte_length;
2147 
2148  DWORD level_0_filter, mip_filter_flags;
2149  using_temp_buffer = false;
2150 
2151  // need filtering if size changes, (also if bitdepth reduced (need
2152  // dithering)??)
2153  level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures
2154 
2155  if (Texture::is_srgb(tex->get_format())) {
2156  level_0_filter |= D3DX_FILTER_SRGB;
2157  }
2158 
2159  // D3DXLoadSurfaceFromMemory will load black luminance and we want full
2160  // white, so convert to explicit luminance-alpha format
2161  if (_d3d_format == D3DFMT_A8) {
2162  // alloc buffer for explicit D3DFMT_A8L8
2163  USHORT *temp_buffer = new USHORT[orig_width * orig_height * orig_depth];
2164  if (!IS_VALID_PTR(temp_buffer)) {
2165  dxgsg9_cat.error()
2166  << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
2167  goto exit_FillDDSurf;
2168  }
2169  using_temp_buffer = true;
2170 
2171  USHORT *out_pixels = temp_buffer;
2172  BYTE *source_pixels = pixels + component_width - 1;
2173  for (UINT z = 0; z < orig_depth; z++) {
2174  for (UINT y = 0; y < orig_height; y++) {
2175  for (UINT x = 0;
2176  x < orig_width;
2177  x++, source_pixels += component_width, out_pixels++) {
2178  // add full white, which is our interpretation of alpha-only
2179  // (similar to default adding full opaque alpha 0xFF to RGB-only
2180  // textures)
2181  *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
2182  }
2183  }
2184  }
2185 
2186  source_format = D3DFMT_A8L8;
2187  source_row_byte_length = orig_width * sizeof(USHORT);
2188  source_page_byte_length = orig_height * source_row_byte_length;
2189  pixels = (BYTE*)temp_buffer;
2190 
2191  } else if (component_width != 1) {
2192  // Convert from 16-bit per channel (or larger) format down to 8-bit per
2193  // channel. This throws away precision in the original image, but dx8
2194  // doesn't support high-precision images anyway.
2195 
2196  int num_components = tex->get_num_components();
2197  int num_pixels = orig_width * orig_height * orig_depth * num_components;
2198  BYTE *temp_buffer = new BYTE[num_pixels];
2199  if (!IS_VALID_PTR(temp_buffer)) {
2200  dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
2201  goto exit_FillDDSurf;
2202  }
2203  using_temp_buffer = true;
2204 
2205  BYTE *source_pixels = pixels + component_width - 1;
2206  for (int i = 0; i < num_pixels; i++) {
2207  temp_buffer[i] = *source_pixels;
2208  source_pixels += component_width;
2209  }
2210  pixels = (BYTE*)temp_buffer;
2211  }
2212 
2213 
2214  // filtering may be done here if texture if targetsize != origsize
2215 #ifdef DO_PSTATS
2216  GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_page_byte_length * orig_depth);
2217 #endif
2218  hr = D3DXLoadVolumeFromMemory
2219  (mip_level_0, nullptr, nullptr, (LPCVOID)pixels,
2220  source_format, source_row_byte_length, source_page_byte_length,
2221  nullptr,
2222  &source_size, level_0_filter, (D3DCOLOR)0x0);
2223  if (FAILED(hr)) {
2224  dxgsg9_cat.error()
2225  << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
2226  << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
2227  goto exit_FillDDSurf;
2228  }
2229 
2230  if (_has_mipmaps) {
2231  if (!dx_use_triangle_mipgen_filter) {
2232  mip_filter_flags = D3DX_FILTER_BOX;
2233  } else {
2234  mip_filter_flags = D3DX_FILTER_TRIANGLE;
2235  }
2236 
2237  if (Texture::is_srgb(tex->get_format())) {
2238  mip_filter_flags |= D3DX_FILTER_SRGB;
2239  }
2240 
2241  // mip_filter_flags| = D3DX_FILTER_DITHER;
2242 
2243  hr = D3DXFilterTexture(_d3d_texture, nullptr, 0,
2244  mip_filter_flags);
2245  if (FAILED(hr)) {
2246  dxgsg9_cat.error()
2247  << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
2248  << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
2249  goto exit_FillDDSurf;
2250  }
2251  }
2252 
2253  exit_FillDDSurf:
2254  if (using_temp_buffer) {
2255  SAFE_DELETE_ARRAY(pixels);
2256  }
2257  RELEASE(mip_level_0, dxgsg9, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE);
2258  return hr;
2259 }
2260 
2261 
2262 /**
2263  * Returns the largest power of 2 less than or equal to value.
2264  */
2265 int DXTextureContext9::
2266 down_to_power_2(int value) {
2267  int x = 1;
2268  while ((x << 1) <= value) {
2269  x = (x << 1);
2270  }
2271  return x;
2272 }
2273 
2274 /**
2275  * Maps from the Texture's Format symbols to bpp. Returns # of alpha bits.
2276  * Note: Texture's format indicates REQUESTED final format, not the stored
2277  * format, which is indicated by pixelbuffer type
2278  */
2279 unsigned int DXTextureContext9::
2280 get_bits_per_pixel(Texture::Format format, int *alphbits) {
2281  *alphbits = 0; // assume no alpha bits
2282  switch(format) {
2283  case Texture::F_alpha:
2284  *alphbits = 8;
2285  case Texture::F_color_index:
2286  case Texture::F_red:
2287  case Texture::F_green:
2288  case Texture::F_blue:
2289  case Texture::F_rgb332:
2290  return 8;
2291  case Texture::F_luminance_alphamask:
2292  *alphbits = 1;
2293  return 16;
2294  case Texture::F_luminance_alpha:
2295  *alphbits = 8;
2296  return 16;
2297  case Texture::F_luminance:
2298  return 8;
2299  case Texture::F_rgba4:
2300  *alphbits = 4;
2301  return 16;
2302  case Texture::F_rgba5:
2303  *alphbits = 1;
2304  return 16;
2305  case Texture::F_depth_component:
2306  case Texture::F_depth_component16:
2307  return 16;
2308  case Texture::F_depth_stencil:
2309  case Texture::F_depth_component24:
2310  return 24;
2311  case Texture::F_depth_component32:
2312  return 32;
2313  case Texture::F_rgb5:
2314  return 16;
2315  case Texture::F_rgb8:
2316  case Texture::F_rgb:
2317  return 24;
2318  case Texture::F_rgba8:
2319  case Texture::F_rgba:
2320  *alphbits = 8;
2321  return 32;
2322  case Texture::F_rgbm:
2323  *alphbits = 1;
2324  return 32;
2325  case Texture::F_rgb12:
2326  return 36;
2327  case Texture::F_rgba12:
2328  *alphbits = 12;
2329  return 48;
2330  case Texture::F_rgba16:
2331  *alphbits = 16;
2332  return 64;
2333  case Texture::F_rgba32:
2334  *alphbits = 32;
2335  return 128;
2336 
2337  case Texture::F_srgb:
2338  return 24;
2339  case Texture::F_srgb_alpha:
2340  *alphbits = 8;
2341  return 32;
2342  case Texture::F_sluminance:
2343  return 8;
2344  case Texture::F_sluminance_alpha:
2345  *alphbits = 8;
2346  return 16;
2347  }
2348  return 8;
2349 }
2350 
2351 /**
2352  * Determines bytes per pixel from D3DFORMAT.
2353  */
2354 PN_stdfloat DXTextureContext9::
2355 d3d_format_to_bytes_per_pixel (D3DFORMAT format)
2356 {
2357  PN_stdfloat bytes_per_pixel;
2358 
2359  bytes_per_pixel = 0.0f;
2360  switch (format)
2361  {
2362  case D3DFMT_R3G3B2:
2363  case D3DFMT_A8:
2364  case D3DFMT_A8P8:
2365  case D3DFMT_P8:
2366  case D3DFMT_L8:
2367  case D3DFMT_A4L4:
2368  bytes_per_pixel = 1.0f;
2369  break;
2370 
2371  case D3DFMT_R16F:
2372  case D3DFMT_CxV8U8:
2373  case D3DFMT_V8U8:
2374  case D3DFMT_R5G6B5:
2375  case D3DFMT_X1R5G5B5:
2376  case D3DFMT_A1R5G5B5:
2377  case D3DFMT_A4R4G4B4:
2378  case D3DFMT_L16:
2379  case D3DFMT_A8L8:
2380  case D3DFMT_A8R3G3B2:
2381  case D3DFMT_X4R4G4B4:
2382  case D3DFMT_D16:
2383  case (D3DFORMAT)MAKEFOURCC('D', 'F', '1', '6'):
2384  bytes_per_pixel = 2.0f;
2385  break;
2386 
2387  case D3DFMT_R8G8B8:
2388  bytes_per_pixel = 3.0f;
2389  break;
2390 
2391  case D3DFMT_G16R16F:
2392  case D3DFMT_Q8W8V8U8:
2393  case D3DFMT_V16U16:
2394  case D3DFMT_R32F:
2395  case D3DFMT_A8R8G8B8:
2396  case D3DFMT_X8R8G8B8:
2397  case D3DFMT_A2B10G10R10:
2398  case D3DFMT_A8B8G8R8:
2399  case D3DFMT_X8B8G8R8:
2400  case D3DFMT_G16R16:
2401  case D3DFMT_A2R10G10B10:
2402  case D3DFMT_D24X8:
2403  case D3DFMT_D24S8:
2404  case D3DFMT_D32:
2405  case (D3DFORMAT)MAKEFOURCC('D', 'F', '2', '4'):
2406  case D3DFMT_INTZ:
2407  bytes_per_pixel = 4.0f;
2408  break;
2409 
2410  case D3DFMT_G32R32F:
2411  case D3DFMT_A16B16G16R16F:
2412  case D3DFMT_Q16W16V16U16:
2413  case D3DFMT_A16B16G16R16:
2414  bytes_per_pixel = 8.0f;
2415  break;
2416 
2417  case D3DFMT_A32B32G32R32F:
2418  bytes_per_pixel = 16.0f;
2419  break;
2420 
2421  case D3DFMT_DXT1:
2422  case D3DFMT_ATI1:
2423  bytes_per_pixel = 0.5f;
2424  break;
2425  case D3DFMT_DXT2:
2426  case D3DFMT_DXT3:
2427  case D3DFMT_DXT4:
2428  case D3DFMT_DXT5:
2429  case D3DFMT_ATI2:
2430  bytes_per_pixel = 1.0f;
2431  break;
2432  }
2433 
2434  return bytes_per_pixel;
2435 }
CPTA_uchar get_ram_image()
Returns the system-RAM image data associated with the texture.
Definition: texture.I:1356
set_z_size
Changes the z size indicated for the texture.
Definition: texture.h:342
static bool is_srgb(Format format)
Returns true if the indicated format is in the sRGB color space, false otherwise.
Definition: texture.cxx:2617
get_y_size
Returns the height of the texture image in texels.
Definition: texture.h:338
Texture * get_texture() const
Returns the pointer to the associated Texture object.
int get_expected_mipmap_x_size(int n) const
Returns the x_size that the nth mipmap level should have, based on the texture's size.
Definition: texture.I:1185
set_data
Stores a new data object on the record.
get_magfilter
Returns the filter mode of the texture for magnification.
Definition: texture.h:389
get_fullpath
Returns the fullpath that has been set.
Definition: texture.h:324
get_z_size
Returns the depth of the texture image in texels.
Definition: texture.h:342
get_simple_ram_image
Returns the image data associated with the "simple" texture image.
Definition: texture.h:509
get_component_type
Returns the numeric interpretation of each component of the texture.
Definition: texture.h:366
get_compression
Returns the compression mode requested for this particular texture, or CM_off if the texture is not t...
Definition: texture.h:405
int get_view() const
Returns the specific view of a multiview texture this context represents.
PTA_uchar make_ram_mipmap_image(int n)
Discards the current system-RAM image for the nth mipmap level, if any, and allocates a new buffer of...
Definition: texture.I:1650
set_magfilter
Sets the filtering method that should be used when viewing the texture up close.
Definition: texture.h:389
This class maintains a cache of Bam and/or Txo objects generated from model files and texture images ...
Definition: bamCache.h:42
constexpr bool is_null() const
Returns true if the PointerTo is a NULL pointer, false otherwise.
Definition: pointerToVoid.I:27
CPTA_uchar get_uncompressed_ram_image()
Returns the system-RAM image associated with the texture, in an uncompressed form if at all possible.
Definition: texture.I:1403
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
get_texture_type
Returns the overall interpretation of the texture.
Definition: texture.h:357
This is a special class object that holds all the information returned by a particular GSG to indicat...
get_anisotropic_degree
Returns the degree of anisotropic filtering that should be applied to the texture.
Definition: texture.h:395
bool create_texture(DXScreenData &scrn)
Use panda texture's pixelbuffer to create a texture for the specified device.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_loadable_ram_mipmap_images
Returns the number of contiguous mipmap levels that exist in RAM, up until the first gap in the seque...
Definition: texture.h:494
A table of objects that are saved within the graphics context for reference by handle later.
bool has_ram_image() const
Returns true if the Texture has its image contents available in main RAM, false if it exists only in ...
Definition: texture.I:1242
int get_expected_mipmap_y_size(int n) const
Returns the y_size that the nth mipmap level should have, based on the texture's size.
Definition: texture.I:1195
void mark_used_lru() const
To be called when the page is used; this will move it to the tail of the AdaptiveLru queue it is alre...
Definition: adaptiveLru.I:148
void texture_uploaded(Texture *tex)
This method is called by the GraphicsStateGuardian after a texture has been successfully uploaded to ...
void dequeue_lru()
Removes the page from its AdaptiveLru.
Definition: adaptiveLru.I:136
size_t get_ram_mipmap_view_size(int n) const
Returns the number of bytes used by the in-memory image per view for mipmap level n,...
Definition: texture.I:1576
get_minfilter
Returns the filter mode of the texture for minification.
Definition: texture.h:383
GraphicsEngine * get_engine() const
Returns the graphics engine that created this GSG.
CPTA_uchar get_ram_mipmap_image(int n) const
Returns the system-RAM image data associated with the nth mipmap level, if present.
Definition: texture.cxx:1208
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
Definition: bamCache.cxx:188
get_format
Returns the format of the texture, which represents both the semantic meaning of the texels and,...
Definition: texture.h:362
get_expected_ram_page_size
Returns the number of bytes that should be used per each Z page of the 3-d texture.
Definition: texture.h:441
void set_ram_mipmap_image(int n, CPTA_uchar image, size_t page_size=0)
Replaces the current system-RAM image for the indicated mipmap level with the new data.
Definition: texture.I:1664
bool extract_texture_data(DXScreenData &scrn)
This method will be called in the draw thread to download the texture memory's image into its ram_ima...
get_supports_compressed_texture
Returns true if this GSG can compress textures as it loads them into texture memory,...
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
const Element * p() const
Function p() is similar to the function from ConstPointerTo.
set_format
Changes the format value for the texture components.
Definition: texture.h:362
set_minfilter
Sets the filtering method that should be used when viewing the texture from a distance.
Definition: texture.h:383
get_num_components
Returns the number of color components for each texel of the texture image.
Definition: texture.h:355
set_anisotropic_degree
Specifies the level of anisotropic filtering to apply to the texture.
Definition: texture.h:395
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_y_size
Changes the y size indicated for the texture.
Definition: texture.h:338
set_post_load_store_cache
Sets the post_load_store_cache flag.
Definition: texture.h:586
set_x_size
Changes the x size indicated for the texture.
Definition: texture.h:334
get_component_width
Returns the number of bytes stored for each color component of a texel.
Definition: texture.h:356
get_match_framebuffer_format
Returns true if the special flag was set that indicates to the GSG that the Texture's format should b...
Definition: texture.h:581
get_simple_x_size
Returns the width of the "simple" image in texels.
Definition: texture.h:507
size_t get_expected_ram_mipmap_page_size(int n) const
Returns the number of bytes that should be used per each Z page of the 3-d texture,...
Definition: texture.I:1624
void clear_ram_image()
Discards the current system-RAM image.
Definition: texture.I:1439
get_clear_color
Returns the color that was previously set using set_clear_color.
Definition: texture.h:270
void set_ram_image(CPTA_uchar image, CompressionMode compression=CM_off, size_t page_size=0)
Replaces the current system-RAM image with the new data.
Definition: texture.I:1429
virtual bool get_supports_compressed_texture_format(int compression_mode) const
Returns true if this GSG can accept textures pre-compressed in the indicated format.
set_component_type
Changes the data value for the texture components.
Definition: texture.h:366
void generate_ram_mipmap_images()
Automatically fills in the n mipmap levels of the Texture, based on the texture's source image.
Definition: texture.I:1691
void update_data_size_bytes(size_t new_data_size_bytes)
Should be called (usually by a derived class) when the on-card size of this object has changed.
void mark_loaded()
Should be called after the texture has been loaded into graphics memory, this updates the internal fl...
virtual void evict_lru()
Evicts the page from the LRU.
get_num_ram_mipmap_images
Returns the maximum number of mipmap level images available in system memory.
Definition: texture.h:493
get_simple_y_size
Returns the height of the "simple" image in texels.
Definition: texture.h:508
void mark_unloaded()
Should be called after the texture has been forced out of texture memory.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PTA_uchar modify_ram_image()
Returns a modifiable pointer to the system-RAM image.
Definition: texture.I:1382
void mark_simple_loaded()
Should be called after the texture's "simple" image has been loaded into graphics memory.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
vector_uchar get_clear_data() const
Returns the raw image data for a single pixel if it were set to the clear color.
Definition: texture.I:287
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void delete_texture()
Release the surface used to store the texture.
get_x_size
Returns the width of the texture image in texels.
Definition: texture.h:334
static BamCache * get_global_ptr()
Returns a pointer to the global BamCache object, which is used automatically by the ModelPool and Tex...
Definition: bamCache.I:223
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_post_load_store_cache
Returns the setting of the post_load_store_cache flag.
Definition: texture.h:586
get_ram_image_compression
Returns the compression mode in which the ram image is already stored pre- compressed.
Definition: texture.h:463
static HRESULT d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface, bool inverted, Texture *result, int view, int z)
copies source_rect in pD3DSurf to upper left of texture
get_render_to_texture
Returns a flag on the texture that indicates whether the texture is intended to be used as a direct-r...
Definition: texture.h:409