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  */
75 evict_lru() {
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  */
1173 delete_texture() {
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  */
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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 dequeue_lru()
Removes the page from its AdaptiveLru.
Definition: adaptiveLru.I:136
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
set_data
Stores a new data object on the record.
This class maintains a cache of Bam and/or Txo objects generated from model files and texture images ...
Definition: bamCache.h:42
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
Definition: bamCache.cxx:194
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
const Element * p() const
Function p() is similar to the function from ConstPointerTo.
bool create_texture(DXScreenData &scrn)
Use panda texture's pixelbuffer to create a texture for the specified device.
virtual void evict_lru()
Evicts the page from the LRU.
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...
void delete_texture()
Release the surface used to store the texture.
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
void texture_uploaded(Texture *tex)
This method is called by the GraphicsStateGuardian after a texture has been successfully uploaded to ...
GraphicsEngine * get_engine() const
Returns the graphics engine that created this GSG.
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.
get_supports_compressed_texture
Returns true if this GSG can compress textures as it loads them into texture memory,...
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
constexpr bool is_null() const
Returns true if the PointerTo is a NULL pointer, false otherwise.
Definition: pointerToVoid.I:27
A table of objects that are saved within the graphics context for reference by handle later.
This is a special class object that holds all the information returned by a particular GSG to indicat...
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.
Texture * get_texture() const
Returns the pointer to the associated Texture object.
void mark_simple_loaded()
Should be called after the texture's "simple" image has been loaded into graphics memory.
void mark_unloaded()
Should be called after the texture has been forced out of texture memory.
void mark_loaded()
Should be called after the texture has been loaded into graphics memory, this updates the internal fl...
int get_view() const
Returns the specific view of a multiview texture this context represents.
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_post_load_store_cache
Returns the setting of the post_load_store_cache flag.
Definition: texture.h:594
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
get_format
Returns the format of the texture, which represents both the semantic meaning of the texels and,...
Definition: texture.h:370
get_minfilter
Returns the filter mode of the texture for minification.
Definition: texture.h:391
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
PTA_uchar modify_ram_image()
Returns a modifiable pointer to the system-RAM image.
Definition: texture.I:1382
set_z_size
Changes the z size indicated for the texture.
Definition: texture.h:350
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:417
get_compression
Returns the compression mode requested for this particular texture, or CM_off if the texture is not t...
Definition: texture.h:413
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
get_texture_type
Returns the overall interpretation of the texture.
Definition: texture.h:365
CPTA_uchar get_ram_image()
Returns the system-RAM image data associated with the texture.
Definition: texture.I:1356
get_simple_ram_image
Returns the image data associated with the "simple" texture image.
Definition: texture.h:517
static bool is_srgb(Format format)
Returns true if the indicated format is in the sRGB color space, false otherwise.
Definition: texture.cxx:2678
get_ram_image_compression
Returns the compression mode in which the ram image is already stored pre- compressed.
Definition: texture.h:471
set_format
Changes the format value for the texture components.
Definition: texture.h:370
get_component_width
Returns the number of bytes stored for each color component of a texel.
Definition: texture.h:364
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
set_anisotropic_degree
Specifies the level of anisotropic filtering to apply to the texture.
Definition: texture.h:403
get_anisotropic_degree
Returns the degree of anisotropic filtering that should be applied to the texture.
Definition: texture.h:403
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:589
get_y_size
Returns the height of the texture image in texels.
Definition: texture.h:346
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_magfilter
Returns the filter mode of the texture for magnification.
Definition: texture.h:397
get_z_size
Returns the depth of the texture image in texels.
Definition: texture.h:350
set_x_size
Changes the x size indicated for the texture.
Definition: texture.h:342
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
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
set_minfilter
Sets the filtering method that should be used when viewing the texture from a distance.
Definition: texture.h:391
set_magfilter
Sets the filtering method that should be used when viewing the texture up close.
Definition: texture.h:397
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
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
get_num_components
Returns the number of color components for each texel of the texture image.
Definition: texture.h:363
void clear_ram_image()
Discards the current system-RAM image.
Definition: texture.I:1439
get_fullpath
Returns the fullpath that has been set.
Definition: texture.h:332
get_x_size
Returns the width of the texture image in texels.
Definition: texture.h:342
get_simple_y_size
Returns the height of the "simple" image in texels.
Definition: texture.h:516
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:449
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
set_y_size
Changes the y size indicated for the texture.
Definition: texture.h:346
set_post_load_store_cache
Sets the post_load_store_cache flag.
Definition: texture.h:594
get_component_type
Returns the numeric interpretation of each component of the texture.
Definition: texture.h:374
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
get_simple_x_size
Returns the width of the "simple" image in texels.
Definition: texture.h:515
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:502
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:1214
get_clear_color
Returns the color that was previously set using set_clear_color.
Definition: texture.h:278
set_component_type
Changes the data value for the texture components.
Definition: texture.h:374
get_num_ram_mipmap_images
Returns the maximum number of mipmap level images available in system memory.
Definition: texture.h:501
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.