Panda3D
|
00001 // Filename: dxTextureContext9.cxx 00002 // Created by: georges (02Feb02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "config_dxgsg9.h" 00016 #include "dxGraphicsStateGuardian9.h" 00017 #include "pStatTimer.h" 00018 #include "dxTextureContext9.h" 00019 #include "bamCache.h" 00020 #include "graphicsEngine.h" 00021 #include <d3dx9tex.h> 00022 #include <assert.h> 00023 #include <time.h> 00024 00025 #define DEBUG_SURFACES false 00026 #define DEBUG_TEXTURES true 00027 00028 TypeHandle DXTextureContext9::_type_handle; 00029 00030 static const DWORD g_LowByteMask = 0x000000FF; 00031 00032 //////////////////////////////////////////////////////////////////// 00033 // Function: DXTextureContext9::Constructor 00034 // Access: Public 00035 // Description: 00036 //////////////////////////////////////////////////////////////////// 00037 DXTextureContext9:: 00038 DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex, int view) : 00039 TextureContext(pgo, tex, view) { 00040 00041 if (dxgsg9_cat.is_spam()) { 00042 dxgsg9_cat.spam() 00043 << "Creating DX texture [" << tex->get_name() << "], minfilter(" << tex->get_minfilter() << "), magfilter(" << tex->get_magfilter() << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n"; 00044 } 00045 00046 _d3d_texture = NULL; 00047 _d3d_2d_texture = NULL; 00048 _d3d_volume_texture = NULL; 00049 _d3d_cube_texture = NULL; 00050 _has_mipmaps = false; 00051 _is_render_target = false; 00052 _managed = -1; 00053 } 00054 00055 //////////////////////////////////////////////////////////////////// 00056 // Function: DXTextureContext9::Destructor 00057 // Access: Public, Virtual 00058 // Description: 00059 //////////////////////////////////////////////////////////////////// 00060 DXTextureContext9:: 00061 ~DXTextureContext9() { 00062 delete_texture(); 00063 } 00064 00065 //////////////////////////////////////////////////////////////////// 00066 // Function: DXTextureContext9::evict_lru 00067 // Access: Public, Virtual 00068 // Description: Evicts the page from the LRU. Called internally when 00069 // the LRU determines that it is full. May also be 00070 // called externally when necessary to explicitly evict 00071 // the page. 00072 // 00073 // It is legal for this method to either evict the page 00074 // as requested, do nothing (in which case the eviction 00075 // will be requested again at the next epoch), or 00076 // requeue itself on the tail of the queue (in which 00077 // case the eviction will be requested again much 00078 // later). 00079 //////////////////////////////////////////////////////////////////// 00080 void DXTextureContext9:: 00081 evict_lru() { 00082 if (get_texture()->get_render_to_texture()) { 00083 // Don't evict the result of render-to-texture. 00084 mark_used_lru(); 00085 return; 00086 } 00087 if (dxgsg9_cat.is_debug()) { 00088 dxgsg9_cat.debug() 00089 << "Evicting " << *get_texture() << "\n"; 00090 } 00091 00092 dequeue_lru(); 00093 delete_texture(); 00094 00095 update_data_size_bytes(0); 00096 mark_unloaded(); 00097 } 00098 00099 //////////////////////////////////////////////////////////////////// 00100 // Function: DXTextureContext9::create_texture 00101 // Access: Public 00102 // Description: Use panda texture's pixelbuffer to create a texture 00103 // for the specified device. This code gets the 00104 // attributes of the texture from the bitmap, creates 00105 // the texture, and then copies the bitmap into the 00106 // texture. The return value is true if the texture is 00107 // successfully created, false otherwise. 00108 //////////////////////////////////////////////////////////////////// 00109 bool DXTextureContext9:: 00110 create_texture(DXScreenData &scrn) { 00111 00112 // check if the texture has already been created 00113 if (_d3d_2d_texture || _d3d_cube_texture || _d3d_volume_texture) { 00114 // texture already created, no need to create 00115 return true; 00116 } 00117 00118 HRESULT hr; 00119 int num_alpha_bits; // number of alpha bits in texture pixfmt 00120 D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN; 00121 bool needs_luminance = false; 00122 bool compress_texture = false; 00123 00124 Texture *tex = get_texture(); 00125 nassertr(IS_VALID_PTR(tex), false); 00126 00127 // Ensure the ram image is loaded, if available. 00128 tex->get_ram_image(); 00129 00130 DWORD orig_width = (DWORD)tex->get_x_size(); 00131 DWORD orig_height = (DWORD)tex->get_y_size(); 00132 DWORD orig_depth = (DWORD)tex->get_z_size(); 00133 00134 // check for texture compression 00135 bool texture_wants_compressed = false; 00136 Texture::CompressionMode compression_mode = tex->get_ram_image_compression(); 00137 bool texture_stored_compressed = compression_mode != Texture::CM_off; 00138 00139 if (texture_stored_compressed) { 00140 texture_wants_compressed = true; 00141 } else { 00142 if (tex->get_compression() == Texture::CM_off) { 00143 // no compression 00144 } else { 00145 if (tex->get_compression() == Texture::CM_default) { 00146 // default = use "compressed-textures" config setting 00147 if (compressed_textures) { 00148 texture_wants_compressed = true; 00149 } 00150 } else { 00151 texture_wants_compressed = true; 00152 } 00153 } 00154 } 00155 00156 switch (tex->get_texture_type()) { 00157 case Texture::TT_1d_texture: 00158 case Texture::TT_2d_texture: 00159 case Texture::TT_cube_map: 00160 // no compression for render target textures, or very small 00161 // textures 00162 if (!tex->get_render_to_texture() && 00163 orig_width >= 4 && orig_height >= 4) { 00164 if (texture_wants_compressed){ 00165 compress_texture = true; 00166 } 00167 } 00168 break; 00169 case Texture::TT_3d_texture: 00170 // compression of 3d textures not supported by all video chips 00171 break; 00172 } 00173 00174 if (texture_stored_compressed && !compress_texture) { 00175 // If we're going to need to reload the texture to get its 00176 // uncompressed image, we'd better do so now, *before* we figure 00177 // out the source format. We have to do this early, even though 00178 // we're going to do it again in fill_d3d_texture_pixels(), 00179 // because sometimes reloading the original ram image will change 00180 // the texture's apparent pixel format (the compressed form may 00181 // have a different format than the uncompressed form). 00182 tex->get_uncompressed_ram_image(); 00183 00184 orig_width = (DWORD)tex->get_x_size(); 00185 orig_height = (DWORD)tex->get_y_size(); 00186 orig_depth = (DWORD)tex->get_z_size(); 00187 } 00188 00189 // bpp indicates requested fmt, not texture fmt 00190 DWORD target_bpp = get_bits_per_pixel(tex->get_format(), &num_alpha_bits); 00191 DWORD num_color_channels = tex->get_num_components(); 00192 00193 // printf ("format = %d \n", tex->get_format()); 00194 // printf ("target_bpp %d, num_color_channels %d num_alpha_bits %d \n", target_bpp, num_color_channels, num_alpha_bits); 00195 00196 //PRINT_REFCNT(dxgsg9, scrn._d3d9); 00197 00198 if ((tex->get_format() == Texture::F_luminance_alpha)|| 00199 (tex->get_format() == Texture::F_luminance_alphamask) || 00200 (tex->get_format() == Texture::F_luminance)) { 00201 needs_luminance = true; 00202 } 00203 00204 if (num_alpha_bits > 0) { 00205 if (num_color_channels == 3) { 00206 dxgsg9_cat.error() 00207 << "texture " << tex->get_name() 00208 << " has no inherent alpha channel, but alpha format is requested!\n"; 00209 } 00210 } 00211 00212 _d3d_format = D3DFMT_UNKNOWN; 00213 00214 // figure out what 'D3DFMT' the Texture is in, so D3DXLoadSurfFromMem knows how to perform copy 00215 00216 switch (num_color_channels) { 00217 case 1: 00218 if (num_alpha_bits > 0) { 00219 _d3d_format = D3DFMT_A8; 00220 } else if (needs_luminance) { 00221 _d3d_format = D3DFMT_L8; 00222 } 00223 break; 00224 case 2: 00225 nassertr(needs_luminance && (num_alpha_bits > 0), false); 00226 _d3d_format = D3DFMT_A8L8; 00227 break; 00228 case 3: 00229 _d3d_format = D3DFMT_R8G8B8; 00230 break; 00231 case 4: 00232 _d3d_format = D3DFMT_A8R8G8B8; 00233 break; 00234 } 00235 00236 // make sure we handled all the possible cases 00237 nassertr(_d3d_format != D3DFMT_UNKNOWN, false); 00238 00239 DWORD target_width = orig_width; 00240 DWORD target_height = orig_height; 00241 DWORD target_depth = orig_depth; 00242 00243 DWORD filter_caps; 00244 00245 switch (tex->get_texture_type()) { 00246 case Texture::TT_1d_texture: 00247 case Texture::TT_2d_texture: 00248 filter_caps = scrn._d3dcaps.TextureFilterCaps; 00249 00250 if (target_width > scrn._d3dcaps.MaxTextureWidth) { 00251 target_width = scrn._d3dcaps.MaxTextureWidth; 00252 } 00253 if (target_height > scrn._d3dcaps.MaxTextureHeight) { 00254 target_height = scrn._d3dcaps.MaxTextureHeight; 00255 } 00256 00257 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_POW2) { 00258 if (!ISPOW2(target_width)) { 00259 target_width = down_to_power_2(target_width); 00260 } 00261 if (!ISPOW2(target_height)) { 00262 target_height = down_to_power_2(target_height); 00263 } 00264 } 00265 break; 00266 00267 case Texture::TT_3d_texture: 00268 if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0) { 00269 dxgsg9_cat.warning() 00270 << "3-d textures are not supported by this graphics driver.\n"; 00271 return false; 00272 } 00273 00274 filter_caps = scrn._d3dcaps.VolumeTextureFilterCaps; 00275 00276 if (target_width > scrn._d3dcaps.MaxVolumeExtent) { 00277 target_width = scrn._d3dcaps.MaxVolumeExtent; 00278 } 00279 if (target_height > scrn._d3dcaps.MaxVolumeExtent) { 00280 target_height = scrn._d3dcaps.MaxVolumeExtent; 00281 } 00282 if (target_depth > scrn._d3dcaps.MaxVolumeExtent) { 00283 target_depth = scrn._d3dcaps.MaxVolumeExtent; 00284 } 00285 00286 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) { 00287 if (!ISPOW2(target_width)) { 00288 target_width = down_to_power_2(target_width); 00289 } 00290 if (!ISPOW2(target_height)) { 00291 target_height = down_to_power_2(target_height); 00292 } 00293 if (!ISPOW2(target_depth)) { 00294 target_depth = down_to_power_2(target_depth); 00295 } 00296 } 00297 break; 00298 00299 case Texture::TT_cube_map: 00300 if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) == 0) { 00301 dxgsg9_cat.warning() 00302 << "Cube map textures are not supported by this graphics driver.\n"; 00303 return false; 00304 } 00305 00306 filter_caps = scrn._d3dcaps.CubeTextureFilterCaps; 00307 00308 if (target_width > scrn._d3dcaps.MaxTextureWidth) { 00309 target_width = scrn._d3dcaps.MaxTextureWidth; 00310 } 00311 00312 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) { 00313 if (!ISPOW2(target_width)) { 00314 target_width = down_to_power_2(target_width); 00315 } 00316 } 00317 00318 target_height = target_width; 00319 break; 00320 } 00321 00322 // checks for SQUARE reqmt (nvidia riva128 needs this) 00323 if ((target_width != target_height) && 00324 (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0) { 00325 // assume pow2 textures. sum exponents, divide by 2 rounding down 00326 // to get sq size 00327 int i, width_exp, height_exp; 00328 for (i = target_width, width_exp = 0; i > 1; width_exp++, i >>= 1) { 00329 } 00330 for (i = target_height, height_exp = 0; i > 1; height_exp++, i >>= 1) { 00331 } 00332 target_height = target_width = 1<<((width_exp+height_exp)>>1); 00333 } 00334 00335 bool shrink_original = false; 00336 00337 if (orig_width != target_width || orig_height != target_height || 00338 orig_depth != target_depth) { 00339 if (tex->get_texture_type() == Texture::TT_3d_texture) { 00340 dxgsg9_cat.info() 00341 << "Reducing size of " << tex->get_name() 00342 << " from " << orig_width << "x" << orig_height << "x" << orig_depth 00343 << " to " << target_width << "x" << target_height 00344 << "x" << target_depth << "\n"; 00345 } else { 00346 dxgsg9_cat.info() 00347 << "Reducing size of " << tex->get_name() 00348 << " from " << orig_width << "x" << orig_height 00349 << " to " << target_width << "x" << target_height << "\n"; 00350 } 00351 00352 shrink_original = true; 00353 } 00354 00355 const char *error_message; 00356 00357 error_message = "create_texture failed: couldn't find compatible device Texture Pixel Format for input texture"; 00358 00359 if (dxgsg9_cat.is_spam()) { 00360 dxgsg9_cat.spam() 00361 << "create_texture handling target bitdepth: " << target_bpp 00362 << " alphabits: " << num_alpha_bits << endl; 00363 } 00364 00365 // I could possibly replace some of this logic with 00366 // D3DXCheckTextureRequirements(), but it wouldn't handle all my 00367 // specialized low-memory cases perfectly 00368 00369 #define CHECK_FOR_FMT(FMT) \ 00370 if (scrn._supported_tex_formats_mask & FMT##_FLAG) { \ 00371 target_pixel_format = D3DFMT_##FMT; \ 00372 goto found_matching_format; } 00373 00374 if (texture_stored_compressed && compress_texture) { 00375 // if the texture is already compressed, we need to choose the 00376 // corresponding format, otherwise we might end up 00377 // cross-compressing from e.g. DXT5 to DXT3 00378 switch (compression_mode){ 00379 case Texture::CM_dxt1: 00380 CHECK_FOR_FMT(DXT1); 00381 break; 00382 case Texture::CM_dxt2: 00383 CHECK_FOR_FMT(DXT2); 00384 break; 00385 case Texture::CM_dxt3: 00386 CHECK_FOR_FMT(DXT3); 00387 break; 00388 case Texture::CM_dxt4: 00389 CHECK_FOR_FMT(DXT4); 00390 break; 00391 case Texture::CM_dxt5: 00392 CHECK_FOR_FMT(DXT5); 00393 break; 00394 } 00395 00396 // We don't support the compressed format. Fall through. 00397 } 00398 00399 if (compress_texture) { 00400 if (num_alpha_bits <= 1) { 00401 CHECK_FOR_FMT(DXT1); 00402 } else if (num_alpha_bits <= 4) { 00403 CHECK_FOR_FMT(DXT3); 00404 } else { 00405 CHECK_FOR_FMT(DXT5); 00406 } 00407 } 00408 00409 // We can't compress for some reason, so ensure the uncompressed 00410 // image is ready to load. 00411 if (texture_stored_compressed) { 00412 tex->get_uncompressed_ram_image(); 00413 compression_mode = tex->get_ram_image_compression(); 00414 texture_stored_compressed = compression_mode != Texture::CM_off; 00415 compress_texture = false; 00416 } 00417 00418 // handle each target bitdepth separately. might be less confusing 00419 // to reorg by num_color_channels (input type, rather than desired 00420 // 1st target) 00421 switch (target_bpp) { 00422 00423 // IMPORTANT NOTE: 00424 // target_bpp is REQUESTED bpp, not what exists in the texture 00425 // array (the texture array contains num_color_channels*8bits) 00426 00427 case 128: 00428 // check if format is supported 00429 if (scrn._supports_rgba32_texture_format) { 00430 target_pixel_format = D3DFMT_A32B32G32R32F; 00431 } 00432 else { 00433 target_pixel_format = scrn._render_to_texture_d3d_format; 00434 } 00435 goto found_matching_format; 00436 00437 case 64: 00438 // check if format is supported 00439 if (scrn._supports_rgba16f_texture_format) { 00440 target_pixel_format = D3DFMT_A16B16G16R16F; 00441 } 00442 else { 00443 target_pixel_format = scrn._render_to_texture_d3d_format; 00444 } 00445 goto found_matching_format; 00446 00447 case 32: 00448 if (!((num_color_channels == 3) || (num_color_channels == 4))) 00449 break; //bail 00450 00451 CHECK_FOR_FMT(A8R8G8B8); 00452 00453 if (num_alpha_bits>0) { 00454 nassertr(num_color_channels == 4, false); 00455 00456 // no 32-bit fmt, look for 16 bit w/alpha (1-15) 00457 00458 // 32 bit RGBA was requested, but only 16 bit alpha fmts are 00459 // avail. By default, convert to 4-4-4-4 which has 4-bit alpha 00460 // for blurry edges. If we know tex only needs 1 bit alpha 00461 // (i.e. for a mask), use 1555 instead. 00462 00463 00464 // ConversionType ConvTo1 = Conv32to16_4444, ConvTo2 = Conv32to16_1555; 00465 // DWORD dwAlphaMask1 = 0xF000, dwAlphaMask2 = 0x8000; 00466 00467 // assume ALPHAMASK is x8000 and RGBMASK is x7fff to simplify 00468 // 32->16 conversion. This should be true on most cards. 00469 00470 if (num_alpha_bits == 1) { 00471 CHECK_FOR_FMT(A1R5G5B5); 00472 } 00473 00474 // normally prefer 4444 due to better alpha channel resolution 00475 CHECK_FOR_FMT(A4R4G4B4); 00476 CHECK_FOR_FMT(A1R5G5B5); 00477 00478 // At this point, bail. Don't worry about converting to 00479 // non-alpha formats yet, I think this will be a very rare case. 00480 error_message = "create_texture failed: couldn't find compatible Tex DDPIXELFORMAT! no available 16 or 32-bit alpha formats!"; 00481 } else { 00482 // convert 3 or 4 channel to closest 16bpp color fmt 00483 00484 if (num_color_channels == 3) { 00485 CHECK_FOR_FMT(R5G6B5); 00486 CHECK_FOR_FMT(X1R5G5B5); 00487 } else { 00488 CHECK_FOR_FMT(R5G6B5); 00489 CHECK_FOR_FMT(X1R5G5B5); 00490 } 00491 } 00492 break; 00493 00494 case 24: 00495 nassertr(num_color_channels == 3, false); 00496 00497 CHECK_FOR_FMT(R8G8B8); 00498 00499 // no 24-bit fmt. look for 32 bit fmt (note: this is 00500 // memory-hogging choice instead I could look for 00501 // memory-conserving 16-bit fmt). 00502 00503 CHECK_FOR_FMT(X8R8G8B8); 00504 CHECK_FOR_FMT(A8R8G8B8); 00505 00506 // no 24-bit or 32 fmt. look for 16 bit fmt (higher res 565 1st) 00507 CHECK_FOR_FMT(R5G6B5); 00508 CHECK_FOR_FMT(X1R5G5B5); 00509 CHECK_FOR_FMT(A1R5G5B5); 00510 break; 00511 00512 case 16: 00513 if (needs_luminance) { 00514 nassertr(num_alpha_bits > 0, false); 00515 nassertr(num_color_channels == 2, false); 00516 00517 CHECK_FOR_FMT(A8L8); 00518 CHECK_FOR_FMT(A8R8G8B8); 00519 00520 if (num_alpha_bits == 1) { 00521 CHECK_FOR_FMT(A1R5G5B5); 00522 } 00523 00524 // normally prefer 4444 due to better alpha channel resolution 00525 CHECK_FOR_FMT(A4R4G4B4); 00526 CHECK_FOR_FMT(A1R5G5B5); 00527 } else { 00528 nassertr((num_color_channels == 3)||(num_color_channels == 4), false); 00529 // look for compatible 16bit fmts, if none then give up 00530 // (don't worry about other bitdepths for 16 bit) 00531 switch(num_alpha_bits) { 00532 case 0: 00533 if (num_color_channels == 3) { 00534 CHECK_FOR_FMT(R5G6B5); 00535 CHECK_FOR_FMT(X1R5G5B5); 00536 } else { 00537 nassertr(num_color_channels == 4, false); 00538 // it could be 4 if user asks us to throw away the alpha channel 00539 CHECK_FOR_FMT(R5G6B5); 00540 CHECK_FOR_FMT(X1R5G5B5); 00541 } 00542 break; 00543 case 1: 00544 // app specifically requests 1-5-5-5 F_rgba5 case, where you 00545 // explicitly want 1-5-5-5 fmt, as opposed to F_rgbm, which 00546 // could use 32bpp ARGB. fail if this particular fmt not 00547 // avail. 00548 nassertr(num_color_channels == 4, false); 00549 CHECK_FOR_FMT(X1R5G5B5); 00550 break; 00551 case 4: 00552 // app specifically requests 4-4-4-4 F_rgba4 case, as opposed 00553 // to F_rgba, which could use 32bpp ARGB 00554 nassertr(num_color_channels == 4, false); 00555 CHECK_FOR_FMT(A4R4G4B4); 00556 break; 00557 default: 00558 nassertr(false, false); // problem in get_bits_per_pixel()? 00559 } 00560 } 00561 case 8: 00562 if (needs_luminance) { 00563 // don't bother handling those other 8bit lum fmts like 4-4, 00564 // since 16 8-8 is usually supported too 00565 nassertr(num_color_channels == 1, false); 00566 00567 // look for native lum fmt first 00568 CHECK_FOR_FMT(L8); 00569 CHECK_FOR_FMT(L8); 00570 00571 CHECK_FOR_FMT(R8G8B8); 00572 CHECK_FOR_FMT(X8R8G8B8); 00573 00574 CHECK_FOR_FMT(R5G6B5); 00575 CHECK_FOR_FMT(X1R5G5B5); 00576 00577 } else if (num_alpha_bits == 8) { 00578 // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444. 00579 00580 // skip 8bit alpha only (D3DFMT_A8), because I think only voodoo 00581 // supports it and the voodoo support isn't the kind of blending 00582 // model we need somehow (is it that voodoo assumes color is 00583 // white? isnt that what we do in ConvAlpha8to32 anyway?) 00584 00585 CHECK_FOR_FMT(A8L8); 00586 CHECK_FOR_FMT(A8R8G8B8); 00587 CHECK_FOR_FMT(A4R4G4B4); 00588 } 00589 break; 00590 00591 default: 00592 error_message = "create_texture failed: unhandled pixel bitdepth in DX loader"; 00593 } 00594 00595 // if we've gotten here, haven't found a match 00596 dxgsg9_cat.error() 00597 << error_message << ": " << tex->get_name() << endl 00598 << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: " 00599 << num_alpha_bits << "; targetbpp: " <<target_bpp 00600 << "; _supported_tex_formats_mask: 0x" 00601 << (void*)scrn._supported_tex_formats_mask 00602 << "; NeedLuminance: " << needs_luminance << endl; 00603 goto error_exit; 00604 00605 /////////////////////////////////////////////////////////// 00606 00607 found_matching_format: 00608 // We found a suitable format that matches the texture's format. 00609 00610 if (tex->get_match_framebuffer_format()) { 00611 // Instead of creating a texture with the found format, we will 00612 // need to make one that exactly matches the framebuffer's 00613 // format. Look up what that format is. 00614 DWORD render_target_index; 00615 IDirect3DSurface9 *render_target; 00616 00617 render_target_index = 0; 00618 hr = scrn._d3d_device->GetRenderTarget(render_target_index, &render_target); 00619 if (FAILED(hr)) { 00620 dxgsg9_cat.error() 00621 << "GetRenderTgt failed in create_texture: " << D3DERRORSTRING(hr); 00622 } else { 00623 D3DSURFACE_DESC surface_desc; 00624 hr = render_target->GetDesc(&surface_desc); 00625 if (FAILED(hr)) { 00626 dxgsg9_cat.error() 00627 << "GetDesc failed in create_texture: " << D3DERRORSTRING(hr); 00628 } else { 00629 if (target_pixel_format != surface_desc.Format) { 00630 if (dxgsg9_cat.is_debug()) { 00631 dxgsg9_cat.debug() 00632 << "Chose format " << D3DFormatStr(surface_desc.Format) 00633 << " instead of " << D3DFormatStr(target_pixel_format) 00634 << " for texture to match framebuffer.\n"; 00635 } 00636 target_pixel_format = surface_desc.Format; 00637 } 00638 } 00639 SAFE_RELEASE(render_target); 00640 } 00641 } 00642 00643 // validate magfilter setting 00644 // degrade filtering if no HW support 00645 00646 Texture::FilterType ft; 00647 00648 ft = tex->get_magfilter(); 00649 if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) { 00650 // mipmap settings make no sense for magfilter 00651 if (ft == Texture::FT_nearest_mipmap_nearest) { 00652 ft = Texture::FT_nearest; 00653 } else { 00654 ft = Texture::FT_linear; 00655 } 00656 } 00657 00658 if (ft == Texture::FT_linear && 00659 (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) { 00660 ft = Texture::FT_nearest; 00661 } 00662 tex->set_magfilter(ft); 00663 00664 // figure out if we are mipmapping this texture 00665 ft = tex->get_minfilter(); 00666 _has_mipmaps = false; 00667 00668 if (!dx_ignore_mipmaps) { // set if no HW mipmap capable 00669 switch(ft) { 00670 case Texture::FT_nearest_mipmap_nearest: 00671 case Texture::FT_linear_mipmap_nearest: 00672 case Texture::FT_nearest_mipmap_linear: // pick nearest in each, interpolate linearly b/w them 00673 case Texture::FT_linear_mipmap_linear: 00674 _has_mipmaps = true; 00675 } 00676 00677 if (dx_mipmap_everything) { // debug toggle, ok to leave in since its just a creation cost 00678 _has_mipmaps = true; 00679 if (dxgsg9_cat.is_spam()) { 00680 if (ft != Texture::FT_linear_mipmap_linear) { 00681 dxgsg9_cat.spam() 00682 << "Forcing trilinear mipmapping on DX texture [" 00683 << tex->get_name() << "]\n"; 00684 } 00685 } 00686 ft = Texture::FT_linear_mipmap_linear; 00687 tex->set_minfilter(ft); 00688 } 00689 00690 } else if ((ft == Texture::FT_nearest_mipmap_nearest) || // cvt to no-mipmap filter types 00691 (ft == Texture::FT_nearest_mipmap_linear)) { 00692 ft = Texture::FT_nearest; 00693 00694 } else if ((ft == Texture::FT_linear_mipmap_nearest) || 00695 (ft == Texture::FT_linear_mipmap_linear)) { 00696 ft = Texture::FT_linear; 00697 } 00698 00699 nassertr((filter_caps & D3DPTFILTERCAPS_MINFPOINT) != 0, false); 00700 00701 #define TRILINEAR_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MINFLINEAR) 00702 00703 // do any other filter type degradations necessary 00704 switch(ft) { 00705 case Texture::FT_linear_mipmap_linear: 00706 if ((filter_caps & TRILINEAR_MIPMAP_TEXFILTERCAPS) != TRILINEAR_MIPMAP_TEXFILTERCAPS) { 00707 if (filter_caps & D3DPTFILTERCAPS_MINFLINEAR) { 00708 ft = Texture::FT_linear_mipmap_nearest; 00709 } else { 00710 // if you cant do linear in a level, you probably cant do 00711 // linear b/w levels, so just do nearest-all 00712 ft = Texture::FT_nearest_mipmap_nearest; 00713 } 00714 } 00715 break; 00716 00717 case Texture::FT_nearest_mipmap_linear: 00718 // if we don't have bilinear, do nearest_nearest 00719 if (!((filter_caps & D3DPTFILTERCAPS_MIPFPOINT) && 00720 (filter_caps & D3DPTFILTERCAPS_MINFLINEAR))) { 00721 ft = Texture::FT_nearest_mipmap_nearest; 00722 } 00723 break; 00724 00725 case Texture::FT_linear_mipmap_nearest: 00726 // if we don't have mip linear, do nearest_nearest 00727 if (!(filter_caps & D3DPTFILTERCAPS_MIPFLINEAR)) { 00728 ft = Texture::FT_nearest_mipmap_nearest; 00729 } 00730 break; 00731 00732 case Texture::FT_linear: 00733 if (!(filter_caps & D3DPTFILTERCAPS_MINFLINEAR)) { 00734 ft = Texture::FT_nearest; 00735 } 00736 break; 00737 } 00738 00739 tex->set_minfilter(ft); 00740 00741 uint aniso_degree; 00742 00743 aniso_degree = 1; 00744 if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) { 00745 aniso_degree = tex->get_anisotropic_degree(); 00746 if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) || 00747 dx_force_anisotropic_filtering) { 00748 aniso_degree = scrn._d3dcaps.MaxAnisotropy; 00749 } 00750 } 00751 tex->set_anisotropic_degree(aniso_degree); 00752 00753 #ifdef _DEBUG 00754 dxgsg9_cat.spam() 00755 << "create_texture: setting aniso degree for " << tex->get_name() 00756 << " to: " << aniso_degree << endl; 00757 #endif 00758 00759 UINT mip_level_count; 00760 00761 if (_has_mipmaps) { 00762 tex->get_ram_image(); 00763 mip_level_count = tex->get_num_loadable_ram_mipmap_images(); 00764 if (mip_level_count < 2) { 00765 // tell CreateTex to alloc space for all mip levels down to 1x1 00766 mip_level_count = 0; 00767 00768 if (dxgsg9_cat.is_debug()) { 00769 dxgsg9_cat.debug() 00770 << "create_texture: generating mipmaps for " << tex->get_name() 00771 << endl; 00772 } 00773 } 00774 } else { 00775 mip_level_count = 1; 00776 } 00777 00778 DWORD usage; 00779 D3DPOOL pool; 00780 00781 usage = 0; 00782 if (tex->get_render_to_texture ( )) { 00783 // REQUIRED PARAMETERS 00784 _managed = false; 00785 _is_render_target = true; 00786 00787 pool = D3DPOOL_DEFAULT; 00788 usage = D3DUSAGE_RENDERTARGET; 00789 if (target_bpp <= 32 ) { 00790 target_pixel_format = scrn._render_to_texture_d3d_format; 00791 } 00792 00793 dxgsg9_cat.debug () 00794 << "*** RENDER TO TEXTURE ***: format " 00795 << D3DFormatStr(target_pixel_format) 00796 << " " 00797 << target_pixel_format 00798 << "\n"; 00799 } 00800 else { 00801 _managed = scrn._managed_textures; 00802 if (_managed) { 00803 pool = D3DPOOL_MANAGED; 00804 } 00805 else { 00806 if (scrn._supports_automatic_mipmap_generation) { 00807 pool = D3DPOOL_DEFAULT; 00808 usage = D3DUSAGE_AUTOGENMIPMAP; 00809 } 00810 else { 00811 if (dx_use_dynamic_textures) { 00812 if (scrn._supports_dynamic_textures) { 00813 pool = D3DPOOL_DEFAULT; 00814 usage = D3DUSAGE_DYNAMIC; 00815 } 00816 else { 00817 // can't lock textures so go back to managed for now 00818 // need to use UpdateTexture or UpdateSurface 00819 _managed = true; 00820 pool = D3DPOOL_MANAGED; 00821 } 00822 } 00823 else { 00824 pool = D3DPOOL_DEFAULT; 00825 } 00826 } 00827 } 00828 } 00829 00830 PN_stdfloat bytes_per_texel; 00831 00832 bytes_per_texel = this -> d3d_format_to_bytes_per_pixel (target_pixel_format); 00833 if (bytes_per_texel == 0.0f) { 00834 dxgsg9_cat.error() 00835 << "D3D create_texture ( ) unknown texture format\n"; 00836 } 00837 00838 int data_size; 00839 00840 data_size = target_width * target_height * target_depth; 00841 if (_has_mipmaps) { 00842 data_size = (int) ((PN_stdfloat) data_size * 1.3333333); 00843 } 00844 data_size = (int) ((PN_stdfloat) data_size * bytes_per_texel); 00845 if (tex->get_texture_type() == Texture::TT_cube_map) { 00846 data_size *= 6; 00847 } 00848 update_data_size_bytes(data_size); 00849 00850 int attempts; 00851 00852 if (dxgsg9_cat.is_debug()) { 00853 dxgsg9_cat.debug() 00854 << "Creating " << *tex << ", " << data_size << " bytes, " 00855 << scrn._d3d_device->GetAvailableTextureMem() 00856 << " reported available.\n"; 00857 dxgsg9_cat.debug() 00858 << " size is " << target_width << " w * " << target_height << " h * " 00859 << target_depth << " d"; 00860 if (_has_mipmaps) { 00861 dxgsg9_cat.debug(false) 00862 << " * 1.3333333 mipmaps"; 00863 } 00864 dxgsg9_cat.debug(false) 00865 << " * " << bytes_per_texel << " bpt"; 00866 if (tex->get_texture_type() == Texture::TT_cube_map) { 00867 dxgsg9_cat.debug(false) 00868 << " * 6 faces"; 00869 } 00870 dxgsg9_cat.debug(false) 00871 << "\n"; 00872 } 00873 00874 attempts = 0; 00875 do 00876 { 00877 switch (tex->get_texture_type()) { 00878 case Texture::TT_1d_texture: 00879 case Texture::TT_2d_texture: 00880 hr = scrn._d3d_device->CreateTexture 00881 (target_width, target_height, mip_level_count, usage, 00882 target_pixel_format, pool, &_d3d_2d_texture, NULL); 00883 _d3d_texture = _d3d_2d_texture; 00884 break; 00885 00886 case Texture::TT_3d_texture: 00887 hr = scrn._d3d_device->CreateVolumeTexture 00888 (target_width, target_height, target_depth, mip_level_count, usage, 00889 target_pixel_format, pool, &_d3d_volume_texture, NULL); 00890 _d3d_texture = _d3d_volume_texture; 00891 break; 00892 00893 case Texture::TT_cube_map: 00894 hr = scrn._d3d_device->CreateCubeTexture 00895 (target_width, mip_level_count, usage, 00896 target_pixel_format, pool, &_d3d_cube_texture, NULL); 00897 _d3d_texture = _d3d_cube_texture; 00898 00899 target_height = target_width; 00900 break; 00901 } 00902 00903 attempts++; 00904 } while (scrn._dxgsg9 -> check_dx_allocation (hr, data_size, attempts)); 00905 00906 if (FAILED(hr)) { 00907 dxgsg9_cat.error() 00908 << "D3D create_texture failed!" << D3DERRORSTRING(hr); 00909 dxgsg9_cat.error() 00910 << " width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n"; 00911 00912 goto error_exit; 00913 } 00914 00915 if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) { 00916 dxgsg9_cat.debug() 00917 << "create_texture: " << tex->get_name() 00918 << " converting panda equivalent of " << D3DFormatStr(_d3d_format) 00919 << " => " << D3DFormatStr(target_pixel_format) << endl; 00920 } 00921 00922 hr = fill_d3d_texture_pixels(scrn, compress_texture); 00923 if (FAILED(hr)) { 00924 00925 dxgsg9_cat.debug () 00926 << "*** fill_d3d_texture_pixels failed ***: format " 00927 << target_pixel_format 00928 << "\n"; 00929 00930 goto error_exit; 00931 } 00932 00933 if (tex->get_post_load_store_cache()) { 00934 tex->set_post_load_store_cache(false); 00935 // OK, get the RAM image, and save it in a BamCache record. 00936 if (extract_texture_data(scrn)) { 00937 if (tex->has_ram_image()) { 00938 BamCache *cache = BamCache::get_global_ptr(); 00939 PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo"); 00940 if (record != (BamCacheRecord *)NULL) { 00941 record->set_data(tex, tex); 00942 cache->store(record); 00943 } 00944 } 00945 } 00946 } 00947 00948 // must not put render to texture into LRU 00949 if (!_managed && !tex->get_render_to_texture()) { 00950 scrn._dxgsg9->get_engine()->texture_uploaded(tex); 00951 } 00952 mark_loaded(); 00953 00954 return true; 00955 00956 error_exit: 00957 00958 RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE); 00959 _d3d_2d_texture = NULL; 00960 _d3d_volume_texture = NULL; 00961 _d3d_cube_texture = NULL; 00962 return false; 00963 } 00964 00965 //////////////////////////////////////////////////////////////////// 00966 // Function: DXTextureContext9::create_simple_texture 00967 // Access: Public 00968 // Description: 00969 //////////////////////////////////////////////////////////////////// 00970 bool DXTextureContext9:: 00971 create_simple_texture(DXScreenData &scrn) { 00972 nassertr(IS_VALID_PTR(get_texture()), false); 00973 00974 HRESULT hr; 00975 00976 delete_texture(); 00977 00978 _d3d_format = D3DFMT_A8R8G8B8; 00979 D3DFORMAT target_pixel_format = D3DFMT_A8R8G8B8; 00980 DWORD target_bpp = 32; 00981 DWORD num_color_channels = 4; 00982 00983 DWORD target_width = (DWORD)get_texture()->get_simple_x_size(); 00984 DWORD target_height = (DWORD)get_texture()->get_simple_y_size(); 00985 DWORD mip_level_count = 1; 00986 DWORD usage = 0; 00987 D3DPOOL pool = D3DPOOL_MANAGED; 00988 00989 int data_size = target_width * target_height * 4; 00990 00991 hr = scrn._d3d_device->CreateTexture 00992 (target_width, target_height, mip_level_count, usage, 00993 target_pixel_format, pool, &_d3d_2d_texture, NULL); 00994 _d3d_texture = _d3d_2d_texture; 00995 if (FAILED(hr)) { 00996 dxgsg9_cat.error() 00997 << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr); 00998 dxgsg9_cat.error() 00999 << " width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n"; 01000 01001 goto error_exit; 01002 } 01003 01004 if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) { 01005 dxgsg9_cat.debug() 01006 << "create_simple_texture: " << get_texture()->get_name() 01007 << "\n"; 01008 } 01009 01010 { 01011 CPTA_uchar image = get_texture()->get_simple_ram_image(); 01012 01013 hr = -1; 01014 // hr = fill_d3d_texture_pixels(scrn); 01015 01016 IDirect3DSurface9 *surface = NULL; 01017 _d3d_2d_texture->GetSurfaceLevel(0, &surface); 01018 01019 RECT source_size; 01020 source_size.left = source_size.top = 0; 01021 source_size.right = target_width; 01022 source_size.bottom = target_height; 01023 01024 DWORD mip_filter = D3DX_FILTER_LINEAR; 01025 01026 hr = D3DXLoadSurfaceFromMemory 01027 (surface, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)image.p(), 01028 target_pixel_format, target_width * 4, (PALETTEENTRY*)NULL, 01029 &source_size, mip_filter, (D3DCOLOR)0x0); 01030 01031 RELEASE(surface, dxgsg9, "create_simple_texture Surface", RELEASE_ONCE); 01032 } 01033 01034 if (FAILED(hr)) { 01035 dxgsg9_cat.debug () 01036 << "*** fill_d3d_texture_pixels failed ***: format " 01037 << target_pixel_format 01038 << "\n"; 01039 01040 goto error_exit; 01041 } 01042 01043 mark_simple_loaded(); 01044 return true; 01045 01046 error_exit: 01047 RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE); 01048 _d3d_2d_texture = NULL; 01049 _d3d_volume_texture = NULL; 01050 _d3d_cube_texture = NULL; 01051 return false; 01052 } 01053 01054 //////////////////////////////////////////////////////////////////// 01055 // Function: DXTextureContext9::delete_texture 01056 // Access: Public 01057 // Description: Release the surface used to store the texture 01058 //////////////////////////////////////////////////////////////////// 01059 void DXTextureContext9:: 01060 delete_texture() { 01061 01062 if (_d3d_texture == NULL) { 01063 // don't bother printing the msg below, since we already released it. 01064 return; 01065 } 01066 01067 RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE); 01068 _d3d_2d_texture = NULL; 01069 _d3d_volume_texture = NULL; 01070 _d3d_cube_texture = NULL; 01071 } 01072 01073 //////////////////////////////////////////////////////////////////// 01074 // Function: DXTextureContext9::extract_texture_data 01075 // Access: Public 01076 // Description: This method will be called in the draw thread to 01077 // download the texture memory's image into its 01078 // ram_image value. It returns true on success, false 01079 // otherwise. 01080 //////////////////////////////////////////////////////////////////// 01081 bool DXTextureContext9:: 01082 extract_texture_data(DXScreenData &screen) { 01083 bool state; 01084 HRESULT hr; 01085 01086 state = false; 01087 Texture *tex = get_texture(); 01088 if (tex->get_texture_type() != Texture::TT_2d_texture) { 01089 dxgsg9_cat.error() 01090 << "Not supported: extract_texture_data for " << tex->get_texture_type() 01091 << "\n"; 01092 return state; 01093 } 01094 nassertr(IS_VALID_PTR(_d3d_2d_texture), false); 01095 01096 D3DSURFACE_DESC desc; 01097 hr = _d3d_2d_texture->GetLevelDesc(0, &desc); 01098 if (FAILED(hr)) { 01099 dxgsg9_cat.error() 01100 << "Texture::GetLevelDesc() failed!" << D3DERRORSTRING(hr); 01101 return state; 01102 } 01103 01104 int div = 1; 01105 Texture::Format format = Texture::F_rgba; 01106 Texture::CompressionMode compression = Texture::CM_off; 01107 01108 switch (desc.Format) { 01109 case D3DFMT_R8G8B8: 01110 format = Texture::F_rgb; 01111 break; 01112 01113 case D3DFMT_A8R8G8B8: 01114 case D3DFMT_X8R8G8B8: 01115 break; 01116 01117 case D3DFMT_L8: 01118 format = Texture::F_luminance; 01119 break; 01120 01121 case D3DFMT_A8L8: 01122 format = Texture::F_luminance_alpha; 01123 break; 01124 01125 case D3DFMT_DXT1: 01126 compression = Texture::CM_dxt1; 01127 div = 4; 01128 break; 01129 case D3DFMT_DXT2: 01130 compression = Texture::CM_dxt2; 01131 div = 4; 01132 break; 01133 case D3DFMT_DXT3: 01134 compression = Texture::CM_dxt3; 01135 div = 4; 01136 break; 01137 case D3DFMT_DXT4: 01138 compression = Texture::CM_dxt4; 01139 div = 4; 01140 break; 01141 case D3DFMT_DXT5: 01142 compression = Texture::CM_dxt5; 01143 div = 4; 01144 break; 01145 01146 default: 01147 dxgsg9_cat.error() 01148 << "Cannot extract texture data: unhandled surface format " 01149 << desc.Format << "\n"; 01150 return state; 01151 } 01152 01153 int num_levels = _d3d_2d_texture->GetLevelCount(); 01154 01155 tex->set_x_size(desc.Width); 01156 tex->set_y_size(desc.Height); 01157 tex->set_z_size(1); 01158 tex->set_component_type(Texture::T_unsigned_byte); 01159 tex->set_format(format); 01160 tex->clear_ram_image(); 01161 01162 if (_is_render_target) { 01163 IDirect3DSurface9* source_surface; 01164 IDirect3DSurface9* destination_surface; 01165 01166 source_surface = 0; 01167 destination_surface = 0; 01168 01169 hr = _d3d_2d_texture -> GetSurfaceLevel (0, &source_surface); 01170 if (hr == D3D_OK) { 01171 01172 D3DPOOL pool; 01173 D3DSURFACE_DESC surface_description; 01174 01175 pool = D3DPOOL_SYSTEMMEM; 01176 source_surface -> GetDesc (&surface_description); 01177 01178 hr = screen._d3d_device->CreateOffscreenPlainSurface ( 01179 surface_description.Width, 01180 surface_description.Height, 01181 surface_description.Format, 01182 pool, 01183 &destination_surface, 01184 NULL); 01185 if (hr == D3D_OK) { 01186 if (source_surface && destination_surface) { 01187 hr = screen._d3d_device -> GetRenderTargetData (source_surface, destination_surface); 01188 if (hr == D3D_OK) { 01189 01190 D3DLOCKED_RECT rect; 01191 01192 hr = destination_surface -> LockRect (&rect, NULL, D3DLOCK_READONLY); 01193 if (hr == D3D_OK) { 01194 01195 unsigned int y; 01196 int size; 01197 int bytes_per_line; 01198 01199 int surface_bytes_per_line; 01200 unsigned char *surface_pointer; 01201 01202 bytes_per_line = surface_description.Width * this -> d3d_format_to_bytes_per_pixel (surface_description.Format); 01203 size = bytes_per_line * surface_description.Height; 01204 01205 surface_bytes_per_line = rect.Pitch; 01206 surface_pointer = (unsigned char *) rect.pBits; 01207 01208 PTA_uchar image = PTA_uchar::empty_array(size); 01209 01210 int offset; 01211 01212 offset = 0; 01213 for (y = 0; y < surface_description.Height; y++) 01214 { 01215 memcpy (&image [offset], surface_pointer, bytes_per_line); 01216 01217 offset += bytes_per_line; 01218 surface_pointer += surface_bytes_per_line; 01219 } 01220 01221 tex->set_ram_image(image, Texture::CM_off); 01222 01223 state = true; 01224 01225 destination_surface -> UnlockRect(); 01226 } 01227 } 01228 } 01229 01230 destination_surface -> Release ( ); 01231 } 01232 else { 01233 dxgsg9_cat.error() 01234 << "CreateImageSurface failed in extract_texture_data()" 01235 << D3DERRORSTRING(hr); 01236 } 01237 source_surface -> Release ( ); 01238 } 01239 } 01240 else { 01241 for (int n = 0; n < num_levels; ++n) { 01242 D3DLOCKED_RECT rect; 01243 hr = _d3d_2d_texture->LockRect(n, &rect, NULL, D3DLOCK_READONLY); 01244 if (FAILED(hr)) { 01245 dxgsg9_cat.error() 01246 << "Texture::LockRect() failed! level = " << n << " " << D3DERRORSTRING(hr); 01247 return state; 01248 } 01249 01250 int x_size = tex->get_expected_mipmap_x_size(n); 01251 int y_size = tex->get_expected_mipmap_y_size(n); 01252 PTA_uchar image; 01253 01254 if (compression == Texture::CM_off) { 01255 // Uncompressed, but we have to respect the pitch. 01256 int pitch = x_size * tex->get_num_components() * tex->get_component_width(); 01257 pitch = min(pitch, (int)rect.Pitch); 01258 int size = pitch * y_size; 01259 image = PTA_uchar::empty_array(size); 01260 if (pitch == rect.Pitch) { 01261 // Easy copy. 01262 memcpy(image.p(), rect.pBits, size); 01263 } else { 01264 // Harder copy: we have to de-interleave DirectX's extra bytes 01265 // on the end of each row. 01266 unsigned char *dest = image.p(); 01267 unsigned char *source = (unsigned char *)rect.pBits; 01268 for (int yi = 0; yi < y_size; ++yi) { 01269 memcpy(dest, source, pitch); 01270 dest += pitch; 01271 source += rect.Pitch; 01272 } 01273 } 01274 01275 } else { 01276 // Compressed; just copy the data verbatim. 01277 int size = rect.Pitch * (y_size / div); 01278 image = PTA_uchar::empty_array(size); 01279 memcpy(image.p(), rect.pBits, size); 01280 } 01281 01282 _d3d_2d_texture->UnlockRect(n); 01283 if (n == 0) { 01284 tex->set_ram_image(image, compression); 01285 } else { 01286 tex->set_ram_mipmap_image(n, image); 01287 } 01288 } 01289 01290 state = true; 01291 } 01292 01293 return state; 01294 } 01295 01296 //////////////////////////////////////////////////////////////////// 01297 // Function: DXTextureContext9::d3d_surface_to_texture 01298 // Access: Public, Static 01299 // Description: copies source_rect in pD3DSurf to upper left of 01300 // texture 01301 //////////////////////////////////////////////////////////////////// 01302 HRESULT DXTextureContext9:: 01303 d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface, 01304 bool inverted, Texture *result, int z) { 01305 // still need custom conversion since d3d/d3dx has no way to convert 01306 // arbitrary fmt to ARGB in-memory user buffer 01307 01308 HRESULT hr; 01309 DWORD num_components = result->get_num_components(); 01310 01311 nassertr(result->get_component_width() == sizeof(BYTE), E_FAIL); // cant handle anything else now 01312 nassertr(result->get_component_type() == Texture::T_unsigned_byte, E_FAIL); // cant handle anything else now 01313 nassertr((num_components == 3) || (num_components == 4), E_FAIL); // cant handle anything else now 01314 nassertr(IS_VALID_PTR(d3d_surface), E_FAIL); 01315 01316 BYTE *buf = result->modify_ram_image(); 01317 if (z >= 0) { 01318 nassertr(z < result->get_z_size(), E_FAIL); 01319 buf += z * result->get_expected_ram_page_size(); 01320 } 01321 01322 if (IsBadWritePtr(d3d_surface, sizeof(DWORD))) { 01323 dxgsg9_cat.error() 01324 << "d3d_surface_to_texture failed: bad pD3DSurf ptr value (" 01325 << ((void*)d3d_surface) << ")\n"; 01326 exit(1); 01327 } 01328 01329 DWORD x_window_offset, y_window_offset; 01330 DWORD copy_width, copy_height; 01331 01332 D3DLOCKED_RECT locked_rect; 01333 D3DSURFACE_DESC surface_desc; 01334 01335 hr = d3d_surface->GetDesc(&surface_desc); 01336 01337 x_window_offset = source_rect.left, y_window_offset = source_rect.top; 01338 copy_width = RECT_XSIZE(source_rect); 01339 copy_height = RECT_YSIZE(source_rect); 01340 01341 // make sure there's enough space in the texture, its size must 01342 // match (especially xsize) or scanlines will be too long 01343 01344 if (!((copy_width == result->get_x_size()) && (copy_height <= (DWORD)result->get_y_size()))) { 01345 dxgsg9_cat.error() 01346 << "d3d_surface_to_texture, Texture size (" << result->get_x_size() 01347 << ", " << result->get_y_size() 01348 << ") too small to hold display surface (" 01349 << copy_width << ", " << copy_height << ")\n"; 01350 nassertr(false, E_FAIL); 01351 return E_FAIL; 01352 } 01353 01354 hr = d3d_surface->LockRect(&locked_rect, (CONST RECT*)NULL, (D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE)); 01355 if (FAILED(hr)) { 01356 dxgsg9_cat.error() 01357 << "d3d_surface_to_texture LockRect() failed!" << D3DERRORSTRING(hr); 01358 return hr; 01359 } 01360 01361 // ones not listed not handled yet 01362 nassertr((surface_desc.Format == D3DFMT_A8R8G8B8) || 01363 (surface_desc.Format == D3DFMT_X8R8G8B8) || 01364 (surface_desc.Format == D3DFMT_R8G8B8) || 01365 (surface_desc.Format == D3DFMT_R5G6B5) || 01366 (surface_desc.Format == D3DFMT_X1R5G5B5) || 01367 (surface_desc.Format == D3DFMT_A1R5G5B5) || 01368 (surface_desc.Format == D3DFMT_A4R4G4B4), E_FAIL); 01369 01370 //buf contains raw ARGB in Texture byteorder 01371 01372 int byte_pitch = locked_rect.Pitch; 01373 BYTE *surface_bytes = (BYTE *)locked_rect.pBits; 01374 01375 if (inverted) { 01376 surface_bytes += byte_pitch * (y_window_offset + copy_height - 1); 01377 byte_pitch = -byte_pitch; 01378 } else { 01379 surface_bytes += byte_pitch * y_window_offset; 01380 } 01381 01382 // writes out last line in DDSurf first in PixelBuf, so Y line order 01383 // precedes inversely 01384 01385 if (DEBUG_SURFACES && dxgsg9_cat.is_debug()) { 01386 dxgsg9_cat.debug() 01387 << "d3d_surface_to_texture converting " 01388 << D3DFormatStr(surface_desc.Format) 01389 << " DDSurf to " << num_components << "-channel panda Texture\n"; 01390 } 01391 01392 DWORD *dest_word = (DWORD *)buf; 01393 BYTE *dest_byte = (BYTE *)buf; 01394 01395 switch(surface_desc.Format) { 01396 case D3DFMT_A8R8G8B8: 01397 case D3DFMT_X8R8G8B8: { 01398 if (num_components == 4) { 01399 DWORD *source_word; 01400 BYTE *dest_line = (BYTE*)dest_word; 01401 01402 for (DWORD y = 0; y < copy_height; y++) { 01403 source_word = ((DWORD*)surface_bytes) + x_window_offset; 01404 memcpy(dest_line, source_word, byte_pitch); 01405 dest_line += byte_pitch; 01406 surface_bytes += byte_pitch; 01407 } 01408 } else { 01409 // 24bpp texture case (numComponents == 3) 01410 DWORD *source_word; 01411 for (DWORD y = 0; y < copy_height; y++) { 01412 source_word = ((DWORD*)surface_bytes) + x_window_offset; 01413 01414 for (DWORD x = 0; x < copy_width; x++) { 01415 BYTE r, g, b; 01416 DWORD pixel = *source_word; 01417 01418 r = (BYTE)((pixel>>16) & g_LowByteMask); 01419 g = (BYTE)((pixel>> 8) & g_LowByteMask); 01420 b = (BYTE)((pixel ) & g_LowByteMask); 01421 01422 *dest_byte++ = b; 01423 *dest_byte++ = g; 01424 *dest_byte++ = r; 01425 source_word++; 01426 } 01427 surface_bytes += byte_pitch; 01428 } 01429 } 01430 break; 01431 } 01432 01433 case D3DFMT_R8G8B8: { 01434 BYTE *source_byte; 01435 01436 if (num_components == 4) { 01437 for (DWORD y = 0; y < copy_height; y++) { 01438 source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE); 01439 for (DWORD x = 0; x < copy_width; x++) { 01440 DWORD r, g, b; 01441 01442 b = *source_byte++; 01443 g = *source_byte++; 01444 r = *source_byte++; 01445 01446 *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b; 01447 dest_word++; 01448 } 01449 surface_bytes += byte_pitch; 01450 } 01451 } else { 01452 // 24bpp texture case (numComponents == 3) 01453 for (DWORD y = 0; y < copy_height; y++) { 01454 source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE); 01455 memcpy(dest_byte, source_byte, byte_pitch); 01456 dest_byte += byte_pitch; 01457 surface_bytes += byte_pitch; 01458 } 01459 } 01460 break; 01461 } 01462 01463 case D3DFMT_R5G6B5: 01464 case D3DFMT_X1R5G5B5: 01465 case D3DFMT_A1R5G5B5: 01466 case D3DFMT_A4R4G4B4: { 01467 WORD *source_word; 01468 // handle 0555, 1555, 0565, 4444 in same loop 01469 01470 BYTE redshift, greenshift, blueshift; 01471 DWORD redmask, greenmask, bluemask; 01472 01473 if (surface_desc.Format == D3DFMT_R5G6B5) { 01474 redshift = (11-3); 01475 redmask = 0xF800; 01476 greenmask = 0x07E0; 01477 greenshift = (5-2); 01478 bluemask = 0x001F; 01479 blueshift = 3; 01480 } else if (surface_desc.Format == D3DFMT_A4R4G4B4) { 01481 redmask = 0x0F00; 01482 redshift = 4; 01483 greenmask = 0x00F0; 01484 greenshift = 0; 01485 bluemask = 0x000F; 01486 blueshift = 4; 01487 } else { // 1555 or x555 01488 redmask = 0x7C00; 01489 redshift = (10-3); 01490 greenmask = 0x03E0; 01491 greenshift = (5-3); 01492 bluemask = 0x001F; 01493 blueshift = 3; 01494 } 01495 01496 if (num_components == 4) { 01497 // Note: these 16bpp loops ignore input alpha completely (alpha 01498 // is set to fully opaque in texture!) 01499 01500 // if we need to capture alpha, probably need to make separate 01501 // loops for diff 16bpp fmts for best speed 01502 01503 for (DWORD y = 0; y < copy_height; y++) { 01504 source_word = ((WORD*)surface_bytes) + x_window_offset; 01505 for (DWORD x = 0; x < copy_width; x++) { 01506 WORD pixel = *source_word; 01507 BYTE r, g, b; 01508 01509 b = (pixel & bluemask) << blueshift; 01510 g = (pixel & greenmask) >> greenshift; 01511 r = (pixel & redmask) >> redshift; 01512 01513 // alpha is just set to 0xFF 01514 01515 *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b; 01516 source_word++; 01517 dest_word++; 01518 } 01519 surface_bytes += byte_pitch; 01520 } 01521 } else { 01522 // 24bpp texture case (numComponents == 3) 01523 for (DWORD y = 0; y < copy_height; y++) { 01524 source_word = ((WORD*)surface_bytes) + x_window_offset; 01525 for (DWORD x = 0; x < copy_width; x++) { 01526 WORD pixel = *source_word; 01527 BYTE r, g, b; 01528 01529 b = (pixel & bluemask) << blueshift; 01530 g = (pixel & greenmask) >> greenshift; 01531 r = (pixel & redmask) >> redshift; 01532 01533 *dest_byte++ = b; 01534 *dest_byte++ = g; 01535 *dest_byte++ = r; 01536 01537 source_word++; 01538 } 01539 surface_bytes += byte_pitch; 01540 } 01541 } 01542 break; 01543 } 01544 01545 default: 01546 dxgsg9_cat.error() 01547 << "d3d_surface_to_texture: unsupported D3DFORMAT!\n"; 01548 } 01549 01550 d3d_surface->UnlockRect(); 01551 return S_OK; 01552 } 01553 01554 //////////////////////////////////////////////////////////////////// 01555 // Function: calculate_row_byte_length 01556 // Access: Private, hidden 01557 // Description: local helper function, which calculates the 01558 // 'row_byte_length' or 'pitch' needed for calling 01559 // D3DXLoadSurfaceFromMemory. 01560 // Takes compressed formats (DXTn) into account. 01561 //////////////////////////////////////////////////////////////////// 01562 static UINT calculate_row_byte_length (int width, int num_color_channels, D3DFORMAT tex_format) 01563 { 01564 UINT source_row_byte_length = 0; 01565 01566 // check for compressed textures and adjust source_row_byte_length and source_format accordingly 01567 switch (tex_format) { 01568 case D3DFMT_DXT1: 01569 // for dxt1 compressed textures, the row_byte_lenght is "the width of one row of cells, in bytes" 01570 // cells are 4 pixels wide, take up 8 bytes, and at least 1 cell has to be there. 01571 source_row_byte_length = max(1,width / 4)*8; 01572 break; 01573 case D3DFMT_DXT2: 01574 case D3DFMT_DXT3: 01575 case D3DFMT_DXT4: 01576 case D3DFMT_DXT5: 01577 // analogue as above, but cells take up 16 bytes 01578 source_row_byte_length = max(1,width / 4)*16; 01579 break; 01580 default: 01581 // no known compression format.. usual calculation 01582 source_row_byte_length = width*num_color_channels; 01583 break; 01584 } 01585 return source_row_byte_length; 01586 } 01587 01588 //////////////////////////////////////////////////////////////////// 01589 // Function: DXTextureContext9::fill_d3d_texture_mipmap_pixels 01590 // Access: Private 01591 // Description: Called from fill_d3d_texture_pixels, this function 01592 // fills a single mipmap with texture data. 01593 // Takes care of all necessery conversions and error 01594 // handling. 01595 //////////////////////////////////////////////////////////////////// 01596 HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format) 01597 { 01598 // This whole function was refactored out of fill_d3d_texture_pixels to make the code 01599 // more readable and to avoid code duplication. 01600 IDirect3DSurface9 *mip_surface = NULL; 01601 bool using_temp_buffer = false; 01602 HRESULT hr = E_FAIL; 01603 CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level); 01604 nassertr(!image.is_null(), E_FAIL); 01605 BYTE *pixels = (BYTE*) image.p(); 01606 DWORD width = (DWORD) get_texture()->get_expected_mipmap_x_size(mip_level); 01607 DWORD height = (DWORD) get_texture()->get_expected_mipmap_y_size(mip_level); 01608 int component_width = get_texture()->get_component_width(); 01609 01610 size_t view_size = get_texture()->get_ram_mipmap_view_size(mip_level); 01611 pixels += view_size * get_view(); 01612 size_t page_size = get_texture()->get_expected_ram_mipmap_page_size(mip_level); 01613 pixels += page_size * depth_index; 01614 01615 if (get_texture()->get_texture_type() == Texture::TT_cube_map) { 01616 nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL); 01617 hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)depth_index, mip_level, &mip_surface); 01618 } else { 01619 nassertr(IS_VALID_PTR(_d3d_2d_texture), E_FAIL); 01620 hr = _d3d_2d_texture->GetSurfaceLevel(mip_level, &mip_surface); 01621 } 01622 01623 if (FAILED(hr)) { 01624 dxgsg9_cat.error() 01625 << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name() 01626 << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr); 01627 return E_FAIL; 01628 } 01629 01630 RECT source_size; 01631 source_size.left = source_size.top = 0; 01632 source_size.right = width; 01633 source_size.bottom = height; 01634 01635 UINT source_row_byte_length = calculate_row_byte_length(width, get_texture()->get_num_components(), source_format); 01636 01637 DWORD mip_filter; 01638 // need filtering if size changes, (also if bitdepth reduced (need 01639 // dithering)??) 01640 mip_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures 01641 01642 // D3DXLoadSurfaceFromMemory will load black luminance and we want 01643 // full white, so convert to explicit luminance-alpha format 01644 if (_d3d_format == D3DFMT_A8) { 01645 // alloc buffer for explicit D3DFMT_A8L8 01646 USHORT *temp_buffer = new USHORT[width * height]; 01647 if (!IS_VALID_PTR(temp_buffer)) { 01648 dxgsg9_cat.error() 01649 << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n"; 01650 goto exit_FillMipmapSurf; 01651 } 01652 using_temp_buffer = true; 01653 01654 USHORT *out_pixels = temp_buffer; 01655 BYTE *source_pixels = pixels + component_width - 1; 01656 for (UINT y = 0; y < height; y++) { 01657 for (UINT x = 0; x < width; x++, source_pixels += component_width, out_pixels++) { 01658 // add full white, which is our interpretation of alpha-only 01659 // (similar to default adding full opaque alpha 0xFF to 01660 // RGB-only textures) 01661 *out_pixels = ((*source_pixels) << 8 ) | 0xFF; 01662 } 01663 } 01664 01665 source_format = D3DFMT_A8L8; 01666 source_row_byte_length = width * sizeof(USHORT); 01667 pixels = (BYTE*)temp_buffer; 01668 } 01669 else if (component_width != 1) { 01670 // Convert from 16-bit per channel (or larger) format down to 01671 // 8-bit per channel. This throws away precision in the 01672 // original image, but dx8 doesn't support high-precision images 01673 // anyway. 01674 01675 int num_components = get_texture()->get_num_components(); 01676 int num_pixels = width * height * num_components; 01677 BYTE *temp_buffer = new BYTE[num_pixels]; 01678 if (!IS_VALID_PTR(temp_buffer)) { 01679 dxgsg9_cat.error() << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n"; 01680 goto exit_FillMipmapSurf; 01681 } 01682 using_temp_buffer = true; 01683 01684 BYTE *source_pixels = pixels + component_width - 1; 01685 for (int i = 0; i < num_pixels; i++) { 01686 temp_buffer[i] = *source_pixels; 01687 source_pixels += component_width; 01688 } 01689 pixels = (BYTE*)temp_buffer; 01690 } 01691 01692 // filtering may be done here if texture if targetsize != origsize 01693 #ifdef DO_PSTATS 01694 GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * height); 01695 #endif 01696 hr = D3DXLoadSurfaceFromMemory 01697 (mip_surface, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)pixels, 01698 source_format, source_row_byte_length, (PALETTEENTRY*)NULL, 01699 &source_size, mip_filter, (D3DCOLOR)0x0); 01700 if (FAILED(hr)) { 01701 dxgsg9_cat.error() 01702 << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name() 01703 << ", mip_level " << mip_level 01704 << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr); 01705 } 01706 01707 exit_FillMipmapSurf: 01708 if (using_temp_buffer) { 01709 SAFE_DELETE_ARRAY(pixels); 01710 } 01711 01712 RELEASE(mip_surface, dxgsg9, "FillDDTextureMipmapPixels MipSurface texture ptr", RELEASE_ONCE); 01713 return hr; 01714 } 01715 01716 //////////////////////////////////////////////////////////////////// 01717 // Function: DXTextureContext9::fill_d3d_texture_pixels 01718 // Access: Private 01719 // Description: 01720 //////////////////////////////////////////////////////////////////// 01721 HRESULT DXTextureContext9:: 01722 fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) { 01723 IDirect3DDevice9 *device = scrn._d3d_device; 01724 Texture *tex = get_texture(); 01725 nassertr(IS_VALID_PTR(tex), E_FAIL); 01726 if (tex->get_texture_type() == Texture::TT_3d_texture) { 01727 return fill_d3d_volume_texture_pixels(scrn); 01728 } 01729 01730 HRESULT hr = E_FAIL; 01731 01732 CPTA_uchar image; 01733 Texture::CompressionMode image_compression = Texture::CM_off; 01734 if (compress_texture) { 01735 // If we are to be compressing this texture, accept a 01736 // pre-compressed ram image if it is already so. 01737 image = tex->get_ram_image(); 01738 if (!image.is_null()) { 01739 image_compression = tex->get_ram_image_compression(); 01740 } 01741 } else { 01742 // If we are not to be compressing this texture, we can only 01743 // accept an uncompressed ram image. Ask the texture to give us 01744 // one, so that there's no danger of accidentally getting a 01745 // pre-compressed image. 01746 image = tex->get_uncompressed_ram_image(); 01747 } 01748 01749 if (image.is_null()) { 01750 // The texture doesn't have an image to load. That's ok; it 01751 // might be a texture we've rendered to by frame buffer 01752 // operations or something. 01753 if (tex->get_render_to_texture()) { 01754 HRESULT result; 01755 01756 if (_d3d_2d_texture) { 01757 // clear render to texture 01758 IDirect3DSurface9 *surface; 01759 01760 result = _d3d_2d_texture -> GetSurfaceLevel (0, &surface); 01761 if (result == D3D_OK) { 01762 D3DSURFACE_DESC surface_description; 01763 01764 if (surface -> GetDesc (&surface_description) == D3D_OK) { 01765 IDirect3DSurface9 *current_render_target; 01766 01767 if (device -> GetRenderTarget (0, ¤t_render_target) == D3D_OK) { 01768 IDirect3DSurface9 *depth_stencil_surface; 01769 01770 // turn off depth stencil when clearing texture if it exists 01771 depth_stencil_surface = 0; 01772 if (device -> GetDepthStencilSurface (&depth_stencil_surface) == D3D_OK) { 01773 if (device -> SetDepthStencilSurface (NULL) == D3D_OK) { 01774 01775 } 01776 } 01777 01778 if (device -> SetRenderTarget (0, surface) == D3D_OK) { 01779 DWORD flags; 01780 D3DCOLOR color; 01781 01782 color = 0xFF000000; 01783 flags = D3DCLEAR_TARGET; 01784 if (device -> Clear (NULL, NULL, flags, color, 0.0f, 0) == D3D_OK) { 01785 } 01786 } 01787 01788 // restore depth stencil 01789 if (depth_stencil_surface) { 01790 device -> SetDepthStencilSurface (depth_stencil_surface); 01791 depth_stencil_surface -> Release(); 01792 } 01793 01794 // restore render target 01795 device -> SetRenderTarget (0, current_render_target); 01796 current_render_target -> Release(); 01797 } 01798 } 01799 01800 surface -> Release(); 01801 } 01802 } 01803 01804 return S_OK; 01805 } 01806 return E_FAIL; 01807 } 01808 nassertr(IS_VALID_PTR((BYTE*)image.p()), E_FAIL); 01809 nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL); 01810 01811 PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector); 01812 01813 DWORD orig_depth = (DWORD) tex->get_z_size(); 01814 D3DFORMAT source_format = _d3d_format; 01815 01816 // check for compressed textures and adjust source_format accordingly 01817 switch (image_compression) { 01818 case Texture::CM_dxt1: 01819 source_format = D3DFMT_DXT1; 01820 break; 01821 case Texture::CM_dxt2: 01822 source_format = D3DFMT_DXT2; 01823 break; 01824 case Texture::CM_dxt3: 01825 source_format = D3DFMT_DXT3; 01826 break; 01827 case Texture::CM_dxt4: 01828 source_format = D3DFMT_DXT4; 01829 break; 01830 case Texture::CM_dxt5: 01831 source_format = D3DFMT_DXT5; 01832 break; 01833 default: 01834 // no known compression format.. no adjustment 01835 break; 01836 } 01837 01838 for (unsigned int di = 0; di < orig_depth; di++) { 01839 01840 // fill top level mipmap 01841 hr = fill_d3d_texture_mipmap_pixels(0, di, source_format); 01842 if (FAILED(hr)) { 01843 return hr; // error message was already output in fill_d3d_texture_mipmap_pixels 01844 } 01845 01846 if (_has_mipmaps) { 01847 // if we have pre-calculated mipmap levels, use them, otherwise generate on the fly 01848 int miplevel_count = _d3d_texture->GetLevelCount(); 01849 if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) { 01850 dxgsg9_cat.debug() 01851 << "Using pre-calculated mipmap levels for texture " << tex->get_name() << "\n"; 01852 01853 for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) { 01854 hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format); 01855 if (FAILED(hr)) { 01856 return hr; // error message was already output in fill_d3d_texture_mipmap_pixels 01857 } 01858 } 01859 } 01860 else { 01861 // mipmaps need to be generated, either use autogen or d3dx functions 01862 01863 if (_managed == false && scrn._supports_automatic_mipmap_generation) { 01864 if (false) 01865 { 01866 //hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_PYRAMIDALQUAD); 01867 //hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_GAUSSIANQUAD); 01868 //hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_ANISOTROPIC); 01869 hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_LINEAR); 01870 if (FAILED(hr)) { 01871 dxgsg9_cat.error() << "SetAutoGenFilterType failed " << D3DERRORSTRING(hr); 01872 } 01873 01874 _d3d_texture -> GenerateMipSubLevels ( ); 01875 } 01876 } 01877 else { 01878 DWORD mip_filter_flags; 01879 if (!dx_use_triangle_mipgen_filter) { 01880 mip_filter_flags = D3DX_FILTER_BOX; 01881 } else { 01882 mip_filter_flags = D3DX_FILTER_TRIANGLE; 01883 } 01884 01885 // mip_filter_flags |= D3DX_FILTER_DITHER; 01886 hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0, 01887 mip_filter_flags); 01888 01889 if (FAILED(hr)) { 01890 dxgsg9_cat.error() 01891 << "FillDDSurfaceTexturePixels failed for " << tex->get_name() 01892 << ", D3DXFilterTex failed" << D3DERRORSTRING(hr); 01893 } 01894 } 01895 } 01896 } 01897 } 01898 01899 return hr; 01900 } 01901 01902 01903 //////////////////////////////////////////////////////////////////// 01904 // Function: DXTextureContext9::fill_d3d_volume_texture_pixels 01905 // Access: Private 01906 // Description: 01907 //////////////////////////////////////////////////////////////////// 01908 HRESULT DXTextureContext9:: 01909 fill_d3d_volume_texture_pixels(DXScreenData &scrn) { 01910 Texture *tex = get_texture(); 01911 HRESULT hr = E_FAIL; 01912 nassertr(IS_VALID_PTR(tex), E_FAIL); 01913 01914 CPTA_uchar image; 01915 if (scrn._dxgsg9->get_supports_compressed_texture()) { 01916 image = tex->get_ram_image(); 01917 } else { 01918 image = tex->get_uncompressed_ram_image(); 01919 } 01920 01921 Texture::CompressionMode image_compression; 01922 if (image.is_null()) { 01923 image_compression = Texture::CM_off; 01924 } else { 01925 image_compression = tex->get_ram_image_compression(); 01926 } 01927 01928 if (!scrn._dxgsg9->get_supports_compressed_texture_format(image_compression)) { 01929 image = tex->get_uncompressed_ram_image(); 01930 image_compression = Texture::CM_off; 01931 } 01932 01933 if (image.is_null()) { 01934 // The texture doesn't have an image to load. That's ok; it 01935 // might be a texture we've rendered to by frame buffer 01936 // operations or something. 01937 return S_OK; 01938 } 01939 01940 PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector); 01941 01942 nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL); 01943 nassertr(tex->get_texture_type() == Texture::TT_3d_texture, E_FAIL); 01944 01945 DWORD orig_width = (DWORD) tex->get_x_size(); 01946 DWORD orig_height = (DWORD) tex->get_y_size(); 01947 DWORD orig_depth = (DWORD) tex->get_z_size(); 01948 DWORD num_color_channels = tex->get_num_components(); 01949 D3DFORMAT source_format = _d3d_format; 01950 BYTE *image_pixels = (BYTE*)image.p(); 01951 int component_width = tex->get_component_width(); 01952 01953 nassertr(IS_VALID_PTR(image_pixels), E_FAIL); 01954 01955 size_t view_size = tex->get_ram_mipmap_view_size(0); 01956 image_pixels += view_size * get_view(); 01957 01958 IDirect3DVolume9 *mip_level_0 = NULL; 01959 bool using_temp_buffer = false; 01960 BYTE *pixels = image_pixels; 01961 01962 nassertr(IS_VALID_PTR(_d3d_volume_texture), E_FAIL); 01963 hr = _d3d_volume_texture->GetVolumeLevel(0, &mip_level_0); 01964 01965 if (FAILED(hr)) { 01966 dxgsg9_cat.error() 01967 << "FillDDSurfaceTexturePixels failed for " << tex->get_name() 01968 << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr); 01969 return E_FAIL; 01970 } 01971 01972 D3DBOX source_size; 01973 source_size.Left = source_size.Top = source_size.Front = 0; 01974 source_size.Right = orig_width; 01975 source_size.Bottom = orig_height; 01976 source_size.Back = orig_depth; 01977 01978 UINT source_row_byte_length = orig_width * num_color_channels; 01979 UINT source_page_byte_length = orig_height * source_row_byte_length; 01980 01981 DWORD level_0_filter, mip_filter_flags; 01982 using_temp_buffer = false; 01983 01984 // need filtering if size changes, (also if bitdepth reduced (need 01985 // dithering)??) 01986 level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures 01987 01988 // D3DXLoadSurfaceFromMemory will load black luminance and we want 01989 // full white, so convert to explicit luminance-alpha format 01990 if (_d3d_format == D3DFMT_A8) { 01991 // alloc buffer for explicit D3DFMT_A8L8 01992 USHORT *temp_buffer = new USHORT[orig_width * orig_height * orig_depth]; 01993 if (!IS_VALID_PTR(temp_buffer)) { 01994 dxgsg9_cat.error() 01995 << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; 01996 goto exit_FillDDSurf; 01997 } 01998 using_temp_buffer = true; 01999 02000 USHORT *out_pixels = temp_buffer; 02001 BYTE *source_pixels = pixels + component_width - 1; 02002 for (UINT z = 0; z < orig_depth; z++) { 02003 for (UINT y = 0; y < orig_height; y++) { 02004 for (UINT x = 0; 02005 x < orig_width; 02006 x++, source_pixels += component_width, out_pixels++) { 02007 // add full white, which is our interpretation of alpha-only 02008 // (similar to default adding full opaque alpha 0xFF to 02009 // RGB-only textures) 02010 *out_pixels = ((*source_pixels) << 8 ) | 0xFF; 02011 } 02012 } 02013 } 02014 02015 source_format = D3DFMT_A8L8; 02016 source_row_byte_length = orig_width * sizeof(USHORT); 02017 source_page_byte_length = orig_height * source_row_byte_length; 02018 pixels = (BYTE*)temp_buffer; 02019 02020 } else if (component_width != 1) { 02021 // Convert from 16-bit per channel (or larger) format down to 02022 // 8-bit per channel. This throws away precision in the 02023 // original image, but dx8 doesn't support high-precision images 02024 // anyway. 02025 02026 int num_components = tex->get_num_components(); 02027 int num_pixels = orig_width * orig_height * orig_depth * num_components; 02028 BYTE *temp_buffer = new BYTE[num_pixels]; 02029 if (!IS_VALID_PTR(temp_buffer)) { 02030 dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; 02031 goto exit_FillDDSurf; 02032 } 02033 using_temp_buffer = true; 02034 02035 BYTE *source_pixels = pixels + component_width - 1; 02036 for (int i = 0; i < num_pixels; i++) { 02037 temp_buffer[i] = *source_pixels; 02038 source_pixels += component_width; 02039 } 02040 pixels = (BYTE*)temp_buffer; 02041 } 02042 02043 02044 // filtering may be done here if texture if targetsize != origsize 02045 #ifdef DO_PSTATS 02046 GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_page_byte_length * orig_depth); 02047 #endif 02048 hr = D3DXLoadVolumeFromMemory 02049 (mip_level_0, (PALETTEENTRY*)NULL, (D3DBOX*)NULL, (LPCVOID)pixels, 02050 source_format, source_row_byte_length, source_page_byte_length, 02051 (PALETTEENTRY*)NULL, 02052 &source_size, level_0_filter, (D3DCOLOR)0x0); 02053 if (FAILED(hr)) { 02054 dxgsg9_cat.error() 02055 << "FillDDSurfaceTexturePixels failed for " << tex->get_name() 02056 << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr); 02057 goto exit_FillDDSurf; 02058 } 02059 02060 if (_has_mipmaps) { 02061 if (!dx_use_triangle_mipgen_filter) { 02062 mip_filter_flags = D3DX_FILTER_BOX; 02063 } else { 02064 mip_filter_flags = D3DX_FILTER_TRIANGLE; 02065 } 02066 02067 // mip_filter_flags| = D3DX_FILTER_DITHER; 02068 02069 hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0, 02070 mip_filter_flags); 02071 if (FAILED(hr)) { 02072 dxgsg9_cat.error() 02073 << "FillDDSurfaceTexturePixels failed for " << tex->get_name() 02074 << ", D3DXFilterTex failed" << D3DERRORSTRING(hr); 02075 goto exit_FillDDSurf; 02076 } 02077 } 02078 02079 exit_FillDDSurf: 02080 if (using_temp_buffer) { 02081 SAFE_DELETE_ARRAY(pixels); 02082 } 02083 RELEASE(mip_level_0, dxgsg9, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE); 02084 return hr; 02085 } 02086 02087 02088 //////////////////////////////////////////////////////////////////// 02089 // Function: DXTextureContext9::down_to_power_2 02090 // Access: Private, Static 02091 // Description: Returns the largest power of 2 less than or equal 02092 // to value. 02093 //////////////////////////////////////////////////////////////////// 02094 int DXTextureContext9:: 02095 down_to_power_2(int value) { 02096 int x = 1; 02097 while ((x << 1) <= value) { 02098 x = (x << 1); 02099 } 02100 return x; 02101 } 02102 02103 //////////////////////////////////////////////////////////////////// 02104 // Function: DXTextureContext9::get_bits_per_pixel 02105 // Access: Private 02106 // Description: Maps from the Texture's Format symbols to bpp. 02107 // Returns # of alpha bits. Note: Texture's format 02108 // indicates REQUESTED final format, not the stored 02109 // format, which is indicated by pixelbuffer type 02110 //////////////////////////////////////////////////////////////////// 02111 unsigned int DXTextureContext9:: 02112 get_bits_per_pixel(Texture::Format format, int *alphbits) { 02113 *alphbits = 0; // assume no alpha bits 02114 switch(format) { 02115 case Texture::F_alpha: 02116 *alphbits = 8; 02117 case Texture::F_color_index: 02118 case Texture::F_red: 02119 case Texture::F_green: 02120 case Texture::F_blue: 02121 case Texture::F_rgb332: 02122 return 8; 02123 case Texture::F_luminance_alphamask: 02124 *alphbits = 1; 02125 return 16; 02126 case Texture::F_luminance_alpha: 02127 *alphbits = 8; 02128 return 16; 02129 case Texture::F_luminance: 02130 return 8; 02131 case Texture::F_rgba4: 02132 *alphbits = 4; 02133 return 16; 02134 case Texture::F_rgba5: 02135 *alphbits = 1; 02136 return 16; 02137 case Texture::F_depth_component: 02138 return 16; 02139 case Texture::F_depth_stencil: 02140 return 32; 02141 case Texture::F_rgb5: 02142 return 16; 02143 case Texture::F_rgb8: 02144 case Texture::F_rgb: 02145 return 24; 02146 case Texture::F_rgba8: 02147 case Texture::F_rgba: 02148 *alphbits = 8; 02149 return 32; 02150 case Texture::F_rgbm: 02151 *alphbits = 1; 02152 return 32; 02153 case Texture::F_rgb12: 02154 return 36; 02155 case Texture::F_rgba12: 02156 *alphbits = 12; 02157 return 48; 02158 case Texture::F_rgba16: 02159 *alphbits = 16; 02160 return 64; 02161 case Texture::F_rgba32: 02162 *alphbits = 32; 02163 return 128; 02164 } 02165 return 8; 02166 } 02167 02168 //////////////////////////////////////////////////////////////////// 02169 // Function: DXTextureContext9::d3d_format_to_bytes_per_pixel 02170 // Access: Private 02171 // Description: Determines bytes per pixel from D3DFORMAT. 02172 //////////////////////////////////////////////////////////////////// 02173 PN_stdfloat DXTextureContext9:: 02174 d3d_format_to_bytes_per_pixel (D3DFORMAT format) 02175 { 02176 PN_stdfloat bytes_per_pixel; 02177 02178 bytes_per_pixel = 0.0f; 02179 switch (format) 02180 { 02181 case D3DFMT_R3G3B2: 02182 case D3DFMT_A8: 02183 case D3DFMT_A8P8: 02184 case D3DFMT_P8: 02185 case D3DFMT_L8: 02186 case D3DFMT_A4L4: 02187 bytes_per_pixel = 1.0f; 02188 break; 02189 02190 case D3DFMT_R16F: 02191 case D3DFMT_CxV8U8: 02192 case D3DFMT_V8U8: 02193 case D3DFMT_R5G6B5: 02194 case D3DFMT_X1R5G5B5: 02195 case D3DFMT_A1R5G5B5: 02196 case D3DFMT_A4R4G4B4: 02197 case D3DFMT_L16: 02198 case D3DFMT_A8L8: 02199 case D3DFMT_A8R3G3B2: 02200 case D3DFMT_X4R4G4B4: 02201 bytes_per_pixel = 2.0f; 02202 break; 02203 02204 case D3DFMT_R8G8B8: 02205 bytes_per_pixel = 3.0f; 02206 break; 02207 02208 case D3DFMT_G16R16F: 02209 case D3DFMT_Q8W8V8U8: 02210 case D3DFMT_V16U16: 02211 case D3DFMT_R32F: 02212 case D3DFMT_A8R8G8B8: 02213 case D3DFMT_X8R8G8B8: 02214 case D3DFMT_A2B10G10R10: 02215 case D3DFMT_A8B8G8R8: 02216 case D3DFMT_X8B8G8R8: 02217 case D3DFMT_G16R16: 02218 case D3DFMT_A2R10G10B10: 02219 bytes_per_pixel = 4.0f; 02220 break; 02221 02222 case D3DFMT_G32R32F: 02223 case D3DFMT_A16B16G16R16F: 02224 case D3DFMT_Q16W16V16U16: 02225 case D3DFMT_A16B16G16R16: 02226 bytes_per_pixel = 8.0f; 02227 break; 02228 02229 case D3DFMT_A32B32G32R32F: 02230 bytes_per_pixel = 16.0f; 02231 break; 02232 02233 case D3DFMT_DXT1: 02234 bytes_per_pixel = 0.5f; 02235 break; 02236 case D3DFMT_DXT2: 02237 case D3DFMT_DXT3: 02238 case D3DFMT_DXT4: 02239 case D3DFMT_DXT5: 02240 bytes_per_pixel = 1.0f; 02241 break; 02242 } 02243 02244 return bytes_per_pixel; 02245 }