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