Browse Source

directx extract_texture_data

David Rose 17 years ago
parent
commit
4074c2717a

+ 21 - 0
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -304,6 +304,27 @@ release_texture(TextureContext *tc) {
   delete dtc;
   delete dtc;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian8::extract_texture_data
+//       Access: Public, Virtual
+//  Description: This method should only be called by the
+//               GraphicsEngine.  Do not call it directly; call
+//               GraphicsEngine::extract_texture_data() instead.
+//
+//               This method will be called in the draw thread to
+//               download the texture memory's image into its
+//               ram_image value.  It returns true on success, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool DXGraphicsStateGuardian8::
+extract_texture_data(Texture *tex) {
+  TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
+  nassertr(tc != (TextureContext *)NULL, false);
+  DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
+
+  return dtc->extract_texture_data();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::prepare_vertex_buffer
 //     Function: DXGraphicsStateGuardian8::prepare_vertex_buffer
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 1 - 0
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -52,6 +52,7 @@ public:
   void apply_texture(int i, TextureContext *tc);
   void apply_texture(int i, TextureContext *tc);
   bool upload_texture(DXTextureContext8 *dtc);
   bool upload_texture(DXTextureContext8 *dtc);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
+  virtual bool extract_texture_data(Texture *tex);
 
 
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
   bool apply_vertex_buffer(VertexBufferContext *vbc,
   bool apply_vertex_buffer(VertexBufferContext *vbc,

+ 151 - 15
panda/src/dxgsg8/dxTextureContext8.cxx

@@ -17,6 +17,7 @@
 #include "dxGraphicsStateGuardian8.h"
 #include "dxGraphicsStateGuardian8.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
 #include "dxgsg8base.h"
 #include "dxgsg8base.h"
+#include "bamCache.h"
 
 
 #include <assert.h>
 #include <assert.h>
 #include <time.h>
 #include <time.h>
@@ -684,13 +685,17 @@ create_texture(DXScreenData &scrn) {
   UINT mip_level_count;
   UINT mip_level_count;
 
 
   if (_has_mipmaps) {
   if (_has_mipmaps) {
-    // tell CreateTex to alloc space for all mip levels down to 1x1
-    mip_level_count = 0;
+    tex->get_ram_image();
+    mip_level_count = tex->get_num_loadable_ram_mipmap_images();
+    if (mip_level_count < 2) {
+      // tell CreateTex to alloc space for all mip levels down to 1x1
+      mip_level_count = 0;
 
 
-    if (dxgsg8_cat.is_debug()) {
-      dxgsg8_cat.debug()
-        << "create_texture: generating mipmaps for " << tex->get_name()
-        << endl;
+      if (dxgsg8_cat.is_debug()) {
+        dxgsg8_cat.debug()
+          << "create_texture: generating mipmaps for " << tex->get_name()
+          << endl;
+      }
     }
     }
   } else {
   } else {
     mip_level_count = 1;
     mip_level_count = 1;
@@ -752,6 +757,21 @@ create_texture(DXScreenData &scrn) {
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     goto error_exit;
     goto error_exit;
   }
   }
+  
+  if (tex->get_post_load_store_cache()) {
+    tex->set_post_load_store_cache(false);
+    // OK, get the RAM image, and save it in a BamCache record.
+    if (extract_texture_data()) {
+      if (tex->has_ram_image()) {
+        BamCache *cache = BamCache::get_global_ptr();
+        PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo");
+        if (record != (BamCacheRecord *)NULL) {
+          record->set_data(tex, false);
+          cache->store(record);
+        }
+      }
+    }
+  }
 
 
   tex->texture_uploaded(scrn._dxgsg8);
   tex->texture_uploaded(scrn._dxgsg8);
   mark_loaded();
   mark_loaded();
@@ -873,6 +893,119 @@ delete_texture() {
   _d3d_cube_texture = NULL;
   _d3d_cube_texture = NULL;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXTextureContext8::extract_texture_data
+//       Access: Public
+//  Description: This method will be called in the draw thread to
+//               download the texture memory's image into its
+//               ram_image value.  It returns true on success, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool DXTextureContext8::
+extract_texture_data() {
+  HRESULT hr;
+
+  Texture *tex = get_texture();
+  if (tex->get_texture_type() != Texture::TT_2d_texture) {
+    dxgsg8_cat.error()
+      << "Not supported: extract_texture_data for " << tex->get_texture_type()
+      << "\n";
+    return false;
+  }
+  nassertr(IS_VALID_PTR(_d3d_2d_texture), false);
+
+  D3DSURFACE_DESC desc;
+  hr = _d3d_2d_texture->GetLevelDesc(0, &desc);
+  if (FAILED(hr)) {
+    dxgsg8_cat.error()
+      << "Texture::GetLevelDesc() failed!" << D3DERRORSTRING(hr);
+    return false;
+  }
+
+  int div = 1;
+  Texture::Format format = Texture::F_rgba;
+  Texture::CompressionMode compression = Texture::CM_off;
+
+  switch (desc.Format) {
+  case D3DFMT_R8G8B8:
+    format = Texture::F_rgb;
+    break;
+
+  case D3DFMT_A8R8G8B8:
+  case D3DFMT_X8R8G8B8:
+    break;
+
+  case D3DFMT_L8:
+    format = Texture::F_luminance;
+    break;
+
+  case D3DFMT_A8L8:
+    format = Texture::F_luminance_alpha;
+    break;
+
+  case D3DFMT_DXT1:
+    compression = Texture::CM_dxt1;
+    div = 4;
+    break;
+  case D3DFMT_DXT2:
+    compression = Texture::CM_dxt2;
+    div = 4;
+    break;
+  case D3DFMT_DXT3:
+    compression = Texture::CM_dxt3;
+    div = 4;
+    break;
+  case D3DFMT_DXT4:
+    compression = Texture::CM_dxt4;
+    div = 4;
+    break;
+  case D3DFMT_DXT5:
+    compression = Texture::CM_dxt5;
+    div = 4;
+    break;
+
+  default:
+    dxgsg8_cat.error()
+      << "Cannot extract texture data: unhandled surface format " 
+      << desc.Format << "\n";
+    return false;
+  }
+
+  int num_levels = _d3d_2d_texture->GetLevelCount();
+
+  tex->set_x_size(desc.Width);
+  tex->set_y_size(desc.Height);
+  tex->set_z_size(1);
+  tex->set_component_type(Texture::T_unsigned_byte);
+  tex->set_format(format);
+  tex->clear_ram_image();
+
+  for (int n = 0; n < num_levels; ++n) {
+    D3DLOCKED_RECT rect;
+    hr = _d3d_2d_texture->LockRect(n, &rect, NULL, D3DLOCK_READONLY);
+    if (FAILED(hr)) {
+      dxgsg8_cat.error()
+        << "Texture::LockRect() failed!" << D3DERRORSTRING(hr);
+      return false;
+    }
+    
+    int y_size = tex->get_expected_mipmap_y_size(n);
+    int size = rect.Pitch * (y_size / div);
+    size = min(size, (int)tex->get_expected_ram_mipmap_image_size(n));
+    PTA_uchar image = PTA_uchar::empty_array(size);
+    memcpy(image.p(), rect.pBits, size);
+    
+    _d3d_2d_texture->UnlockRect(n);
+    if (n == 0) {
+      tex->set_ram_image(image, compression);
+    } else {
+      tex->set_ram_mipmap_image(n, image);
+    }
+  }
+    
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXTextureContext8::d3d_surface_to_texture
 //     Function: DXTextureContext8::d3d_surface_to_texture
 //       Access: Public, Static
 //       Access: Public, Static
@@ -1181,6 +1314,7 @@ HRESULT DXTextureContext8::fill_d3d_texture_mipmap_pixels(int mip_level, int dep
   bool using_temp_buffer = false;
   bool using_temp_buffer = false;
   HRESULT hr = E_FAIL;
   HRESULT hr = E_FAIL;
   CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
   CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
+  nassertr(!image.is_null(), E_FAIL);
   BYTE *pixels = (BYTE*) image.p();
   BYTE *pixels = (BYTE*) image.p();
   DWORD width  = (DWORD) get_texture()->get_expected_mipmap_x_size(mip_level);
   DWORD width  = (DWORD) get_texture()->get_expected_mipmap_x_size(mip_level);
   DWORD height = (DWORD) get_texture()->get_expected_mipmap_y_size(mip_level);
   DWORD height = (DWORD) get_texture()->get_expected_mipmap_y_size(mip_level);
@@ -1276,6 +1410,7 @@ HRESULT DXTextureContext8::fill_d3d_texture_mipmap_pixels(int mip_level, int dep
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg8_cat.error()
     dxgsg8_cat.error()
       << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
       << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
+      << ", mip_level " << mip_level
       << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
       << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
   }
   }
 
 
@@ -1295,14 +1430,16 @@ exit_FillMipmapSurf:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 HRESULT DXTextureContext8::
 HRESULT DXTextureContext8::
 fill_d3d_texture_pixels() {
 fill_d3d_texture_pixels() {
-  if (get_texture()->get_texture_type() == Texture::TT_3d_texture) {
+  Texture *tex = get_texture();
+  nassertr(IS_VALID_PTR(tex), E_FAIL);
+  if (tex->get_texture_type() == Texture::TT_3d_texture) {
     return fill_d3d_volume_texture_pixels();
     return fill_d3d_volume_texture_pixels();
   }
   }
 
 
   HRESULT hr = E_FAIL;
   HRESULT hr = E_FAIL;
-  nassertr(IS_VALID_PTR(get_texture()), E_FAIL);
+  nassertr(IS_VALID_PTR(tex), E_FAIL);
 
 
-  CPTA_uchar image = get_texture()->get_ram_image();
+  CPTA_uchar image = tex->get_ram_image();
   if (image.is_null()) {
   if (image.is_null()) {
     // The texture doesn't have an image to load.  That's ok; it
     // The texture doesn't have an image to load.  That's ok; it
     // might be a texture we've rendered to by frame buffer
     // might be a texture we've rendered to by frame buffer
@@ -1314,11 +1451,11 @@ fill_d3d_texture_pixels() {
 
 
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
 
 
-  DWORD orig_depth = (DWORD) get_texture()->get_z_size();
+  DWORD orig_depth = (DWORD) tex->get_z_size();
   D3DFORMAT source_format = _d3d_format;
   D3DFORMAT source_format = _d3d_format;
 
 
   // check for compressed textures and adjust source_format accordingly
   // check for compressed textures and adjust source_format accordingly
-  switch (get_texture()->get_ram_image_compression()) {
+  switch (tex->get_ram_image_compression()) {
   case Texture::CM_dxt1:
   case Texture::CM_dxt1:
     source_format = D3DFMT_DXT1;
     source_format = D3DFMT_DXT1;
     break;
     break;
@@ -1350,10 +1487,9 @@ fill_d3d_texture_pixels() {
     if (_has_mipmaps) {
     if (_has_mipmaps) {
       // if we have pre-calculated mipmap levels, use them, otherwise generate on the fly
       // if we have pre-calculated mipmap levels, use them, otherwise generate on the fly
       int miplevel_count = _d3d_2d_texture->GetLevelCount(); // what if it's not a 2d texture?
       int miplevel_count = _d3d_2d_texture->GetLevelCount(); // what if it's not a 2d texture?
-
-      if (miplevel_count <= get_texture()->get_num_ram_mipmap_images()) {
+      if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
         dxgsg8_cat.debug()
         dxgsg8_cat.debug()
-        << "Using pre-calculated mipmap levels for texture  " << get_texture()->get_name();
+        << "Using pre-calculated mipmap levels for texture  " << tex->get_name();
 
 
         for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) {
         for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) {
           hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
           hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
@@ -1378,7 +1514,7 @@ fill_d3d_texture_pixels() {
         
         
         if (FAILED(hr)) {
         if (FAILED(hr)) {
           dxgsg8_cat.error()
           dxgsg8_cat.error()
-            << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
+            << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
             << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
             << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
         }
         }
       }
       }

+ 1 - 0
panda/src/dxgsg8/dxTextureContext8.h

@@ -31,6 +31,7 @@ public:
   bool create_texture(DXScreenData &scrn);
   bool create_texture(DXScreenData &scrn);
   bool create_simple_texture(DXScreenData &scrn);
   bool create_simple_texture(DXScreenData &scrn);
   void delete_texture();
   void delete_texture();
+  bool extract_texture_data();
 
 
   INLINE bool has_mipmaps() const;
   INLINE bool has_mipmaps() const;
   INLINE IDirect3DBaseTexture8 *get_d3d_texture() const;
   INLINE IDirect3DBaseTexture8 *get_d3d_texture() const;

+ 21 - 0
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -366,6 +366,27 @@ release_texture(TextureContext *tc) {
   delete dtc;
   delete dtc;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian9::extract_texture_data
+//       Access: Public, Virtual
+//  Description: This method should only be called by the
+//               GraphicsEngine.  Do not call it directly; call
+//               GraphicsEngine::extract_texture_data() instead.
+//
+//               This method will be called in the draw thread to
+//               download the texture memory's image into its
+//               ram_image value.  It returns true on success, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool DXGraphicsStateGuardian9::
+extract_texture_data(Texture *tex) {
+  TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
+  nassertr(tc != (TextureContext *)NULL, false);
+  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
+
+  return dtc->extract_texture_data();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian9::prepare_shader
 //     Function: DXGraphicsStateGuardian9::prepare_shader
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 1 - 0
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -86,6 +86,7 @@ public:
   void apply_texture(int i, TextureContext *tc);
   void apply_texture(int i, TextureContext *tc);
   bool upload_texture(DXTextureContext9 *dtc);
   bool upload_texture(DXTextureContext9 *dtc);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
+  virtual bool extract_texture_data(Texture *tex);
 
 
   ShaderContext *prepare_shader(Shader *se);
   ShaderContext *prepare_shader(Shader *se);
   void release_shader(ShaderContext *sc);
   void release_shader(ShaderContext *sc);

+ 151 - 16
panda/src/dxgsg9/dxTextureContext9.cxx

@@ -16,6 +16,7 @@
 #include "dxGraphicsStateGuardian9.h"
 #include "dxGraphicsStateGuardian9.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
 #include "dxTextureContext9.h"
 #include "dxTextureContext9.h"
+#include "bamCache.h"
 #include <d3dx9tex.h>
 #include <d3dx9tex.h>
 #include <assert.h>
 #include <assert.h>
 #include <time.h>
 #include <time.h>
@@ -718,13 +719,17 @@ create_texture(DXScreenData &scrn) {
   UINT mip_level_count;
   UINT mip_level_count;
 
 
   if (_has_mipmaps) {
   if (_has_mipmaps) {
-    // tell CreateTex to alloc space for all mip levels down to 1x1
-    mip_level_count = 0;
+    tex->get_ram_image();
+    mip_level_count = tex->get_num_loadable_ram_mipmap_images();
+    if (mip_level_count < 2) {
+      // tell CreateTex to alloc space for all mip levels down to 1x1
+      mip_level_count = 0;
 
 
-    if (dxgsg9_cat.is_debug()) {
-      dxgsg9_cat.debug()
-        << "create_texture: generating mipmaps for " << tex->get_name()
-        << endl;
+      if (dxgsg9_cat.is_debug()) {
+        dxgsg9_cat.debug()
+          << "create_texture: generating mipmaps for " << tex->get_name()
+          << endl;
+      }
     }
     }
   } else {
   } else {
     mip_level_count = 1;
     mip_level_count = 1;
@@ -926,6 +931,21 @@ create_texture(DXScreenData &scrn) {
     goto error_exit;
     goto error_exit;
   }
   }
 
 
+  if (tex->get_post_load_store_cache()) {
+    tex->set_post_load_store_cache(false);
+    // OK, get the RAM image, and save it in a BamCache record.
+    if (extract_texture_data()) {
+      if (tex->has_ram_image()) {
+        BamCache *cache = BamCache::get_global_ptr();
+        PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo");
+        if (record != (BamCacheRecord *)NULL) {
+          record->set_data(tex, false);
+          cache->store(record);
+        }
+      }
+    }
+  }
+
   // must not put render to texture into LRU
   // must not put render to texture into LRU
   if (!_managed && !tex->get_render_to_texture()) {
   if (!_managed && !tex->get_render_to_texture()) {
     if (_lru_page == 0) {
     if (_lru_page == 0) {
@@ -1069,6 +1089,119 @@ delete_texture() {
   _d3d_cube_texture = NULL;
   _d3d_cube_texture = NULL;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXTextureContext9::extract_texture_data
+//       Access: Public
+//  Description: This method will be called in the draw thread to
+//               download the texture memory's image into its
+//               ram_image value.  It returns true on success, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool DXTextureContext9::
+extract_texture_data() {
+  HRESULT hr;
+
+  Texture *tex = get_texture();
+  if (tex->get_texture_type() != Texture::TT_2d_texture) {
+    dxgsg9_cat.error()
+      << "Not supported: extract_texture_data for " << tex->get_texture_type()
+      << "\n";
+    return false;
+  }
+  nassertr(IS_VALID_PTR(_d3d_2d_texture), false);
+
+  D3DSURFACE_DESC desc;
+  hr = _d3d_2d_texture->GetLevelDesc(0, &desc);
+  if (FAILED(hr)) {
+    dxgsg9_cat.error()
+      << "Texture::GetLevelDesc() failed!" << D3DERRORSTRING(hr);
+    return false;
+  }
+
+  int div = 1;
+  Texture::Format format = Texture::F_rgba;
+  Texture::CompressionMode compression = Texture::CM_off;
+
+  switch (desc.Format) {
+  case D3DFMT_R8G8B8:
+    format = Texture::F_rgb;
+    break;
+
+  case D3DFMT_A8R8G8B8:
+  case D3DFMT_X8R8G8B8:
+    break;
+
+  case D3DFMT_L8:
+    format = Texture::F_luminance;
+    break;
+
+  case D3DFMT_A8L8:
+    format = Texture::F_luminance_alpha;
+    break;
+
+  case D3DFMT_DXT1:
+    compression = Texture::CM_dxt1;
+    div = 4;
+    break;
+  case D3DFMT_DXT2:
+    compression = Texture::CM_dxt2;
+    div = 4;
+    break;
+  case D3DFMT_DXT3:
+    compression = Texture::CM_dxt3;
+    div = 4;
+    break;
+  case D3DFMT_DXT4:
+    compression = Texture::CM_dxt4;
+    div = 4;
+    break;
+  case D3DFMT_DXT5:
+    compression = Texture::CM_dxt5;
+    div = 4;
+    break;
+
+  default:
+    dxgsg9_cat.error()
+      << "Cannot extract texture data: unhandled surface format " 
+      << desc.Format << "\n";
+    return false;
+  }
+
+  int num_levels = _d3d_2d_texture->GetLevelCount();
+
+  tex->set_x_size(desc.Width);
+  tex->set_y_size(desc.Height);
+  tex->set_z_size(1);
+  tex->set_component_type(Texture::T_unsigned_byte);
+  tex->set_format(format);
+  tex->clear_ram_image();
+
+  for (int n = 0; n < num_levels; ++n) {
+    D3DLOCKED_RECT rect;
+    hr = _d3d_2d_texture->LockRect(n, &rect, NULL, D3DLOCK_READONLY);
+    if (FAILED(hr)) {
+      dxgsg9_cat.error()
+        << "Texture::LockRect() failed!" << D3DERRORSTRING(hr);
+      return false;
+    }
+    
+    int y_size = tex->get_expected_mipmap_y_size(n);
+    int size = rect.Pitch * (y_size / div);
+    size = min(size, (int)tex->get_expected_ram_mipmap_image_size(n));
+    PTA_uchar image = PTA_uchar::empty_array(size);
+    memcpy(image.p(), rect.pBits, size);
+    
+    _d3d_2d_texture->UnlockRect(n);
+    if (n == 0) {
+      tex->set_ram_image(image, compression);
+    } else {
+      tex->set_ram_mipmap_image(n, image);
+    }
+  }
+    
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXTextureContext9::d3d_surface_to_texture
 //     Function: DXTextureContext9::d3d_surface_to_texture
 //       Access: Public, Static
 //       Access: Public, Static
@@ -1377,6 +1510,7 @@ HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int dep
   bool using_temp_buffer = false;
   bool using_temp_buffer = false;
   HRESULT hr = E_FAIL;
   HRESULT hr = E_FAIL;
   CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
   CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
+  nassertr(!image.is_null(), E_FAIL);
   BYTE *pixels = (BYTE*) image.p();
   BYTE *pixels = (BYTE*) image.p();
   DWORD width  = (DWORD) get_texture()->get_expected_mipmap_x_size(mip_level);
   DWORD width  = (DWORD) get_texture()->get_expected_mipmap_x_size(mip_level);
   DWORD height = (DWORD) get_texture()->get_expected_mipmap_y_size(mip_level);
   DWORD height = (DWORD) get_texture()->get_expected_mipmap_y_size(mip_level);
@@ -1472,6 +1606,7 @@ HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int dep
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg9_cat.error()
     dxgsg9_cat.error()
       << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
       << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
+      << ", mip_level " << mip_level
       << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
       << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
   }
   }
 
 
@@ -1491,19 +1626,20 @@ exit_FillMipmapSurf:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 HRESULT DXTextureContext9::
 HRESULT DXTextureContext9::
 fill_d3d_texture_pixels(bool supports_automatic_mipmap_generation,  IDirect3DDevice9 *device) {
 fill_d3d_texture_pixels(bool supports_automatic_mipmap_generation,  IDirect3DDevice9 *device) {
-  if (get_texture()->get_texture_type() == Texture::TT_3d_texture) {
+  Texture *tex = get_texture();
+  nassertr(IS_VALID_PTR(tex), E_FAIL);
+  if (tex->get_texture_type() == Texture::TT_3d_texture) {
     return fill_d3d_volume_texture_pixels();
     return fill_d3d_volume_texture_pixels();
   }
   }
 
 
   HRESULT hr = E_FAIL;
   HRESULT hr = E_FAIL;
-  nassertr(IS_VALID_PTR(get_texture()), E_FAIL);
 
 
-  CPTA_uchar image = get_texture()->get_ram_image();
+  CPTA_uchar image = tex->get_ram_image();
   if (image.is_null()) {
   if (image.is_null()) {
     // The texture doesn't have an image to load.  That's ok; it
     // The texture doesn't have an image to load.  That's ok; it
     // might be a texture we've rendered to by frame buffer
     // might be a texture we've rendered to by frame buffer
     // operations or something.
     // operations or something.
-    if (get_texture()->get_render_to_texture()) {   
+    if (tex->get_render_to_texture()) {   
       HRESULT result;
       HRESULT result;
 
 
       if (_d3d_2d_texture) {
       if (_d3d_2d_texture) {
@@ -1546,11 +1682,11 @@ fill_d3d_texture_pixels(bool supports_automatic_mipmap_generation,  IDirect3DDev
 
 
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
 
 
-  DWORD orig_depth = (DWORD) get_texture()->get_z_size();
+  DWORD orig_depth = (DWORD) tex->get_z_size();
   D3DFORMAT source_format = _d3d_format;
   D3DFORMAT source_format = _d3d_format;
   
   
   // check for compressed textures and adjust source_format accordingly
   // check for compressed textures and adjust source_format accordingly
-  switch (get_texture()->get_ram_image_compression()) {
+  switch (tex->get_ram_image_compression()) {
   case Texture::CM_dxt1:
   case Texture::CM_dxt1:
     source_format = D3DFMT_DXT1;
     source_format = D3DFMT_DXT1;
     break;
     break;
@@ -1582,10 +1718,9 @@ fill_d3d_texture_pixels(bool supports_automatic_mipmap_generation,  IDirect3DDev
     if (_has_mipmaps) {
     if (_has_mipmaps) {
       // if we have pre-calculated mipmap levels, use them, otherwise generate on the fly
       // if we have pre-calculated mipmap levels, use them, otherwise generate on the fly
       int miplevel_count = _d3d_2d_texture->GetLevelCount(); // what if it's not a 2d texture?
       int miplevel_count = _d3d_2d_texture->GetLevelCount(); // what if it's not a 2d texture?
-
-      if (miplevel_count <= get_texture()->get_num_ram_mipmap_images()) {
+      if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
         dxgsg9_cat.debug()
         dxgsg9_cat.debug()
-        << "Using pre-calculated mipmap levels for texture  " << get_texture()->get_name();
+        << "Using pre-calculated mipmap levels for texture  " << tex->get_name();
 
 
         for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) {
         for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) {
           hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
           hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
@@ -1625,7 +1760,7 @@ fill_d3d_texture_pixels(bool supports_automatic_mipmap_generation,  IDirect3DDev
 
 
           if (FAILED(hr)) {
           if (FAILED(hr)) {
             dxgsg9_cat.error()
             dxgsg9_cat.error()
-              << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
+              << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
               << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
               << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
           }
           }
         }
         }

+ 1 - 0
panda/src/dxgsg9/dxTextureContext9.h

@@ -33,6 +33,7 @@ public:
   bool create_texture(DXScreenData &scrn);
   bool create_texture(DXScreenData &scrn);
   bool create_simple_texture(DXScreenData &scrn);
   bool create_simple_texture(DXScreenData &scrn);
   void delete_texture();
   void delete_texture();
+  bool extract_texture_data();
 
 
   INLINE bool has_mipmaps() const;
   INLINE bool has_mipmaps() const;
   INLINE IDirect3DBaseTexture9 *get_d3d_texture() const;
   INLINE IDirect3DBaseTexture9 *get_d3d_texture() const;

+ 12 - 22
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -7104,9 +7104,11 @@ upload_texture_image(CLP(TextureContext) *gtc,
     for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) {
     for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) {
       CPTA_uchar ptimage = tex->get_ram_mipmap_image(n);
       CPTA_uchar ptimage = tex->get_ram_mipmap_image(n);
       if (ptimage == (const unsigned char *)NULL) {
       if (ptimage == (const unsigned char *)NULL) {
-        GLCAT.warning()
-          << "No mipmap level " << n << " defined for " << tex->get_name()
-          << "\n";
+        if (GLCAT.is_debug()) {
+          GLCAT.debug()
+            << "No mipmap level " << n << " defined for " << tex->get_name()
+            << "\n";
+        }
         // No mipmap level n; stop here.
         // No mipmap level n; stop here.
         break;
         break;
       }
       }
@@ -7651,25 +7653,13 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
     break;
     break;
   }
   }
 
 
-  /*
-  switch (target) {
-  case GL_TEXTURE_1D:
-    tex->setup_1d_texture(width, type, format);
-    break;
-    
-  case GL_TEXTURE_2D:
-    tex->setup_2d_texture(width, height, type, format);
-    break;
-    
-  case GL_TEXTURE_3D:
-    tex->setup_3d_texture(width, height, depth, type, format);
-    break;
-    
-  case GL_TEXTURE_CUBE_MAP:
-    tex->setup_cube_map(width, type, format);
-    break;
-  }
-  */
+  // We don't want to call setup_texture() again; that resets too
+  // much.  Instead, we'll just set the individual components.
+  tex->set_x_size(width);
+  tex->set_y_size(height);
+  tex->set_z_size(depth);
+  tex->set_component_type(type);
+  tex->set_format(format);
 
 
   tex->set_wrap_u(get_panda_wrap_mode(wrap_u));
   tex->set_wrap_u(get_panda_wrap_mode(wrap_u));
   tex->set_wrap_v(get_panda_wrap_mode(wrap_v));
   tex->set_wrap_v(get_panda_wrap_mode(wrap_v));