Panda3D

dxTextureContext9.cxx

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, &current_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 }
 All Classes Functions Variables Enumerations