directx extract_texture_data

This commit is contained in:
David Rose 2008-08-21 23:04:31 +00:00
parent ea3f6a2206
commit 4074c2717a
9 changed files with 360 additions and 53 deletions

View File

@ -304,6 +304,27 @@ release_texture(TextureContext *tc) {
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
// Access: Public, Virtual

View File

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

View File

@ -17,6 +17,7 @@
#include "dxGraphicsStateGuardian8.h"
#include "pStatTimer.h"
#include "dxgsg8base.h"
#include "bamCache.h"
#include <assert.h>
#include <time.h>
@ -684,13 +685,17 @@ create_texture(DXScreenData &scrn) {
UINT mip_level_count;
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 {
mip_level_count = 1;
@ -752,6 +757,21 @@ create_texture(DXScreenData &scrn) {
if (FAILED(hr)) {
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);
mark_loaded();
@ -873,6 +893,119 @@ delete_texture() {
_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
// Access: Public, Static
@ -1181,6 +1314,7 @@ HRESULT DXTextureContext8::fill_d3d_texture_mipmap_pixels(int mip_level, int dep
bool using_temp_buffer = false;
HRESULT hr = E_FAIL;
CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
nassertr(!image.is_null(), E_FAIL);
BYTE *pixels = (BYTE*) image.p();
DWORD width = (DWORD) get_texture()->get_expected_mipmap_x_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)) {
dxgsg8_cat.error()
<< "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
<< ", mip_level " << mip_level
<< ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
}
@ -1295,14 +1430,16 @@ exit_FillMipmapSurf:
////////////////////////////////////////////////////////////////////
HRESULT DXTextureContext8::
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();
}
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()) {
// The texture doesn't have an image to load. That's ok; it
// 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);
DWORD orig_depth = (DWORD) get_texture()->get_z_size();
DWORD orig_depth = (DWORD) tex->get_z_size();
D3DFORMAT source_format = _d3d_format;
// 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:
source_format = D3DFMT_DXT1;
break;
@ -1350,10 +1487,9 @@ fill_d3d_texture_pixels() {
if (_has_mipmaps) {
// 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?
if (miplevel_count <= get_texture()->get_num_ram_mipmap_images()) {
if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
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) {
hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format);
@ -1378,7 +1514,7 @@ fill_d3d_texture_pixels() {
if (FAILED(hr)) {
dxgsg8_cat.error()
<< "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
<< "FillDDSurfaceTexturePixels failed for " << tex->get_name()
<< ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
}
}

View File

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

View File

@ -366,6 +366,27 @@ release_texture(TextureContext *tc) {
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
// Access: Public, Virtual

View File

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

View File

@ -16,6 +16,7 @@
#include "dxGraphicsStateGuardian9.h"
#include "pStatTimer.h"
#include "dxTextureContext9.h"
#include "bamCache.h"
#include <d3dx9tex.h>
#include <assert.h>
#include <time.h>
@ -718,13 +719,17 @@ create_texture(DXScreenData &scrn) {
UINT mip_level_count;
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 {
mip_level_count = 1;
@ -926,6 +931,21 @@ create_texture(DXScreenData &scrn) {
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
if (!_managed && !tex->get_render_to_texture()) {
if (_lru_page == 0) {
@ -1069,6 +1089,119 @@ delete_texture() {
_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
// Access: Public, Static
@ -1377,6 +1510,7 @@ HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int dep
bool using_temp_buffer = false;
HRESULT hr = E_FAIL;
CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
nassertr(!image.is_null(), E_FAIL);
BYTE *pixels = (BYTE*) image.p();
DWORD width = (DWORD) get_texture()->get_expected_mipmap_x_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)) {
dxgsg9_cat.error()
<< "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
<< ", mip_level " << mip_level
<< ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
}
@ -1491,19 +1626,20 @@ exit_FillMipmapSurf:
////////////////////////////////////////////////////////////////////
HRESULT DXTextureContext9::
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();
}
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()) {
// The texture doesn't have an image to load. That's ok; it
// might be a texture we've rendered to by frame buffer
// operations or something.
if (get_texture()->get_render_to_texture()) {
if (tex->get_render_to_texture()) {
HRESULT result;
if (_d3d_2d_texture) {
@ -1546,11 +1682,11 @@ fill_d3d_texture_pixels(bool supports_automatic_mipmap_generation, IDirect3DDev
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;
// 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:
source_format = D3DFMT_DXT1;
break;
@ -1582,10 +1718,9 @@ fill_d3d_texture_pixels(bool supports_automatic_mipmap_generation, IDirect3DDev
if (_has_mipmaps) {
// 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?
if (miplevel_count <= get_texture()->get_num_ram_mipmap_images()) {
if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
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) {
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)) {
dxgsg9_cat.error()
<< "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
<< "FillDDSurfaceTexturePixels failed for " << tex->get_name()
<< ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
}
}

View File

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

View File

@ -7104,9 +7104,11 @@ upload_texture_image(CLP(TextureContext) *gtc,
for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) {
CPTA_uchar ptimage = tex->get_ram_mipmap_image(n);
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.
break;
}
@ -7651,25 +7653,13 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
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_v(get_panda_wrap_mode(wrap_v));