diff --git a/panda/src/dxgsg9/dxTextureContext9.cxx b/panda/src/dxgsg9/dxTextureContext9.cxx index 09d90a1b5b..1ee6fadbc9 100755 --- a/panda/src/dxgsg9/dxTextureContext9.cxx +++ b/panda/src/dxgsg9/dxTextureContext9.cxx @@ -47,6 +47,7 @@ DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex) : _d3d_volume_texture = NULL; _d3d_cube_texture = NULL; _has_mipmaps = false; + _is_render_target = false; _managed = -1; } @@ -752,6 +753,8 @@ create_texture(DXScreenData &scrn) { if (tex->get_render_to_texture ( )) { // REQUIRED PARAMETERS _managed = false; + _is_render_target = true; + pool = D3DPOOL_DEFAULT; usage = D3DUSAGE_RENDERTARGET; if (target_bpp <= 32 ) { @@ -797,75 +800,10 @@ create_texture(DXScreenData &scrn) { float bytes_per_texel; - bytes_per_texel = 1.0f; - switch (target_pixel_format) - { - case D3DFMT_R3G3B2: - case D3DFMT_A8: - case D3DFMT_A8P8: - case D3DFMT_P8: - case D3DFMT_L8: - case D3DFMT_A4L4: - bytes_per_texel = 1.0f; - break; - - case D3DFMT_R16F: - case D3DFMT_CxV8U8: - case D3DFMT_V8U8: - case D3DFMT_R5G6B5: - case D3DFMT_X1R5G5B5: - case D3DFMT_A1R5G5B5: - case D3DFMT_A4R4G4B4: - case D3DFMT_L16: - case D3DFMT_A8L8: - case D3DFMT_A8R3G3B2: - case D3DFMT_X4R4G4B4: - bytes_per_texel = 2.0f; - break; - - case D3DFMT_R8G8B8: - bytes_per_texel = 3.0f; - break; - - case D3DFMT_G16R16F: - case D3DFMT_Q8W8V8U8: - case D3DFMT_V16U16: - case D3DFMT_R32F: - case D3DFMT_A8R8G8B8: - case D3DFMT_X8R8G8B8: - case D3DFMT_A2B10G10R10: - case D3DFMT_A8B8G8R8: - case D3DFMT_X8B8G8R8: - case D3DFMT_G16R16: - case D3DFMT_A2R10G10B10: - bytes_per_texel = 4.0f; - break; - - case D3DFMT_G32R32F: - case D3DFMT_A16B16G16R16F: - case D3DFMT_Q16W16V16U16: - case D3DFMT_A16B16G16R16: - bytes_per_texel = 8.0f; - break; - - case D3DFMT_A32B32G32R32F: - bytes_per_texel = 16.0f; - break; - - case D3DFMT_DXT1: - bytes_per_texel = 0.5f; - break; - case D3DFMT_DXT2: - case D3DFMT_DXT3: - case D3DFMT_DXT4: - case D3DFMT_DXT5: - bytes_per_texel = 1.0f; - break; - - default: - dxgsg9_cat.error() - << "D3D create_texture ( ) unknown texture format\n"; - break; + bytes_per_texel = this -> d3d_format_to_bytes_per_pixel (target_pixel_format); + if (bytes_per_texel == 0.0f) { + dxgsg9_cat.error() + << "D3D create_texture ( ) unknown texture format\n"; } int data_size; @@ -944,7 +882,7 @@ create_texture(DXScreenData &scrn) { 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 (extract_texture_data(scrn)) { if (tex->has_ram_image()) { BamCache *cache = BamCache::get_global_ptr(); PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo"); @@ -1090,15 +1028,17 @@ delete_texture() { // otherwise. //////////////////////////////////////////////////////////////////// bool DXTextureContext9:: -extract_texture_data() { +extract_texture_data(DXScreenData &screen) { + bool state; HRESULT hr; - + + state = false; 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; + return state; } nassertr(IS_VALID_PTR(_d3d_2d_texture), false); @@ -1107,7 +1047,7 @@ extract_texture_data() { if (FAILED(hr)) { dxgsg9_cat.error() << "Texture::GetLevelDesc() failed!" << D3DERRORSTRING(hr); - return false; + return state; } int div = 1; @@ -1156,7 +1096,7 @@ extract_texture_data() { dxgsg9_cat.error() << "Cannot extract texture data: unhandled surface format " << desc.Format << "\n"; - return false; + return state; } int num_levels = _d3d_2d_texture->GetLevelCount(); @@ -1168,30 +1108,112 @@ extract_texture_data() { 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! level = " << n << " " << D3DERRORSTRING(hr); - return false; - } + if (_is_render_target) { + IDirect3DSurface9* source_surface; + IDirect3DSurface9* destination_surface; + + source_surface = 0; + destination_surface = 0; - 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); + hr = _d3d_2d_texture -> GetSurfaceLevel (0, &source_surface); + if (hr == D3D_OK) { + + D3DPOOL pool; + D3DSURFACE_DESC surface_description; + + pool = D3DPOOL_SYSTEMMEM; + source_surface -> GetDesc (&surface_description); + + hr = screen._d3d_device->CreateOffscreenPlainSurface ( + surface_description.Width, + surface_description.Height, + surface_description.Format, + pool, + &destination_surface, + NULL); + if (hr == D3D_OK) { + if (source_surface && destination_surface) { + hr = screen._d3d_device -> GetRenderTargetData (source_surface, destination_surface); + if (hr == D3D_OK) { + + D3DLOCKED_RECT rect; + + hr = destination_surface -> LockRect (&rect, NULL, D3DLOCK_READONLY); + if (hr == D3D_OK) { + + unsigned int y; + int size; + int bytes_per_line; + + int surface_bytes_per_line; + unsigned char *surface_pointer; + + bytes_per_line = surface_description.Width * this -> d3d_format_to_bytes_per_pixel (surface_description.Format); + size = bytes_per_line * surface_description.Height; + + surface_bytes_per_line = rect.Pitch; + surface_pointer = (unsigned char *) rect.pBits; + + PTA_uchar image = PTA_uchar::empty_array(size); + + int offset; + + offset = 0; + for (y = 0; y < surface_description.Height; y++) + { + memcpy (&image [offset], surface_pointer, bytes_per_line); + + offset += bytes_per_line; + surface_pointer += surface_bytes_per_line; + } + + tex->set_ram_image(image, Texture::CM_off); + + state = true; + + destination_surface -> UnlockRect(); + } + } + } + + destination_surface -> Release ( ); + } + else { + dxgsg9_cat.error() + << "CreateImageSurface failed in extract_texture_data()" + << D3DERRORSTRING(hr); + } + source_surface -> Release ( ); } } + else { + 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! level = " << n << " " << D3DERRORSTRING(hr); + return state; + } + + 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; + state = true; + } + + return state; } //////////////////////////////////////////////////////////////////// @@ -2065,3 +2087,82 @@ get_bits_per_pixel(Texture::Format format, int *alphbits) { } return 8; } + +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::d3d_format_to_bytes_per_pixel +// Access: Private +// Description: Determines bytes per pixel from D3DFORMAT. +//////////////////////////////////////////////////////////////////// +float DXTextureContext9:: +d3d_format_to_bytes_per_pixel (D3DFORMAT format) +{ + int bytes_per_pixel; + + bytes_per_pixel = 0.0f; + switch (format) + { + case D3DFMT_R3G3B2: + case D3DFMT_A8: + case D3DFMT_A8P8: + case D3DFMT_P8: + case D3DFMT_L8: + case D3DFMT_A4L4: + bytes_per_pixel = 1.0f; + break; + + case D3DFMT_R16F: + case D3DFMT_CxV8U8: + case D3DFMT_V8U8: + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + case D3DFMT_A4R4G4B4: + case D3DFMT_L16: + case D3DFMT_A8L8: + case D3DFMT_A8R3G3B2: + case D3DFMT_X4R4G4B4: + bytes_per_pixel = 2.0f; + break; + + case D3DFMT_R8G8B8: + bytes_per_pixel = 3.0f; + break; + + case D3DFMT_G16R16F: + case D3DFMT_Q8W8V8U8: + case D3DFMT_V16U16: + case D3DFMT_R32F: + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A2B10G10R10: + case D3DFMT_A8B8G8R8: + case D3DFMT_X8B8G8R8: + case D3DFMT_G16R16: + case D3DFMT_A2R10G10B10: + bytes_per_pixel = 4.0f; + break; + + case D3DFMT_G32R32F: + case D3DFMT_A16B16G16R16F: + case D3DFMT_Q16W16V16U16: + case D3DFMT_A16B16G16R16: + bytes_per_pixel = 8.0f; + break; + + case D3DFMT_A32B32G32R32F: + bytes_per_pixel = 16.0f; + break; + + case D3DFMT_DXT1: + bytes_per_pixel = 0.5f; + break; + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: + bytes_per_pixel = 1.0f; + break; + } + + return bytes_per_pixel; +} diff --git a/panda/src/dxgsg9/dxTextureContext9.h b/panda/src/dxgsg9/dxTextureContext9.h index 78421611fb..af7cde8814 100755 --- a/panda/src/dxgsg9/dxTextureContext9.h +++ b/panda/src/dxgsg9/dxTextureContext9.h @@ -35,7 +35,7 @@ public: bool create_texture(DXScreenData &scrn); bool create_simple_texture(DXScreenData &scrn); void delete_texture(); - bool extract_texture_data(); + bool extract_texture_data(DXScreenData &scrn); INLINE bool has_mipmaps() const; INLINE IDirect3DBaseTexture9 *get_d3d_texture() const; @@ -54,6 +54,7 @@ private: HRESULT fill_d3d_volume_texture_pixels(DXScreenData &scrn); static int down_to_power_2(int value); unsigned int get_bits_per_pixel(Texture::Format format, int *alphbits); + float d3d_format_to_bytes_per_pixel (D3DFORMAT format); private: D3DFORMAT _d3d_format; // the 'D3DFORMAT' the Panda TextureBuffer fmt corresponds to @@ -66,7 +67,8 @@ private: private: bool _has_mipmaps; - + bool _is_render_target; + public: static TypeHandle get_class_type() { return _type_handle;