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) :
00039   TextureContext(pgo, tex) {
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_rgba32f_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   float 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) ((float) data_size * 1.3333333f);
00843   }
00844   data_size = (int) ((float) 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   pixels += depth_index * get_texture()->get_expected_ram_mipmap_page_size(mip_level);
01611   
01612   if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
01613     nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
01614     hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)depth_index, mip_level, &mip_surface);
01615   } else {
01616     nassertr(IS_VALID_PTR(_d3d_2d_texture), E_FAIL);
01617     hr = _d3d_2d_texture->GetSurfaceLevel(mip_level, &mip_surface);
01618   }
01619 
01620   if (FAILED(hr)) {
01621     dxgsg9_cat.error()
01622       << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
01623       << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
01624     return E_FAIL;
01625   }
01626 
01627   RECT source_size;
01628   source_size.left = source_size.top = 0;
01629   source_size.right = width;
01630   source_size.bottom = height;
01631 
01632   UINT source_row_byte_length = calculate_row_byte_length(width, get_texture()->get_num_components(), source_format);
01633 
01634   DWORD mip_filter;
01635   // need filtering if size changes, (also if bitdepth reduced (need
01636   // dithering)??)
01637   mip_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
01638 
01639   // D3DXLoadSurfaceFromMemory will load black luminance and we want
01640   // full white, so convert to explicit luminance-alpha format
01641   if (_d3d_format == D3DFMT_A8) {
01642     // alloc buffer for explicit D3DFMT_A8L8
01643     USHORT *temp_buffer = new USHORT[width * height];
01644     if (!IS_VALID_PTR(temp_buffer)) {
01645       dxgsg9_cat.error()
01646         << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
01647       goto exit_FillMipmapSurf;
01648     }
01649     using_temp_buffer = true;
01650 
01651     USHORT *out_pixels = temp_buffer;
01652     BYTE *source_pixels = pixels + component_width - 1;
01653     for (UINT y = 0; y < height; y++) {
01654       for (UINT x = 0; x < width; x++, source_pixels += component_width, out_pixels++) {
01655         // add full white, which is our interpretation of alpha-only
01656         // (similar to default adding full opaque alpha 0xFF to
01657         // RGB-only textures)
01658         *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
01659       }
01660     }
01661 
01662     source_format = D3DFMT_A8L8;
01663     source_row_byte_length = width * sizeof(USHORT);
01664     pixels = (BYTE*)temp_buffer;
01665   } 
01666   else if (component_width != 1) {
01667     // Convert from 16-bit per channel (or larger) format down to
01668     // 8-bit per channel.  This throws away precision in the
01669     // original image, but dx8 doesn't support high-precision images
01670     // anyway.
01671 
01672     int num_components = get_texture()->get_num_components();
01673     int num_pixels = width * height * num_components;
01674     BYTE *temp_buffer = new BYTE[num_pixels];
01675     if (!IS_VALID_PTR(temp_buffer)) {
01676       dxgsg9_cat.error() << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
01677       goto exit_FillMipmapSurf;
01678     }
01679     using_temp_buffer = true;
01680 
01681     BYTE *source_pixels = pixels + component_width - 1;
01682     for (int i = 0; i < num_pixels; i++) {
01683       temp_buffer[i] = *source_pixels;
01684       source_pixels += component_width;
01685     }
01686     pixels = (BYTE*)temp_buffer;
01687   }
01688 
01689   // filtering may be done here if texture if targetsize != origsize
01690 #ifdef DO_PSTATS
01691   GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * height);
01692 #endif
01693   hr = D3DXLoadSurfaceFromMemory
01694     (mip_surface, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)pixels,
01695       source_format, source_row_byte_length, (PALETTEENTRY*)NULL,
01696       &source_size, mip_filter, (D3DCOLOR)0x0);
01697   if (FAILED(hr)) {
01698     dxgsg9_cat.error()
01699       << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
01700       << ", mip_level " << mip_level
01701       << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
01702   }
01703 
01704 exit_FillMipmapSurf:
01705   if (using_temp_buffer) {
01706     SAFE_DELETE_ARRAY(pixels);
01707   }
01708 
01709   RELEASE(mip_surface, dxgsg9, "FillDDTextureMipmapPixels MipSurface texture ptr", RELEASE_ONCE);
01710   return hr;
01711 }
01712 
01713 ////////////////////////////////////////////////////////////////////
01714 //     Function: DXTextureContext9::fill_d3d_texture_pixels
01715 //       Access: Private
01716 //  Description:
01717 ////////////////////////////////////////////////////////////////////
01718 HRESULT DXTextureContext9::
01719 fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
01720   IDirect3DDevice9 *device = scrn._d3d_device;
01721   Texture *tex = get_texture();
01722   nassertr(IS_VALID_PTR(tex), E_FAIL);
01723   if (tex->get_texture_type() == Texture::TT_3d_texture) {
01724     return fill_d3d_volume_texture_pixels(scrn);
01725   }
01726 
01727   HRESULT hr = E_FAIL;
01728 
01729   CPTA_uchar image;
01730   Texture::CompressionMode image_compression = Texture::CM_off;
01731   if (compress_texture) {
01732     // If we are to be compressing this texture, accept a
01733     // pre-compressed ram image if it is already so.
01734     image = tex->get_ram_image();
01735     if (!image.is_null()) {
01736       image_compression = tex->get_ram_image_compression();
01737     }
01738   } else {
01739     // If we are not to be compressing this texture, we can only
01740     // accept an uncompressed ram image.  Ask the texture to give us
01741     // one, so that there's no danger of accidentally getting a
01742     // pre-compressed image.
01743     image = tex->get_uncompressed_ram_image();
01744   }
01745 
01746   if (image.is_null()) {
01747     // The texture doesn't have an image to load.  That's ok; it
01748     // might be a texture we've rendered to by frame buffer
01749     // operations or something.
01750     if (tex->get_render_to_texture()) {   
01751       HRESULT result;
01752 
01753       if (_d3d_2d_texture) {
01754         // clear render to texture
01755         IDirect3DSurface9 *surface;
01756 
01757         result = _d3d_2d_texture -> GetSurfaceLevel (0, &surface);
01758         if (result == D3D_OK) {
01759           D3DSURFACE_DESC surface_description;
01760 
01761           if (surface -> GetDesc (&surface_description) == D3D_OK) {
01762             IDirect3DSurface9 *current_render_target;
01763 
01764             if (device -> GetRenderTarget (0, &current_render_target) == D3D_OK) {
01765               IDirect3DSurface9 *depth_stencil_surface;
01766 
01767               // turn off depth stencil when clearing texture if it exists
01768               depth_stencil_surface = 0;
01769               if (device -> GetDepthStencilSurface (&depth_stencil_surface) == D3D_OK) {
01770                 if (device -> SetDepthStencilSurface (NULL) == D3D_OK) {
01771       
01772                 }
01773               }
01774 
01775               if (device -> SetRenderTarget (0, surface)  == D3D_OK) {
01776                 DWORD flags;
01777                 D3DCOLOR color;
01778 
01779                 color = 0xFF000000;
01780                 flags = D3DCLEAR_TARGET;
01781                 if (device -> Clear (NULL, NULL, flags, color, 0.0f, 0) == D3D_OK) {
01782                 }
01783               }
01784 
01785               // restore depth stencil 
01786               if (depth_stencil_surface) {
01787                 device -> SetDepthStencilSurface (depth_stencil_surface);
01788                 depth_stencil_surface -> Release();
01789               }
01790 
01791               // restore render target
01792               device -> SetRenderTarget (0, current_render_target);
01793               current_render_target -> Release();
01794             }
01795           }
01796 
01797           surface -> Release();
01798         }
01799       }
01800       
01801       return S_OK;
01802     }
01803     return E_FAIL;
01804   }
01805   nassertr(IS_VALID_PTR((BYTE*)image.p()), E_FAIL);
01806   nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
01807 
01808   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
01809 
01810   DWORD orig_depth = (DWORD) tex->get_z_size();
01811   D3DFORMAT source_format = _d3d_format;
01812 
01813   // check for compressed textures and adjust source_format accordingly
01814   switch (image_compression) {
01815   case Texture::CM_dxt1:
01816     source_format = D3DFMT_DXT1;
01817     break;
01818   case Texture::CM_dxt2:
01819     source_format = D3DFMT_DXT2;
01820     break;
01821   case Texture::CM_dxt3:
01822     source_format = D3DFMT_DXT3;
01823     break;
01824   case Texture::CM_dxt4:
01825     source_format = D3DFMT_DXT4;
01826     break;
01827   case Texture::CM_dxt5:
01828     source_format = D3DFMT_DXT5;
01829     break;
01830   default:
01831     // no known compression format.. no adjustment
01832     break;
01833   }
01834 
01835   for (unsigned int di = 0; di < orig_depth; di++) {
01836     
01837     // fill top level mipmap
01838     hr = fill_d3d_texture_mipmap_pixels(0, di, source_format);
01839     if (FAILED(hr)) {
01840       return hr; // error message was already output in fill_d3d_texture_mipmap_pixels
01841     }
01842 
01843     if (_has_mipmaps) {
01844       // if we have pre-calculated mipmap levels, use them, otherwise generate on the fly
01845       int miplevel_count = _d3d_2d_texture->GetLevelCount(); // what if it's not a 2d texture?
01846       if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
01847         dxgsg9_cat.debug()
01848           << "Using pre-calculated mipmap levels for texture  " << tex->get_name() << "\n";
01849 
01850         for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) {
01851           hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
01852           if (FAILED(hr)) {
01853             return hr; // error message was already output in fill_d3d_texture_mipmap_pixels
01854           }
01855         }        
01856       } 
01857       else {
01858         // mipmaps need to be generated, either use autogen or d3dx functions
01859 
01860         if (_managed == false && scrn._supports_automatic_mipmap_generation) {
01861           if (false)
01862           {
01863             //hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_PYRAMIDALQUAD);
01864             //hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_GAUSSIANQUAD);
01865             //hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_ANISOTROPIC);
01866             hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_LINEAR);
01867             if (FAILED(hr)) {
01868               dxgsg9_cat.error() << "SetAutoGenFilterType failed " << D3DERRORSTRING(hr);
01869             }
01870 
01871             _d3d_texture -> GenerateMipSubLevels ( );
01872           }
01873         }
01874         else {
01875           DWORD mip_filter_flags;
01876           if (!dx_use_triangle_mipgen_filter) {
01877             mip_filter_flags = D3DX_FILTER_BOX;
01878           } else {
01879             mip_filter_flags = D3DX_FILTER_TRIANGLE;
01880           }
01881 
01882           // mip_filter_flags |= D3DX_FILTER_DITHER;
01883           hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0,
01884                                 mip_filter_flags);
01885 
01886           if (FAILED(hr)) {
01887             dxgsg9_cat.error()
01888               << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
01889               << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
01890           }
01891         }
01892       }
01893     }
01894   }
01895 
01896   return hr;
01897 }
01898 
01899 
01900 ////////////////////////////////////////////////////////////////////
01901 //     Function: DXTextureContext9::fill_d3d_volume_texture_pixels
01902 //       Access: Private
01903 //  Description:
01904 ////////////////////////////////////////////////////////////////////
01905 HRESULT DXTextureContext9::
01906 fill_d3d_volume_texture_pixels(DXScreenData &scrn) {
01907   Texture *tex = get_texture();
01908   HRESULT hr = E_FAIL;
01909   nassertr(IS_VALID_PTR(tex), E_FAIL);
01910 
01911   CPTA_uchar image;
01912   if (scrn._dxgsg9->get_supports_compressed_texture()) {
01913     image = tex->get_ram_image();
01914   } else {
01915     image = tex->get_uncompressed_ram_image();
01916   }
01917 
01918   Texture::CompressionMode image_compression;
01919   if (image.is_null()) {
01920     image_compression = Texture::CM_off;
01921   } else {
01922     image_compression = tex->get_ram_image_compression();
01923   }
01924 
01925   if (!scrn._dxgsg9->get_supports_compressed_texture_format(image_compression)) {
01926     image = tex->get_uncompressed_ram_image();
01927     image_compression = Texture::CM_off;
01928   }    
01929 
01930   if (image.is_null()) {
01931     // The texture doesn't have an image to load.  That's ok; it
01932     // might be a texture we've rendered to by frame buffer
01933     // operations or something.
01934     return S_OK;
01935   }
01936 
01937   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
01938 
01939   nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
01940   nassertr(tex->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
01941 
01942   DWORD orig_width  = (DWORD) tex->get_x_size();
01943   DWORD orig_height = (DWORD) tex->get_y_size();
01944   DWORD orig_depth = (DWORD) tex->get_z_size();
01945   DWORD num_color_channels = tex->get_num_components();
01946   D3DFORMAT source_format = _d3d_format;
01947   BYTE *image_pixels = (BYTE*)image.p();
01948   int component_width = tex->get_component_width();
01949 
01950   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
01951 
01952   IDirect3DVolume9 *mip_level_0 = NULL;
01953   bool using_temp_buffer = false;
01954   BYTE *pixels = image_pixels;
01955 
01956   nassertr(IS_VALID_PTR(_d3d_volume_texture), E_FAIL);
01957   hr = _d3d_volume_texture->GetVolumeLevel(0, &mip_level_0);
01958 
01959   if (FAILED(hr)) {
01960     dxgsg9_cat.error()
01961       << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
01962       << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
01963     return E_FAIL;
01964   }
01965 
01966   D3DBOX source_size;
01967   source_size.Left = source_size.Top = source_size.Front = 0;
01968   source_size.Right = orig_width;
01969   source_size.Bottom = orig_height;
01970   source_size.Back = orig_depth;
01971 
01972   UINT source_row_byte_length = orig_width * num_color_channels;
01973   UINT source_page_byte_length = orig_height * source_row_byte_length;
01974 
01975   DWORD level_0_filter, mip_filter_flags;
01976   using_temp_buffer = false;
01977 
01978   // need filtering if size changes, (also if bitdepth reduced (need
01979   // dithering)??)
01980   level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
01981 
01982   // D3DXLoadSurfaceFromMemory will load black luminance and we want
01983   // full white, so convert to explicit luminance-alpha format
01984   if (_d3d_format == D3DFMT_A8) {
01985     // alloc buffer for explicit D3DFMT_A8L8
01986     USHORT *temp_buffer = new USHORT[orig_width * orig_height * orig_depth];
01987     if (!IS_VALID_PTR(temp_buffer)) {
01988       dxgsg9_cat.error()
01989         << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
01990       goto exit_FillDDSurf;
01991     }
01992     using_temp_buffer = true;
01993 
01994     USHORT *out_pixels = temp_buffer;
01995     BYTE *source_pixels = pixels + component_width - 1;
01996     for (UINT z = 0; z < orig_depth; z++) {
01997       for (UINT y = 0; y < orig_height; y++) {
01998         for (UINT x = 0;
01999              x < orig_width;
02000              x++, source_pixels += component_width, out_pixels++) {
02001           // add full white, which is our interpretation of alpha-only
02002           // (similar to default adding full opaque alpha 0xFF to
02003           // RGB-only textures)
02004           *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
02005         }
02006       }
02007     }
02008 
02009     source_format = D3DFMT_A8L8;
02010     source_row_byte_length = orig_width * sizeof(USHORT);
02011     source_page_byte_length = orig_height * source_row_byte_length;
02012     pixels = (BYTE*)temp_buffer;
02013 
02014   } else if (component_width != 1) {
02015     // Convert from 16-bit per channel (or larger) format down to
02016     // 8-bit per channel.  This throws away precision in the
02017     // original image, but dx8 doesn't support high-precision images
02018     // anyway.
02019 
02020     int num_components = tex->get_num_components();
02021     int num_pixels = orig_width * orig_height * orig_depth * num_components;
02022     BYTE *temp_buffer = new BYTE[num_pixels];
02023     if (!IS_VALID_PTR(temp_buffer)) {
02024       dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
02025       goto exit_FillDDSurf;
02026     }
02027     using_temp_buffer = true;
02028 
02029     BYTE *source_pixels = pixels + component_width - 1;
02030     for (int i = 0; i < num_pixels; i++) {
02031       temp_buffer[i] = *source_pixels;
02032       source_pixels += component_width;
02033     }
02034     pixels = (BYTE*)temp_buffer;
02035   }
02036 
02037 
02038   // filtering may be done here if texture if targetsize != origsize
02039 #ifdef DO_PSTATS
02040   GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_page_byte_length * orig_depth);
02041 #endif
02042   hr = D3DXLoadVolumeFromMemory
02043     (mip_level_0, (PALETTEENTRY*)NULL, (D3DBOX*)NULL, (LPCVOID)pixels,
02044      source_format, source_row_byte_length, source_page_byte_length,
02045      (PALETTEENTRY*)NULL,
02046      &source_size, level_0_filter, (D3DCOLOR)0x0);
02047   if (FAILED(hr)) {
02048     dxgsg9_cat.error()
02049       << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
02050       << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
02051     goto exit_FillDDSurf;
02052   }
02053 
02054   if (_has_mipmaps) {
02055     if (!dx_use_triangle_mipgen_filter) {
02056       mip_filter_flags = D3DX_FILTER_BOX;
02057     } else {
02058       mip_filter_flags = D3DX_FILTER_TRIANGLE;
02059     }
02060 
02061     //    mip_filter_flags| = D3DX_FILTER_DITHER;
02062 
02063     hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0,
02064                            mip_filter_flags);
02065     if (FAILED(hr)) {
02066       dxgsg9_cat.error()
02067         << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
02068         << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
02069       goto exit_FillDDSurf;
02070     }
02071   }
02072 
02073  exit_FillDDSurf:
02074   if (using_temp_buffer) {
02075     SAFE_DELETE_ARRAY(pixels);
02076   }
02077   RELEASE(mip_level_0, dxgsg9, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE);
02078   return hr;
02079 }
02080 
02081 
02082 ////////////////////////////////////////////////////////////////////
02083 //     Function: DXTextureContext9::down_to_power_2
02084 //       Access: Private, Static
02085 //  Description: Returns the largest power of 2 less than or equal
02086 //               to value.
02087 ////////////////////////////////////////////////////////////////////
02088 int DXTextureContext9::
02089 down_to_power_2(int value) {
02090   int x = 1;
02091   while ((x << 1) <= value) {
02092     x = (x << 1);
02093   }
02094   return x;
02095 }
02096 
02097 ////////////////////////////////////////////////////////////////////
02098 //     Function: DXTextureContext9::get_bits_per_pixel
02099 //       Access: Private
02100 //  Description: Maps from the Texture's Format symbols to bpp.
02101 //               Returns # of alpha bits.  Note: Texture's format
02102 //               indicates REQUESTED final format, not the stored
02103 //               format, which is indicated by pixelbuffer type
02104 ////////////////////////////////////////////////////////////////////
02105 unsigned int DXTextureContext9::
02106 get_bits_per_pixel(Texture::Format format, int *alphbits) {
02107   *alphbits = 0;      // assume no alpha bits
02108   switch(format) {
02109   case Texture::F_alpha:
02110     *alphbits = 8;
02111   case Texture::F_color_index:
02112   case Texture::F_red:
02113   case Texture::F_green:
02114   case Texture::F_blue:
02115   case Texture::F_rgb332:
02116     return 8;
02117   case Texture::F_luminance_alphamask:
02118     *alphbits = 1;
02119     return 16;
02120   case Texture::F_luminance_alpha:
02121     *alphbits = 8;
02122     return 16;
02123   case Texture::F_luminance:
02124     return 8;
02125   case Texture::F_rgba4:
02126     *alphbits = 4;
02127     return 16;
02128   case Texture::F_rgba5:
02129     *alphbits = 1;
02130     return 16;
02131   case Texture::F_depth_component:
02132     return 16;
02133   case Texture::F_depth_stencil:
02134     return 32;
02135   case Texture::F_rgb5:
02136     return 16;
02137   case Texture::F_rgb8:
02138   case Texture::F_rgb:
02139     return 24;
02140   case Texture::F_rgba8:
02141   case Texture::F_rgba:
02142     *alphbits = 8;
02143     return 32;
02144   case Texture::F_rgbm:
02145     *alphbits = 1;
02146     return 32;
02147   case Texture::F_rgb12:
02148     return 36;
02149   case Texture::F_rgba12:
02150     *alphbits = 12;
02151     return 48;
02152   case Texture::F_rgba16:
02153     *alphbits = 16;
02154     return 64;
02155   case Texture::F_rgba32:
02156     *alphbits = 32;
02157     return 128;
02158   }
02159   return 8;
02160 }
02161 
02162 ////////////////////////////////////////////////////////////////////
02163 //     Function: DXTextureContext9::d3d_format_to_bytes_per_pixel
02164 //       Access: Private
02165 //  Description: Determines bytes per pixel from D3DFORMAT.
02166 ////////////////////////////////////////////////////////////////////
02167 float DXTextureContext9::
02168 d3d_format_to_bytes_per_pixel (D3DFORMAT format)
02169 {
02170   float bytes_per_pixel;
02171   
02172   bytes_per_pixel = 0.0f;
02173   switch (format)
02174   {
02175     case D3DFMT_R3G3B2:
02176     case D3DFMT_A8:
02177     case D3DFMT_A8P8:
02178     case D3DFMT_P8:
02179     case D3DFMT_L8:
02180     case D3DFMT_A4L4:
02181       bytes_per_pixel = 1.0f;
02182       break;
02183 
02184     case D3DFMT_R16F:
02185     case D3DFMT_CxV8U8:
02186     case D3DFMT_V8U8:
02187     case D3DFMT_R5G6B5:
02188     case D3DFMT_X1R5G5B5:
02189     case D3DFMT_A1R5G5B5:
02190     case D3DFMT_A4R4G4B4:
02191     case D3DFMT_L16:
02192     case D3DFMT_A8L8:
02193     case D3DFMT_A8R3G3B2:
02194     case D3DFMT_X4R4G4B4:
02195       bytes_per_pixel = 2.0f;
02196       break;
02197 
02198     case D3DFMT_R8G8B8:
02199       bytes_per_pixel = 3.0f;
02200       break;
02201 
02202     case D3DFMT_G16R16F:
02203     case D3DFMT_Q8W8V8U8:
02204     case D3DFMT_V16U16:
02205     case D3DFMT_R32F:
02206     case D3DFMT_A8R8G8B8:
02207     case D3DFMT_X8R8G8B8:
02208     case D3DFMT_A2B10G10R10:
02209     case D3DFMT_A8B8G8R8:
02210     case D3DFMT_X8B8G8R8:
02211     case D3DFMT_G16R16:
02212     case D3DFMT_A2R10G10B10:
02213       bytes_per_pixel = 4.0f;
02214       break;
02215 
02216     case D3DFMT_G32R32F:
02217     case D3DFMT_A16B16G16R16F:
02218     case D3DFMT_Q16W16V16U16:
02219     case D3DFMT_A16B16G16R16:
02220       bytes_per_pixel = 8.0f;
02221       break;
02222 
02223     case D3DFMT_A32B32G32R32F:
02224       bytes_per_pixel = 16.0f;
02225       break;
02226 
02227     case D3DFMT_DXT1:
02228       bytes_per_pixel = 0.5f;
02229       break;
02230     case D3DFMT_DXT2:
02231     case D3DFMT_DXT3:
02232     case D3DFMT_DXT4:
02233     case D3DFMT_DXT5:
02234       bytes_per_pixel = 1.0f;
02235       break;
02236   }
02237   
02238   return bytes_per_pixel;
02239 }
 All Classes Functions Variables Enumerations