The last of the saving patches for d3dx9. :)
-- v4: d3dx9: Add support for saving IDirect3DVolumeTexture9 textures to DDS files in D3DXSaveTextureToFileInMemory(). d3dx9: Add support for saving IDirect3DCubeTexture9 textures to DDS files in D3DXSaveTextureToFileInMemory(). d3dx9: Add support for saving IDirect3DTexture9 textures to DDS files in D3DXSaveTextureToFileInMemory(). d3dx9/tests: Add more tests for saving textures to DDS files. d3dx9/tests: Add a test for reading back a texture saved as D3DXIFF_JPG.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 3 + dlls/d3dx9_36/tests/texture.c | 104 +++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 2 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 3813461bc9b..e5a9207ad91 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -580,6 +580,9 @@ static HRESULT d3dx_pixels_save_wic(struct d3dx_pixels *pixels, const struct pix if (FAILED(hr)) goto exit;
+ if (image_file_format == D3DXIFF_JPG) + FIXME("JPEG saving quality adjustment currently unimplemented, expect lower quality JPEG.\n"); + hr = IWICBitmapFrameEncode_SetSize(wic_frame, pixels->size.width, pixels->size.height); if (FAILED(hr)) goto exit; diff --git a/dlls/d3dx9_36/tests/texture.c b/dlls/d3dx9_36/tests/texture.c index 1c8ba0507b3..a4512967835 100644 --- a/dlls/d3dx9_36/tests/texture.c +++ b/dlls/d3dx9_36/tests/texture.c @@ -176,6 +176,23 @@ static BOOL compare_color(DWORD c1, DWORD c2, BYTE max_diff) && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff); }
+static uint8_t pixel_4bpp_max_channel_diff(uint32_t c1, uint32_t c2) +{ + uint8_t max_diff = 0; + unsigned int i; + + for (i = 0; i < 4; ++i) + { + uint8_t x, y; + + x = (c1 >> (i * 8)) & 0xff; + y = (c2 >> (i * 8)) & 0xff; + max_diff = max(max_diff, (x > y ? x - y : y - x)); + } + + return max_diff; +} + struct surface_readback { IDirect3DSurface9 *surface; @@ -3089,8 +3106,42 @@ static void WINAPI fill_cube_positive_x(D3DXVECTOR4 *out, const D3DXVECTOR3 *tex out->x = 1; }
+static void set_vec2(D3DXVECTOR2 *v, float x, float y) +{ + v->x = x; + v->y = y; +} + +static const D3DXVECTOR4 quadrant_color[] = +{ + { 1.0f, 0.0f, 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f }, +}; + +static void WINAPI fill_func(D3DXVECTOR4 *value, const D3DXVECTOR2 *coord, const D3DXVECTOR2 *size, void *data) +{ + D3DXVECTOR2 vec = *coord; + unsigned int idx; + + if (data) + { + *value = *(D3DXVECTOR4 *)data; + return; + } + + set_vec2(&vec, (vec.x / size->x) - 0.5f, (vec.y / size->y) - 0.5f); + if (vec.x < 8.0f) + idx = vec.y < 8.0f ? 0 : 2; + else + idx = vec.y < 8.0f ? 1 : 3; + + *value = quadrant_color[idx]; +} + static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) { + const D3DXVECTOR4 clear_val = { 0.0f, 0.0f, 0.0f, 0.0f }; + IDirect3DSurface9 *surface; + struct surface_readback rb; HRESULT hr; IDirect3DTexture9 *texture; IDirect3DCubeTexture9 *cube_texture; @@ -3165,8 +3216,6 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); if (SUCCEEDED(hr)) { - IDirect3DSurface9 *surface; - buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); buffer_size = ID3DXBuffer_GetBufferSize(buffer); hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); @@ -3269,6 +3318,57 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) }
IDirect3DVolumeTexture9_Release(volume_texture); + + /* Test JPEG compression quality. */ + hr = IDirect3DDevice9_CreateTexture(device, 16, 16, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &texture, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXFillTexture(texture, fill_func, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_JPG, (IDirect3DBaseTexture9 *)texture, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXFillTexture(texture, fill_func, (void *)&clear_val); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, ID3DXBuffer_GetBufferPointer(buffer), + ID3DXBuffer_GetBufferSize(buffer), NULL, D3DX_FILTER_NONE, 0, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_Release(surface); + ID3DXBuffer_Release(buffer); + + /* + * Wine's JPEG compression quality is worse than native. Native uses 4:2:0 + * subsampling which is the same as what we use, but whatever compression + * settings they're using results in a JPEG image that is much closer to + * the original uncompressed surface. Native compresses with a quality + * setting of 95 while currently we use the libjpeg default of 75. + * However, even if we up our quality to 95 to match we still end up with + * a max_diff of 14, so there must also be some other setting(s) involved. + * The quality difference is most apparent in 16x16 blocks with multiple + * colors. + */ + get_texture_surface_readback(device, texture, 0, &rb); + todo_wine ok(compare_color(get_readback_color(&rb, 0, 0), 0xffff0000, 5), + "Unexpected color %#x, max_diff %d.\n", get_readback_color(&rb, 0, 0), + pixel_4bpp_max_channel_diff(get_readback_color(&rb, 0, 0), 0xffff0000)); + todo_wine ok(compare_color(get_readback_color(&rb, 15, 0), 0xff00ff00, 3), + "Unexpected color %#x, max_diff %d.\n", get_readback_color(&rb, 15, 0), + pixel_4bpp_max_channel_diff(get_readback_color(&rb, 15, 0), 0xff00ff00)); + todo_wine ok(compare_color(get_readback_color(&rb, 0, 15), 0xff0000ff, 6), + "Unexpected color %#x, max_diff %d.\n", get_readback_color(&rb, 0, 15), + pixel_4bpp_max_channel_diff(get_readback_color(&rb, 0, 15), 0xff0000ff)); + todo_wine ok(compare_color(get_readback_color(&rb, 15, 15), 0xffffffff, 1), + "Unexpected color %#x, max_diff %d.\n", get_readback_color(&rb, 15, 15), + pixel_4bpp_max_channel_diff(get_readback_color(&rb, 15, 15), 0xffffffff)); + release_surface_readback(&rb); + + IDirect3DTexture9_Release(texture); }
static void test_texture_shader(void)
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/tests/d3dx9_test_images.h | 86 +++++++++++ dlls/d3dx9_36/tests/surface.c | 83 ---------- dlls/d3dx9_36/tests/texture.c | 192 ++++++++++++++++++++++++ 3 files changed, 278 insertions(+), 83 deletions(-)
diff --git a/dlls/d3dx9_36/tests/d3dx9_test_images.h b/dlls/d3dx9_36/tests/d3dx9_test_images.h index f79e9f68894..3ed5373c705 100644 --- a/dlls/d3dx9_36/tests/d3dx9_test_images.h +++ b/dlls/d3dx9_36/tests/d3dx9_test_images.h @@ -72,6 +72,9 @@ struct dds_header DWORD reserved2; };
+#define DDS_FILE_HEADER_SIZE (sizeof(uint32_t) + sizeof(struct dds_header)) +#define PALETTED_DDS_FILE_HEADER_SIZE (DDS_FILE_HEADER_SIZE + (sizeof(PALETTEENTRY) * 256)) + static const struct { uint32_t filter; @@ -91,6 +94,89 @@ test_filter_values[] = { 0xff800001, D3DERR_INVALIDCALL }, };
+static const PALETTEENTRY test_palette[256] = +{ + {0x00,0x00,0x00,0x00}, {0x00,0x00,0x80,0x01}, {0x00,0x80,0x00,0x02}, {0x00,0x80,0x80,0x03}, + {0x80,0x00,0x00,0x04}, {0x80,0x00,0x80,0x05}, {0x80,0x80,0x00,0x06}, {0xc0,0xc0,0xc0,0x07}, + {0xc0,0xdc,0xc0,0x08}, {0xf0,0xca,0xa6,0x09}, {0x00,0x20,0x40,0x0a}, {0x00,0x20,0x60,0x0b}, + {0x00,0x20,0x80,0x0c}, {0x00,0x20,0xa0,0x0d}, {0x00,0x20,0xc0,0x0e}, {0x00,0x20,0xe0,0x0f}, + + {0x00,0x40,0x00,0x10}, {0x00,0x40,0x20,0x11}, {0x00,0x40,0x40,0x12}, {0x00,0x40,0x60,0x13}, + {0x00,0x40,0x80,0x14}, {0x00,0x40,0xa0,0x15}, {0x00,0x40,0xc0,0x16}, {0x00,0x40,0xe0,0x17}, + {0x00,0x60,0x00,0x18}, {0x00,0x60,0x20,0x19}, {0x00,0x60,0x40,0x1a}, {0x00,0x60,0x60,0x1b}, + {0x00,0x60,0x80,0x1c}, {0x00,0x60,0xa0,0x1d}, {0x00,0x60,0xc0,0x1e}, {0x00,0x60,0xe0,0x1f}, + + {0x00,0x80,0x00,0x20}, {0x00,0x80,0x20,0x21}, {0x00,0x80,0x40,0x22}, {0x00,0x80,0x60,0x23}, + {0x00,0x80,0x80,0x24}, {0x00,0x80,0xa0,0x25}, {0x00,0x80,0xc0,0x26}, {0x00,0x80,0xe0,0x27}, + {0x00,0xa0,0x00,0x28}, {0x00,0xa0,0x20,0x29}, {0x00,0xa0,0x40,0x2a}, {0x00,0xa0,0x60,0x2b}, + {0x00,0xa0,0x80,0x2c}, {0x00,0xa0,0xa0,0x2d}, {0x00,0xa0,0xc0,0x2e}, {0x00,0xa0,0xe0,0x2f}, + + {0x00,0xc0,0x00,0x30}, {0x00,0xc0,0x20,0x31}, {0x00,0xc0,0x40,0x32}, {0x00,0xc0,0x60,0x33}, + {0x00,0xc0,0x80,0x34}, {0x00,0xc0,0xa0,0x35}, {0x00,0xc0,0xc0,0x36}, {0x00,0xc0,0xe0,0x37}, + {0x00,0xe0,0x00,0x38}, {0x00,0xe0,0x20,0x39}, {0x00,0xe0,0x40,0x3a}, {0x00,0xe0,0x60,0x3b}, + {0x00,0xe0,0x80,0x3c}, {0x00,0xe0,0xa0,0x3d}, {0x00,0xe0,0xc0,0x3e}, {0x00,0xe0,0xe0,0x3f}, + + {0x40,0x00,0x00,0x40}, {0x40,0x00,0x20,0x41}, {0x40,0x00,0x40,0x42}, {0x40,0x00,0x60,0x43}, + {0x40,0x00,0x80,0x44}, {0x40,0x00,0xa0,0x45}, {0x40,0x00,0xc0,0x46}, {0x40,0x00,0xe0,0x47}, + {0x40,0x20,0x00,0x48}, {0x40,0x20,0x20,0x49}, {0x40,0x20,0x40,0x4a}, {0x40,0x20,0x60,0x4b}, + {0x40,0x20,0x80,0x4c}, {0x40,0x20,0xa0,0x4d}, {0x40,0x20,0xc0,0x4e}, {0x40,0x20,0xe0,0x4f}, + + {0x40,0x40,0x00,0x50}, {0x40,0x40,0x20,0x51}, {0x40,0x40,0x40,0x52}, {0x40,0x40,0x60,0x53}, + {0x40,0x40,0x80,0x54}, {0x40,0x40,0xa0,0x55}, {0x40,0x40,0xc0,0x56}, {0x40,0x40,0xe0,0x57}, + {0x40,0x60,0x00,0x58}, {0x40,0x60,0x20,0x59}, {0x40,0x60,0x40,0x5a}, {0x40,0x60,0x60,0x5b}, + {0x40,0x60,0x80,0x5c}, {0x40,0x60,0xa0,0x5d}, {0x40,0x60,0xc0,0x5e}, {0x40,0x60,0xe0,0x5f}, + + {0x40,0x80,0x00,0x60}, {0x40,0x80,0x20,0x61}, {0x40,0x80,0x40,0x62}, {0x40,0x80,0x60,0x63}, + {0x40,0x80,0x80,0x64}, {0x40,0x80,0xa0,0x65}, {0x40,0x80,0xc0,0x66}, {0x40,0x80,0xe0,0x67}, + {0x40,0xa0,0x00,0x68}, {0x40,0xa0,0x20,0x69}, {0x40,0xa0,0x40,0x6a}, {0x40,0xa0,0x60,0x6b}, + {0x40,0xa0,0x80,0x6c}, {0x40,0xa0,0xa0,0x6d}, {0x40,0xa0,0xc0,0x6e}, {0x40,0xa0,0xe0,0x6f}, + + {0x40,0xc0,0x00,0x70}, {0x40,0xc0,0x20,0x71}, {0x40,0xc0,0x40,0x72}, {0x40,0xc0,0x60,0x73}, + {0x40,0xc0,0x80,0x74}, {0x40,0xc0,0xa0,0x75}, {0x40,0xc0,0xc0,0x76}, {0x40,0xc0,0xe0,0x77}, + {0x40,0xe0,0x00,0x78}, {0x40,0xe0,0x20,0x79}, {0x40,0xe0,0x40,0x7a}, {0x40,0xe0,0x60,0x7b}, + {0x40,0xe0,0x80,0x7c}, {0x40,0xe0,0xa0,0x7d}, {0x40,0xe0,0xc0,0x7e}, {0x40,0xe0,0xe0,0x7f}, + + {0x80,0x00,0x00,0x80}, {0x80,0x00,0x20,0x81}, {0x80,0x00,0x40,0x82}, {0x80,0x00,0x60,0x83}, + {0x80,0x00,0x80,0x84}, {0x80,0x00,0xa0,0x85}, {0x80,0x00,0xc0,0x86}, {0x80,0x00,0xe0,0x87}, + {0x80,0x20,0x00,0x88}, {0x80,0x20,0x20,0x89}, {0x80,0x20,0x40,0x8a}, {0x80,0x20,0x60,0x8b}, + {0x80,0x20,0x80,0x8c}, {0x80,0x20,0xa0,0x8d}, {0x80,0x20,0xc0,0x8e}, {0x80,0x20,0xe0,0x8f}, + + {0x80,0x40,0x00,0x90}, {0x80,0x40,0x20,0x91}, {0x80,0x40,0x40,0x92}, {0x80,0x40,0x60,0x93}, + {0x80,0x40,0x80,0x94}, {0x80,0x40,0xa0,0x95}, {0x80,0x40,0xc0,0x96}, {0x80,0x40,0xe0,0x97}, + {0x80,0x60,0x00,0x98}, {0x80,0x60,0x20,0x99}, {0x80,0x60,0x40,0x9a}, {0x80,0x60,0x60,0x9b}, + {0x80,0x60,0x80,0x9c}, {0x80,0x60,0xa0,0x9d}, {0x80,0x60,0xc0,0x9e}, {0x80,0x60,0xe0,0x9f}, + + {0x80,0x80,0x00,0xa0}, {0x80,0x80,0x20,0xa1}, {0x80,0x80,0x40,0xa2}, {0x80,0x80,0x60,0xa3}, + {0x80,0x80,0x80,0xa4}, {0x80,0x80,0xa0,0xa5}, {0x80,0x80,0xc0,0xa6}, {0x80,0x80,0xe0,0xa7}, + {0x80,0xa0,0x00,0xa8}, {0x80,0xa0,0x20,0xa9}, {0x80,0xa0,0x40,0xaa}, {0x80,0xa0,0x60,0xab}, + {0x80,0xa0,0x80,0xac}, {0x80,0xa0,0xa0,0xad}, {0x80,0xa0,0xc0,0xae}, {0x80,0xa0,0xe0,0xaf}, + + {0x80,0xc0,0x00,0xb0}, {0x80,0xc0,0x20,0xb1}, {0x80,0xc0,0x40,0xb2}, {0x80,0xc0,0x60,0xb3}, + {0x80,0xc0,0x80,0xb4}, {0x80,0xc0,0xa0,0xb5}, {0x80,0xc0,0xc0,0xb6}, {0x80,0xc0,0xe0,0xb7}, + {0x80,0xe0,0x00,0xb8}, {0x80,0xe0,0x20,0xb9}, {0x80,0xe0,0x40,0xba}, {0x80,0xe0,0x60,0xbb}, + {0x80,0xe0,0x80,0xbc}, {0x80,0xe0,0xa0,0xbd}, {0x80,0xe0,0xc0,0xbe}, {0x80,0xe0,0xe0,0xbf}, + + {0xc0,0x00,0x00,0xc0}, {0xc0,0x00,0x20,0xc1}, {0xc0,0x00,0x40,0xc2}, {0xc0,0x00,0x60,0xc3}, + {0xc0,0x00,0x80,0xc4}, {0xc0,0x00,0xa0,0xc5}, {0xc0,0x00,0xc0,0xc6}, {0xc0,0x00,0xe0,0xc7}, + {0xc0,0x20,0x00,0xc8}, {0xc0,0x20,0x20,0xc9}, {0xc0,0x20,0x40,0xca}, {0xc0,0x20,0x60,0xcb}, + {0xc0,0x20,0x80,0xcc}, {0xc0,0x20,0xa0,0xcd}, {0xc0,0x20,0xc0,0xce}, {0xc0,0x20,0xe0,0xcf}, + + {0xc0,0x40,0x00,0xd0}, {0xc0,0x40,0x20,0xd1}, {0xc0,0x40,0x40,0xd2}, {0xc0,0x40,0x60,0xd3}, + {0xc0,0x40,0x80,0xd4}, {0xc0,0x40,0xa0,0xd5}, {0xc0,0x40,0xc0,0xd6}, {0xc0,0x40,0xe0,0xd7}, + {0xc0,0x60,0x00,0xd8}, {0xc0,0x60,0x20,0xd9}, {0xc0,0x60,0x40,0xda}, {0xc0,0x60,0x60,0xdb}, + {0xc0,0x60,0x80,0xdc}, {0xc0,0x60,0xa0,0xdd}, {0xc0,0x60,0xc0,0xde}, {0xc0,0x60,0xe0,0xdf}, + + {0xc0,0x80,0x00,0xe0}, {0xc0,0x80,0x20,0xe1}, {0xc0,0x80,0x40,0xe2}, {0xc0,0x80,0x60,0xe3}, + {0xc0,0x80,0x80,0xe4}, {0xc0,0x80,0xa0,0xe5}, {0xc0,0x80,0xc0,0xe6}, {0xc0,0x80,0xe0,0xe7}, + {0xc0,0xa0,0x00,0xe8}, {0xc0,0xa0,0x20,0xe9}, {0xc0,0xa0,0x40,0xea}, {0xc0,0xa0,0x60,0xeb}, + {0xc0,0xa0,0x80,0xec}, {0xc0,0xa0,0xa0,0xed}, {0xc0,0xa0,0xc0,0xee}, {0xc0,0xa0,0xe0,0xef}, + + {0xc0,0xc0,0x00,0xf0}, {0xc0,0xc0,0x20,0xf1}, {0xc0,0xc0,0x40,0xf2}, {0xc0,0xc0,0x60,0xf3}, + {0xc0,0xc0,0x80,0xf4}, {0xc0,0xc0,0xa0,0xf5}, {0xf0,0xfb,0xff,0xf6}, {0xa4,0xa0,0xa0,0xf7}, + {0x80,0x80,0x80,0xf8}, {0x00,0x00,0xff,0xf9}, {0x00,0xff,0x00,0xfa}, {0x00,0xff,0xff,0xfb}, + {0xff,0x00,0x00,0xfc}, {0xff,0x00,0xff,0xfd}, {0xff,0xff,0x00,0xfe}, {0xff,0xff,0xff,0xff}, +}; + /* 1x1 bmp (1 bpp) */ static const uint8_t bmp_1bpp[] = { diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 38e328f58c5..c618ff6c48a 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1060,89 +1060,6 @@ static inline void _check_readback_pixel_4bpp(unsigned int line, struct surface_ todo_wine_if(todo) ok_(__FILE__, line)(color == expected_color, "Got color 0x%08x, expected 0x%08x.\n", color, expected_color); }
-static const PALETTEENTRY test_palette[256] = -{ - {0x00,0x00,0x00,0x00}, {0x00,0x00,0x80,0x01}, {0x00,0x80,0x00,0x02}, {0x00,0x80,0x80,0x03}, - {0x80,0x00,0x00,0x04}, {0x80,0x00,0x80,0x05}, {0x80,0x80,0x00,0x06}, {0xc0,0xc0,0xc0,0x07}, - {0xc0,0xdc,0xc0,0x08}, {0xf0,0xca,0xa6,0x09}, {0x00,0x20,0x40,0x0a}, {0x00,0x20,0x60,0x0b}, - {0x00,0x20,0x80,0x0c}, {0x00,0x20,0xa0,0x0d}, {0x00,0x20,0xc0,0x0e}, {0x00,0x20,0xe0,0x0f}, - - {0x00,0x40,0x00,0x10}, {0x00,0x40,0x20,0x11}, {0x00,0x40,0x40,0x12}, {0x00,0x40,0x60,0x13}, - {0x00,0x40,0x80,0x14}, {0x00,0x40,0xa0,0x15}, {0x00,0x40,0xc0,0x16}, {0x00,0x40,0xe0,0x17}, - {0x00,0x60,0x00,0x18}, {0x00,0x60,0x20,0x19}, {0x00,0x60,0x40,0x1a}, {0x00,0x60,0x60,0x1b}, - {0x00,0x60,0x80,0x1c}, {0x00,0x60,0xa0,0x1d}, {0x00,0x60,0xc0,0x1e}, {0x00,0x60,0xe0,0x1f}, - - {0x00,0x80,0x00,0x20}, {0x00,0x80,0x20,0x21}, {0x00,0x80,0x40,0x22}, {0x00,0x80,0x60,0x23}, - {0x00,0x80,0x80,0x24}, {0x00,0x80,0xa0,0x25}, {0x00,0x80,0xc0,0x26}, {0x00,0x80,0xe0,0x27}, - {0x00,0xa0,0x00,0x28}, {0x00,0xa0,0x20,0x29}, {0x00,0xa0,0x40,0x2a}, {0x00,0xa0,0x60,0x2b}, - {0x00,0xa0,0x80,0x2c}, {0x00,0xa0,0xa0,0x2d}, {0x00,0xa0,0xc0,0x2e}, {0x00,0xa0,0xe0,0x2f}, - - {0x00,0xc0,0x00,0x30}, {0x00,0xc0,0x20,0x31}, {0x00,0xc0,0x40,0x32}, {0x00,0xc0,0x60,0x33}, - {0x00,0xc0,0x80,0x34}, {0x00,0xc0,0xa0,0x35}, {0x00,0xc0,0xc0,0x36}, {0x00,0xc0,0xe0,0x37}, - {0x00,0xe0,0x00,0x38}, {0x00,0xe0,0x20,0x39}, {0x00,0xe0,0x40,0x3a}, {0x00,0xe0,0x60,0x3b}, - {0x00,0xe0,0x80,0x3c}, {0x00,0xe0,0xa0,0x3d}, {0x00,0xe0,0xc0,0x3e}, {0x00,0xe0,0xe0,0x3f}, - - {0x40,0x00,0x00,0x40}, {0x40,0x00,0x20,0x41}, {0x40,0x00,0x40,0x42}, {0x40,0x00,0x60,0x43}, - {0x40,0x00,0x80,0x44}, {0x40,0x00,0xa0,0x45}, {0x40,0x00,0xc0,0x46}, {0x40,0x00,0xe0,0x47}, - {0x40,0x20,0x00,0x48}, {0x40,0x20,0x20,0x49}, {0x40,0x20,0x40,0x4a}, {0x40,0x20,0x60,0x4b}, - {0x40,0x20,0x80,0x4c}, {0x40,0x20,0xa0,0x4d}, {0x40,0x20,0xc0,0x4e}, {0x40,0x20,0xe0,0x4f}, - - {0x40,0x40,0x00,0x50}, {0x40,0x40,0x20,0x51}, {0x40,0x40,0x40,0x52}, {0x40,0x40,0x60,0x53}, - {0x40,0x40,0x80,0x54}, {0x40,0x40,0xa0,0x55}, {0x40,0x40,0xc0,0x56}, {0x40,0x40,0xe0,0x57}, - {0x40,0x60,0x00,0x58}, {0x40,0x60,0x20,0x59}, {0x40,0x60,0x40,0x5a}, {0x40,0x60,0x60,0x5b}, - {0x40,0x60,0x80,0x5c}, {0x40,0x60,0xa0,0x5d}, {0x40,0x60,0xc0,0x5e}, {0x40,0x60,0xe0,0x5f}, - - {0x40,0x80,0x00,0x60}, {0x40,0x80,0x20,0x61}, {0x40,0x80,0x40,0x62}, {0x40,0x80,0x60,0x63}, - {0x40,0x80,0x80,0x64}, {0x40,0x80,0xa0,0x65}, {0x40,0x80,0xc0,0x66}, {0x40,0x80,0xe0,0x67}, - {0x40,0xa0,0x00,0x68}, {0x40,0xa0,0x20,0x69}, {0x40,0xa0,0x40,0x6a}, {0x40,0xa0,0x60,0x6b}, - {0x40,0xa0,0x80,0x6c}, {0x40,0xa0,0xa0,0x6d}, {0x40,0xa0,0xc0,0x6e}, {0x40,0xa0,0xe0,0x6f}, - - {0x40,0xc0,0x00,0x70}, {0x40,0xc0,0x20,0x71}, {0x40,0xc0,0x40,0x72}, {0x40,0xc0,0x60,0x73}, - {0x40,0xc0,0x80,0x74}, {0x40,0xc0,0xa0,0x75}, {0x40,0xc0,0xc0,0x76}, {0x40,0xc0,0xe0,0x77}, - {0x40,0xe0,0x00,0x78}, {0x40,0xe0,0x20,0x79}, {0x40,0xe0,0x40,0x7a}, {0x40,0xe0,0x60,0x7b}, - {0x40,0xe0,0x80,0x7c}, {0x40,0xe0,0xa0,0x7d}, {0x40,0xe0,0xc0,0x7e}, {0x40,0xe0,0xe0,0x7f}, - - {0x80,0x00,0x00,0x80}, {0x80,0x00,0x20,0x81}, {0x80,0x00,0x40,0x82}, {0x80,0x00,0x60,0x83}, - {0x80,0x00,0x80,0x84}, {0x80,0x00,0xa0,0x85}, {0x80,0x00,0xc0,0x86}, {0x80,0x00,0xe0,0x87}, - {0x80,0x20,0x00,0x88}, {0x80,0x20,0x20,0x89}, {0x80,0x20,0x40,0x8a}, {0x80,0x20,0x60,0x8b}, - {0x80,0x20,0x80,0x8c}, {0x80,0x20,0xa0,0x8d}, {0x80,0x20,0xc0,0x8e}, {0x80,0x20,0xe0,0x8f}, - - {0x80,0x40,0x00,0x90}, {0x80,0x40,0x20,0x91}, {0x80,0x40,0x40,0x92}, {0x80,0x40,0x60,0x93}, - {0x80,0x40,0x80,0x94}, {0x80,0x40,0xa0,0x95}, {0x80,0x40,0xc0,0x96}, {0x80,0x40,0xe0,0x97}, - {0x80,0x60,0x00,0x98}, {0x80,0x60,0x20,0x99}, {0x80,0x60,0x40,0x9a}, {0x80,0x60,0x60,0x9b}, - {0x80,0x60,0x80,0x9c}, {0x80,0x60,0xa0,0x9d}, {0x80,0x60,0xc0,0x9e}, {0x80,0x60,0xe0,0x9f}, - - {0x80,0x80,0x00,0xa0}, {0x80,0x80,0x20,0xa1}, {0x80,0x80,0x40,0xa2}, {0x80,0x80,0x60,0xa3}, - {0x80,0x80,0x80,0xa4}, {0x80,0x80,0xa0,0xa5}, {0x80,0x80,0xc0,0xa6}, {0x80,0x80,0xe0,0xa7}, - {0x80,0xa0,0x00,0xa8}, {0x80,0xa0,0x20,0xa9}, {0x80,0xa0,0x40,0xaa}, {0x80,0xa0,0x60,0xab}, - {0x80,0xa0,0x80,0xac}, {0x80,0xa0,0xa0,0xad}, {0x80,0xa0,0xc0,0xae}, {0x80,0xa0,0xe0,0xaf}, - - {0x80,0xc0,0x00,0xb0}, {0x80,0xc0,0x20,0xb1}, {0x80,0xc0,0x40,0xb2}, {0x80,0xc0,0x60,0xb3}, - {0x80,0xc0,0x80,0xb4}, {0x80,0xc0,0xa0,0xb5}, {0x80,0xc0,0xc0,0xb6}, {0x80,0xc0,0xe0,0xb7}, - {0x80,0xe0,0x00,0xb8}, {0x80,0xe0,0x20,0xb9}, {0x80,0xe0,0x40,0xba}, {0x80,0xe0,0x60,0xbb}, - {0x80,0xe0,0x80,0xbc}, {0x80,0xe0,0xa0,0xbd}, {0x80,0xe0,0xc0,0xbe}, {0x80,0xe0,0xe0,0xbf}, - - {0xc0,0x00,0x00,0xc0}, {0xc0,0x00,0x20,0xc1}, {0xc0,0x00,0x40,0xc2}, {0xc0,0x00,0x60,0xc3}, - {0xc0,0x00,0x80,0xc4}, {0xc0,0x00,0xa0,0xc5}, {0xc0,0x00,0xc0,0xc6}, {0xc0,0x00,0xe0,0xc7}, - {0xc0,0x20,0x00,0xc8}, {0xc0,0x20,0x20,0xc9}, {0xc0,0x20,0x40,0xca}, {0xc0,0x20,0x60,0xcb}, - {0xc0,0x20,0x80,0xcc}, {0xc0,0x20,0xa0,0xcd}, {0xc0,0x20,0xc0,0xce}, {0xc0,0x20,0xe0,0xcf}, - - {0xc0,0x40,0x00,0xd0}, {0xc0,0x40,0x20,0xd1}, {0xc0,0x40,0x40,0xd2}, {0xc0,0x40,0x60,0xd3}, - {0xc0,0x40,0x80,0xd4}, {0xc0,0x40,0xa0,0xd5}, {0xc0,0x40,0xc0,0xd6}, {0xc0,0x40,0xe0,0xd7}, - {0xc0,0x60,0x00,0xd8}, {0xc0,0x60,0x20,0xd9}, {0xc0,0x60,0x40,0xda}, {0xc0,0x60,0x60,0xdb}, - {0xc0,0x60,0x80,0xdc}, {0xc0,0x60,0xa0,0xdd}, {0xc0,0x60,0xc0,0xde}, {0xc0,0x60,0xe0,0xdf}, - - {0xc0,0x80,0x00,0xe0}, {0xc0,0x80,0x20,0xe1}, {0xc0,0x80,0x40,0xe2}, {0xc0,0x80,0x60,0xe3}, - {0xc0,0x80,0x80,0xe4}, {0xc0,0x80,0xa0,0xe5}, {0xc0,0x80,0xc0,0xe6}, {0xc0,0x80,0xe0,0xe7}, - {0xc0,0xa0,0x00,0xe8}, {0xc0,0xa0,0x20,0xe9}, {0xc0,0xa0,0x40,0xea}, {0xc0,0xa0,0x60,0xeb}, - {0xc0,0xa0,0x80,0xec}, {0xc0,0xa0,0xa0,0xed}, {0xc0,0xa0,0xc0,0xee}, {0xc0,0xa0,0xe0,0xef}, - - {0xc0,0xc0,0x00,0xf0}, {0xc0,0xc0,0x20,0xf1}, {0xc0,0xc0,0x40,0xf2}, {0xc0,0xc0,0x60,0xf3}, - {0xc0,0xc0,0x80,0xf4}, {0xc0,0xc0,0xa0,0xf5}, {0xf0,0xfb,0xff,0xf6}, {0xa4,0xa0,0xa0,0xf7}, - {0x80,0x80,0x80,0xf8}, {0x00,0x00,0xff,0xf9}, {0x00,0xff,0x00,0xfa}, {0x00,0xff,0xff,0xfb}, - {0xff,0x00,0x00,0xfc}, {0xff,0x00,0xff,0xfd}, {0xff,0xff,0x00,0xfe}, {0xff,0xff,0xff,0xff}, -}; - static const uint16_t v16u16_2_2[] = { 0x0000, 0x3000, 0x4000, 0x7fff, 0x8000, 0x8001, 0xc000, 0xffff, diff --git a/dlls/d3dx9_36/tests/texture.c b/dlls/d3dx9_36/tests/texture.c index a4512967835..37d1649f8a2 100644 --- a/dlls/d3dx9_36/tests/texture.c +++ b/dlls/d3dx9_36/tests/texture.c @@ -25,6 +25,7 @@ #include "d3dx9tex.h" #include "resources.h" #include <stdint.h> +#include <assert.h> #include "d3dx9_test_images.h"
static int has_2d_dxt1, has_2d_dxt3, has_2d_dxt5, has_cube_dxt5, has_3d_dxt3; @@ -3137,6 +3138,195 @@ static void WINAPI fill_func(D3DXVECTOR4 *value, const D3DXVECTOR2 *coord, const *value = quadrant_color[idx]; }
+static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) +{ + static const struct + { + D3DRESOURCETYPE type; + D3DFORMAT format; + D3DPOOL pool; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t mip_levels; + const PALETTEENTRY *palette; + + HRESULT expected_hr; + struct dds_pixel_format expected_pixel_format; + uint32_t expected_flags; + uint32_t expected_width; + uint32_t expected_height; + uint32_t expected_pitch; + uint32_t expected_depth; + uint32_t expected_mip_levels; + uint32_t expected_caps; + uint32_t expected_caps2; + uint32_t expected_buffer_size; + BOOL todo_hr; + } tests[] = + { + /* Paletted format tests. */ + { + D3DRTYPE_TEXTURE, D3DFMT_P8, D3DPOOL_SCRATCH, 4, 4, 0, 3, test_palette, D3D_OK, + { 32, DDS_PF_INDEXED, 0, 8, 0, 0, 0, 0 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, + (DDSCAPS_TEXTURE | DDSCAPS_PALETTE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX), + 0, PALETTED_DDS_FILE_HEADER_SIZE + 21, + .todo_hr = TRUE + }, + { + D3DRTYPE_CUBETEXTURE, D3DFMT_P8, D3DPOOL_SCRATCH, 4, 0, 0, 3, test_palette, D3D_OK, + { 32, DDS_PF_INDEXED, 0, 8, 0, 0, 0, 0 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, + (DDSCAPS_TEXTURE | DDSCAPS_PALETTE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX), + (DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES), PALETTED_DDS_FILE_HEADER_SIZE + 126, + .todo_hr = TRUE + }, + { + D3DRTYPE_VOLUMETEXTURE, D3DFMT_P8, D3DPOOL_SCRATCH, 4, 4, 4, 3, test_palette, D3D_OK, + { 32, DDS_PF_INDEXED, 0, 8, 0, 0, 0, 0 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT | DDSD_DEPTH), 4, 4, 0, 4, 3, + (DDSCAPS_TEXTURE | DDSCAPS_PALETTE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX), + DDSCAPS2_VOLUME, PALETTED_DDS_FILE_HEADER_SIZE + 73, + .todo_hr = TRUE + }, + /* D3DFMT_A8R8G8B8 textures with multiple levels. */ + { + D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 4, 0, 3, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, + (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX | DDSCAPS_ALPHA), + 0, DDS_FILE_HEADER_SIZE + 84, + .todo_hr = TRUE + }, + { + D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 0, 0, 3, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, + (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_ALPHA | DDSCAPS_COMPLEX), + (DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES), DDS_FILE_HEADER_SIZE + 504, + .todo_hr = TRUE + }, + /* 5 */ + /* + * Volume texture with D3DPOOL default. Can't be mapped for read, + * can't be saved. + */ + { + D3DRTYPE_VOLUMETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 4, 4, 3, NULL, D3DERR_INVALIDCALL, + .todo_hr = TRUE + }, + /* D3DPOOL_SYSTEMMEM can be saved. */ + { + D3DRTYPE_VOLUMETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, 4, 4, 4, 3, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_DEPTH | DDSD_MIPMAPCOUNT), 4, 4, 0, 4, 3, + (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_ALPHA | DDSCAPS_COMPLEX), + DDSCAPS2_VOLUME, DDS_FILE_HEADER_SIZE + 292, + .todo_hr = TRUE + }, + /* Single mip level, no mip flags. */ + { + D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 4, 0, 1, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), 4, 4, 0, 0, 0, + (DDSCAPS_TEXTURE | DDSCAPS_ALPHA), + 0, DDS_FILE_HEADER_SIZE + 64, + .todo_hr = TRUE + }, + { + D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 0, 0, 1, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), 4, 4, 0, 0, 0, + (DDSCAPS_TEXTURE | DDSCAPS_ALPHA | DDSCAPS_COMPLEX), + (DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES), DDS_FILE_HEADER_SIZE + 384, + .todo_hr = TRUE + }, + { + D3DRTYPE_VOLUMETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, 4, 4, 4, 1, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_DEPTH), 4, 4, 0, 4, 0, + (DDSCAPS_TEXTURE | DDSCAPS_ALPHA), + DDSCAPS2_VOLUME, DDS_FILE_HEADER_SIZE + 256, + .todo_hr = TRUE + }, + /* 10. */ + /* Volume texture with a depth of 1. */ + { + D3DRTYPE_VOLUMETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, 4, 4, 1, 1, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), 4, 4, 0, 0, 0, + (DDSCAPS_TEXTURE | DDSCAPS_ALPHA), + 0, DDS_FILE_HEADER_SIZE + 64, + .todo_hr = TRUE + }, + }; + struct + { + DWORD magic; + struct dds_header header; + BYTE *data; + } *dds; + IDirect3DVolumeTexture9 *volume_texture; + IDirect3DCubeTexture9 *cube_texture; + IDirect3DBaseTexture9 *save_tex; + IDirect3DTexture9 *texture; + ID3DXBuffer *buffer; + unsigned int i; + HRESULT hr; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("Test %u", i); + + switch (tests[i].type) + { + case D3DRTYPE_TEXTURE: + hr = IDirect3DDevice9_CreateTexture(device, tests[i].width, tests[i].height, tests[i].mip_levels, 0, + tests[i].format, tests[i].pool, &texture, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + save_tex = (IDirect3DBaseTexture9 *)texture; + break; + + case D3DRTYPE_CUBETEXTURE: + hr = IDirect3DDevice9_CreateCubeTexture(device, tests[i].width, tests[i].mip_levels, 0, + tests[i].format, tests[i].pool, &cube_texture, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + save_tex = (IDirect3DBaseTexture9 *)cube_texture; + break; + + case D3DRTYPE_VOLUMETEXTURE: + hr = IDirect3DDevice9_CreateVolumeTexture(device, tests[i].width, tests[i].height, tests[i].depth, + tests[i].mip_levels, 0, tests[i].format, tests[i].pool, &volume_texture, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + save_tex = (IDirect3DBaseTexture9 *)volume_texture; + break; + + default: + assert(0); + break; + } + + hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, save_tex, tests[i].palette); + todo_wine_if(tests[i].todo_hr) ok(hr == tests[i].expected_hr, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + ok(ID3DXBuffer_GetBufferSize(buffer) == tests[i].expected_buffer_size, "Unexpected buffer size %lu.\n", + ID3DXBuffer_GetBufferSize(buffer)); + + dds = ID3DXBuffer_GetBufferPointer(buffer); + check_dds_header(&dds->header, tests[i].expected_flags, tests[i].expected_height, tests[i].expected_width, + tests[i].expected_pitch, tests[i].expected_depth, tests[i].expected_mip_levels, + &tests[i].expected_pixel_format, tests[i].expected_caps, tests[i].expected_caps2, + FALSE); + ID3DXBuffer_Release(buffer); + } + + IDirect3DBaseTexture9_Release(save_tex); + winetest_pop_context(); + } +} + static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) { const D3DXVECTOR4 clear_val = { 0.0f, 0.0f, 0.0f, 0.0f }; @@ -3369,6 +3559,8 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) release_surface_readback(&rb);
IDirect3DTexture9_Release(texture); + + test_save_texture_to_dds_file(device); }
static void test_texture_shader(void)
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 78 +++++++++++++++++++ dlls/d3dx9_36/surface.c | 86 +++------------------ dlls/d3dx9_36/tests/texture.c | 29 +++----- dlls/d3dx9_36/texture.c | 136 ++++++++++++++++++++++++++++------ 4 files changed, 214 insertions(+), 115 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 7da9f9dd788..0e965eb6017 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -50,6 +50,80 @@ static inline HRESULT d3dx9_handle_load_filter(DWORD *filter) return d3dx9_validate_filter(*filter); }
+#define DDS_PALETTE_SIZE (sizeof(PALETTEENTRY) * 256) + +/* dds_header.flags */ +#define DDS_CAPS 0x1 +#define DDS_HEIGHT 0x2 +#define DDS_WIDTH 0x4 +#define DDS_PITCH 0x8 +#define DDS_PIXELFORMAT 0x1000 +#define DDS_MIPMAPCOUNT 0x20000 +#define DDS_LINEARSIZE 0x80000 +#define DDS_DEPTH 0x800000 + +/* dds_header.caps */ +#define DDSCAPS_ALPHA 0x2 +#define DDS_CAPS_COMPLEX 0x8 +#define DDSCAPS_PALETTE 0x100 +#define DDS_CAPS_TEXTURE 0x1000 +#define DDS_CAPS_MIPMAP 0x400000 + +/* dds_header.caps2 */ +#define DDS_CAPS2_CUBEMAP 0x200 +#define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400 +#define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800 +#define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000 +#define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x2000 +#define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x4000 +#define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x8000 +#define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \ + | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \ + | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ ) +#define DDS_CAPS2_VOLUME 0x200000 + +/* dds_pixel_format.flags */ +#define DDS_PF_ALPHA 0x1 +#define DDS_PF_ALPHA_ONLY 0x2 +#define DDS_PF_FOURCC 0x4 +#define DDS_PF_INDEXED 0x20 +#define DDS_PF_RGB 0x40 +#define DDS_PF_YUV 0x200 +#define DDS_PF_LUMINANCE 0x20000 +#define DDS_PF_BUMPLUMINANCE 0x40000 +#define DDS_PF_BUMPDUDV 0x80000 + +struct dds_pixel_format +{ + DWORD size; + DWORD flags; + DWORD fourcc; + DWORD bpp; + DWORD rmask; + DWORD gmask; + DWORD bmask; + DWORD amask; +}; + +struct dds_header +{ + DWORD signature; + DWORD size; + DWORD flags; + DWORD height; + DWORD width; + DWORD pitch_or_linear_size; + DWORD depth; + DWORD miplevels; + DWORD reserved[11]; + struct dds_pixel_format pixel_format; + DWORD caps; + DWORD caps2; + DWORD caps3; + DWORD caps4; + DWORD reserved2; +}; + struct vec4 { float x, y, z, w; @@ -316,6 +390,10 @@ HRESULT lock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, D3DLO IDirect3DSurface9 **temp_surface, BOOL write); HRESULT unlock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, IDirect3DSurface9 *temp_surface, BOOL update); +uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, + uint32_t depth, uint32_t mip_levels); +HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource_type, + enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels); HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, D3DXIMAGE_FILEFORMAT file_format, ID3DXBuffer **dst_buffer); const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format); diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index e5a9207ad91..3af573fb0e9 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -78,80 +78,6 @@ static const GUID *wic_guid_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id return NULL; }
-#define DDS_PALETTE_SIZE (sizeof(PALETTEENTRY) * 256) - -/* dds_header.flags */ -#define DDS_CAPS 0x1 -#define DDS_HEIGHT 0x2 -#define DDS_WIDTH 0x4 -#define DDS_PITCH 0x8 -#define DDS_PIXELFORMAT 0x1000 -#define DDS_MIPMAPCOUNT 0x20000 -#define DDS_LINEARSIZE 0x80000 -#define DDS_DEPTH 0x800000 - -/* dds_header.caps */ -#define DDSCAPS_ALPHA 0x2 -#define DDS_CAPS_COMPLEX 0x8 -#define DDSCAPS_PALETTE 0x100 -#define DDS_CAPS_TEXTURE 0x1000 -#define DDS_CAPS_MIPMAP 0x400000 - -/* dds_header.caps2 */ -#define DDS_CAPS2_CUBEMAP 0x200 -#define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400 -#define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800 -#define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000 -#define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x2000 -#define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x4000 -#define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x8000 -#define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \ - | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \ - | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ ) -#define DDS_CAPS2_VOLUME 0x200000 - -/* dds_pixel_format.flags */ -#define DDS_PF_ALPHA 0x1 -#define DDS_PF_ALPHA_ONLY 0x2 -#define DDS_PF_FOURCC 0x4 -#define DDS_PF_INDEXED 0x20 -#define DDS_PF_RGB 0x40 -#define DDS_PF_YUV 0x200 -#define DDS_PF_LUMINANCE 0x20000 -#define DDS_PF_BUMPLUMINANCE 0x40000 -#define DDS_PF_BUMPDUDV 0x80000 - -struct dds_pixel_format -{ - DWORD size; - DWORD flags; - DWORD fourcc; - DWORD bpp; - DWORD rmask; - DWORD gmask; - DWORD bmask; - DWORD amask; -}; - -struct dds_header -{ - DWORD signature; - DWORD size; - DWORD flags; - DWORD height; - DWORD width; - DWORD pitch_or_linear_size; - DWORD depth; - DWORD miplevels; - DWORD reserved[11]; - struct dds_pixel_format pixel_format; - DWORD caps; - DWORD caps2; - DWORD caps3; - DWORD caps4; - DWORD reserved2; -}; - #define TGA_IMAGETYPE_COLORMAPPED 1 #define TGA_IMAGETYPE_TRUECOLOR 2 #define TGA_IMAGETYPE_GRAYSCALE 3 @@ -473,7 +399,7 @@ static HRESULT d3dx_calculate_pixels_size(enum d3dx_pixel_format_id format, uint return D3D_OK; }
-static uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, uint32_t depth, +uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, uint32_t depth, uint32_t mip_levels) { uint32_t layer_size, row_pitch, slice_pitch, i; @@ -491,7 +417,7 @@ static uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id forma return layer_size; }
-static HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource_type, +HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource_type, enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels) { HRESULT hr; @@ -514,6 +440,14 @@ static HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE r header->depth = size->depth; header->caps2 |= DDS_CAPS2_VOLUME; } + + if (mip_levels > 1) + { + header->flags |= DDS_MIPMAPCOUNT; + header->caps |= (DDS_CAPS_MIPMAP | DDS_CAPS_COMPLEX); + header->miplevels = mip_levels; + } + if (header->pixel_format.flags & DDS_PF_ALPHA || header->pixel_format.flags & DDS_PF_ALPHA_ONLY) header->caps |= DDSCAPS_ALPHA; if (header->pixel_format.flags & DDS_PF_INDEXED) diff --git a/dlls/d3dx9_36/tests/texture.c b/dlls/d3dx9_36/tests/texture.c index 37d1649f8a2..10f669e0cff 100644 --- a/dlls/d3dx9_36/tests/texture.c +++ b/dlls/d3dx9_36/tests/texture.c @@ -3172,7 +3172,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, (DDSCAPS_TEXTURE | DDSCAPS_PALETTE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX), 0, PALETTED_DDS_FILE_HEADER_SIZE + 21, - .todo_hr = TRUE }, { D3DRTYPE_CUBETEXTURE, D3DFMT_P8, D3DPOOL_SCRATCH, 4, 0, 0, 3, test_palette, D3D_OK, @@ -3197,7 +3196,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX | DDSCAPS_ALPHA), 0, DDS_FILE_HEADER_SIZE + 84, - .todo_hr = TRUE }, { D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 0, 0, 3, NULL, D3D_OK, @@ -3232,7 +3230,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), 4, 4, 0, 0, 0, (DDSCAPS_TEXTURE | DDSCAPS_ALPHA), 0, DDS_FILE_HEADER_SIZE + 64, - .todo_hr = TRUE }, { D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 0, 0, 1, NULL, D3D_OK, @@ -3370,24 +3367,20 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) } }
- todo_wine { hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, (IDirect3DBaseTexture9 *)texture, NULL); ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); - if (SUCCEEDED(hr)) - { - buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); - buffer_size = ID3DXBuffer_GetBufferSize(buffer); - hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); - ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK);
- ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); - ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); - ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); - ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE); - ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); - ID3DXBuffer_Release(buffer); - } - } + buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); + buffer_size = ID3DXBuffer_GetBufferSize(buffer); + hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); + ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); + + ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); + ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); + ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); + ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE); + ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); + ID3DXBuffer_Release(buffer);
IDirect3DTexture9_Release(texture);
diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index 4b4192dc8b6..00309904206 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -1856,25 +1856,39 @@ HRESULT WINAPI D3DXSaveTextureToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette) { - HRESULT hr; + const struct pixel_format_desc *fmt_desc = NULL; + unsigned int levels, file_size, i; + struct d3dx_image image; D3DRESOURCETYPE type; + ID3DXBuffer *buffer; + struct volume size; + HRESULT hr;
TRACE("dst_buffer %p, file_format %u, src_texture %p, src_palette %p.\n", dst_buffer, file_format, src_texture, src_palette);
- if (!dst_buffer || !src_texture) return D3DERR_INVALIDCALL; - - if (file_format == D3DXIFF_DDS) - { - FIXME("DDS file format isn't supported yet\n"); - return E_NOTIMPL; - } + if (!dst_buffer || !src_texture || file_format > D3DXIFF_PFM) + return D3DERR_INVALIDCALL;
+ *dst_buffer = buffer = NULL; type = IDirect3DBaseTexture9_GetType(src_texture); - switch (type) + if (type < D3DRTYPE_TEXTURE || type > D3DRTYPE_CUBETEXTURE) + return D3DERR_INVALIDCALL; + + if (file_format != D3DXIFF_DDS) { - case D3DRTYPE_TEXTURE: - case D3DRTYPE_CUBETEXTURE: + if (type == D3DRTYPE_VOLUMETEXTURE) + { + IDirect3DVolume9 *volume; + + hr = IDirect3DVolumeTexture9_GetVolumeLevel((IDirect3DVolumeTexture9 *)src_texture, 0, &volume); + if (SUCCEEDED(hr)) + { + hr = D3DXSaveVolumeToFileInMemory(dst_buffer, file_format, volume, src_palette, NULL); + IDirect3DVolume9_Release(volume); + } + } + else { IDirect3DSurface9 *surface;
@@ -1884,26 +1898,106 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE hr = D3DXSaveSurfaceToFileInMemory(dst_buffer, file_format, surface, src_palette, NULL); IDirect3DSurface9_Release(surface); } - break; }
- case D3DRTYPE_VOLUMETEXTURE: + return hr; + } + + levels = IDirect3DBaseTexture9_GetLevelCount(src_texture); + switch (type) + { + case D3DRTYPE_TEXTURE: { - IDirect3DVolume9 *volume; + IDirect3DTexture9 *texture = (IDirect3DTexture9 *)src_texture; + D3DSURFACE_DESC desc;
- hr = IDirect3DVolumeTexture9_GetVolumeLevel((IDirect3DVolumeTexture9 *)src_texture, 0, &volume); - if (SUCCEEDED(hr)) - { - hr = D3DXSaveVolumeToFileInMemory(dst_buffer, file_format, volume, src_palette, NULL); - IDirect3DVolume9_Release(volume); - } + hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc); + if (FAILED(hr)) + break; + + fmt_desc = get_format_info(desc.Format); + if (is_unknown_format(fmt_desc)) + return E_NOTIMPL; + + set_volume_struct(&size, desc.Width, desc.Height, 1); break; }
default: - return D3DERR_INVALIDCALL; + return E_NOTIMPL; + } + + if (is_index_format(fmt_desc) && !src_palette) + return E_NOTIMPL; + + file_size = d3dx_calculate_layer_pixels_size(fmt_desc->format, size.width, size.height, size.depth, levels); + file_size += is_index_format(fmt_desc) ? sizeof(struct dds_header) + DDS_PALETTE_SIZE : sizeof(struct dds_header); + + hr = D3DXCreateBuffer(file_size, &buffer); + if (FAILED(hr)) + return hr; + + hr = d3dx_init_dds_header((struct dds_header *)ID3DXBuffer_GetBufferPointer(buffer), type, fmt_desc->format, &size, + levels); + if (FAILED(hr)) + goto exit; + + if (is_index_format(fmt_desc)) + memcpy((uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + sizeof(struct dds_header), src_palette, + DDS_PALETTE_SIZE); + + hr = d3dx_image_init(ID3DXBuffer_GetBufferPointer(buffer), ID3DXBuffer_GetBufferSize(buffer), &image, 0, 0); + if (FAILED(hr)) + goto exit; + + for (i = 0; i < levels; ++i) + { + IDirect3DSurface9 *src_surface, *tmp_surface; + struct d3dx_pixels src_pixels, dst_pixels; + D3DSURFACE_DESC src_surface_desc; + D3DLOCKED_RECT src_locked_rect; + RECT src_rect; + + hr = d3dx_image_get_pixels(&image, 0, i, &dst_pixels); + if (FAILED(hr)) + goto exit; + + hr = get_surface(type, src_texture, 0, i, &src_surface); + if (FAILED(hr)) + goto exit; + + hr = lock_surface(src_surface, NULL, &src_locked_rect, &tmp_surface, FALSE); + if (FAILED(hr)) + { + IDirect3DSurface9_Release(src_surface); + goto exit; + } + + IDirect3DTexture9_GetLevelDesc((IDirect3DTexture9 *)src_texture, i, &src_surface_desc); + SetRect(&src_rect, 0, 0, src_surface_desc.Width, src_surface_desc.Height); + set_d3dx_pixels(&src_pixels, src_locked_rect.pBits, src_locked_rect.Pitch, 0, src_palette, + src_surface_desc.Width, src_surface_desc.Height, 1, &src_rect); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, fmt_desc, D3DX_FILTER_NONE, 0); + if (FAILED(hr)) + { + unlock_surface(src_surface, NULL, tmp_surface, FALSE); + IDirect3DSurface9_Release(src_surface); + goto exit; + } + + hr = unlock_surface(src_surface, NULL, tmp_surface, FALSE); + IDirect3DSurface9_Release(src_surface); + if (FAILED(hr)) + goto exit; }
+ *dst_buffer = buffer; + +exit: + if (buffer && (buffer != *dst_buffer)) + ID3DXBuffer_Release(buffer); + return hr; }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 6 +++ dlls/d3dx9_36/tests/texture.c | 29 +++++------- dlls/d3dx9_36/texture.c | 89 ++++++++++++++++++++++------------- 3 files changed, 73 insertions(+), 51 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 3af573fb0e9..e3bc77bd52e 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -448,6 +448,12 @@ HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource header->miplevels = mip_levels; }
+ if (resource_type == D3DRTYPE_CUBETEXTURE) + { + header->caps |= DDS_CAPS_COMPLEX; + header->caps2 |= (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES); + } + if (header->pixel_format.flags & DDS_PF_ALPHA || header->pixel_format.flags & DDS_PF_ALPHA_ONLY) header->caps |= DDSCAPS_ALPHA; if (header->pixel_format.flags & DDS_PF_INDEXED) diff --git a/dlls/d3dx9_36/tests/texture.c b/dlls/d3dx9_36/tests/texture.c index 10f669e0cff..622d4ebc2e7 100644 --- a/dlls/d3dx9_36/tests/texture.c +++ b/dlls/d3dx9_36/tests/texture.c @@ -3179,7 +3179,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, (DDSCAPS_TEXTURE | DDSCAPS_PALETTE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX), (DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES), PALETTED_DDS_FILE_HEADER_SIZE + 126, - .todo_hr = TRUE }, { D3DRTYPE_VOLUMETEXTURE, D3DFMT_P8, D3DPOOL_SCRATCH, 4, 4, 4, 3, test_palette, D3D_OK, @@ -3203,7 +3202,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_ALPHA | DDSCAPS_COMPLEX), (DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES), DDS_FILE_HEADER_SIZE + 504, - .todo_hr = TRUE }, /* 5 */ /* @@ -3237,7 +3235,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), 4, 4, 0, 0, 0, (DDSCAPS_TEXTURE | DDSCAPS_ALPHA | DDSCAPS_COMPLEX), (DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES), DDS_FILE_HEADER_SIZE + 384, - .todo_hr = TRUE }, { D3DRTYPE_VOLUMETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, 4, 4, 4, 1, NULL, D3D_OK, @@ -3433,24 +3430,20 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) ID3DXBuffer_Release(buffer); }
- todo_wine { hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, (IDirect3DBaseTexture9 *)cube_texture, NULL); ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); - if (SUCCEEDED(hr)) - { - buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); - buffer_size = ID3DXBuffer_GetBufferSize(buffer); - hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); - ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK);
- ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); - ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); - ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); - ok(info.ResourceType == D3DRTYPE_CUBETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_CUBETEXTURE); - ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); - ID3DXBuffer_Release(buffer); - } - } + buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); + buffer_size = ID3DXBuffer_GetBufferSize(buffer); + hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); + ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); + + ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); + ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); + ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); + ok(info.ResourceType == D3DRTYPE_CUBETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_CUBETEXTURE); + ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); + ID3DXBuffer_Release(buffer);
IDirect3DCubeTexture9_Release(cube_texture);
diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index 00309904206..25f8ef6c6b4 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -1857,7 +1857,7 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette) { const struct pixel_format_desc *fmt_desc = NULL; - unsigned int levels, file_size, i; + unsigned int levels, file_size, i, j; struct d3dx_image image; D3DRESOURCETYPE type; ID3DXBuffer *buffer; @@ -1923,6 +1923,24 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE break; }
+ case D3DRTYPE_CUBETEXTURE: + { + IDirect3DCubeTexture9 *texture = (IDirect3DCubeTexture9 *)src_texture; + D3DSURFACE_DESC desc; + + hr = IDirect3DCubeTexture9_GetLevelDesc(texture, 0, &desc); + if (FAILED(hr)) + break; + + fmt_desc = get_format_info(desc.Format); + if (is_unknown_format(fmt_desc)) + return E_NOTIMPL; + + set_volume_struct(&size, desc.Width, desc.Height, 1); + break; + } + + default: return E_NOTIMPL; } @@ -1931,6 +1949,8 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE return E_NOTIMPL;
file_size = d3dx_calculate_layer_pixels_size(fmt_desc->format, size.width, size.height, size.depth, levels); + if (type == D3DRTYPE_CUBETEXTURE) + file_size *= 6; file_size += is_index_format(fmt_desc) ? sizeof(struct dds_header) + DDS_PALETTE_SIZE : sizeof(struct dds_header);
hr = D3DXCreateBuffer(file_size, &buffer); @@ -1950,46 +1970,49 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE if (FAILED(hr)) goto exit;
- for (i = 0; i < levels; ++i) + for (j = 0; j < image.layer_count; ++j) { - IDirect3DSurface9 *src_surface, *tmp_surface; - struct d3dx_pixels src_pixels, dst_pixels; - D3DSURFACE_DESC src_surface_desc; - D3DLOCKED_RECT src_locked_rect; - RECT src_rect; + for (i = 0; i < levels; ++i) + { + IDirect3DSurface9 *src_surface, *tmp_surface; + struct d3dx_pixels src_pixels, dst_pixels; + D3DSURFACE_DESC src_surface_desc; + D3DLOCKED_RECT src_locked_rect; + RECT src_rect;
- hr = d3dx_image_get_pixels(&image, 0, i, &dst_pixels); - if (FAILED(hr)) - goto exit; + hr = d3dx_image_get_pixels(&image, j, i, &dst_pixels); + if (FAILED(hr)) + goto exit;
- hr = get_surface(type, src_texture, 0, i, &src_surface); - if (FAILED(hr)) - goto exit; + hr = get_surface(type, src_texture, j, i, &src_surface); + if (FAILED(hr)) + goto exit;
- hr = lock_surface(src_surface, NULL, &src_locked_rect, &tmp_surface, FALSE); - if (FAILED(hr)) - { - IDirect3DSurface9_Release(src_surface); - goto exit; - } + hr = lock_surface(src_surface, NULL, &src_locked_rect, &tmp_surface, FALSE); + if (FAILED(hr)) + { + IDirect3DSurface9_Release(src_surface); + goto exit; + }
- IDirect3DTexture9_GetLevelDesc((IDirect3DTexture9 *)src_texture, i, &src_surface_desc); - SetRect(&src_rect, 0, 0, src_surface_desc.Width, src_surface_desc.Height); - set_d3dx_pixels(&src_pixels, src_locked_rect.pBits, src_locked_rect.Pitch, 0, src_palette, - src_surface_desc.Width, src_surface_desc.Height, 1, &src_rect); + IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc); + SetRect(&src_rect, 0, 0, src_surface_desc.Width, src_surface_desc.Height); + set_d3dx_pixels(&src_pixels, src_locked_rect.pBits, src_locked_rect.Pitch, 0, src_palette, + src_surface_desc.Width, src_surface_desc.Height, 1, &src_rect);
- hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, fmt_desc, D3DX_FILTER_NONE, 0); - if (FAILED(hr)) - { - unlock_surface(src_surface, NULL, tmp_surface, FALSE); + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, fmt_desc, D3DX_FILTER_NONE, 0); + if (FAILED(hr)) + { + unlock_surface(src_surface, NULL, tmp_surface, FALSE); + IDirect3DSurface9_Release(src_surface); + goto exit; + } + + hr = unlock_surface(src_surface, NULL, tmp_surface, FALSE); IDirect3DSurface9_Release(src_surface); - goto exit; + if (FAILED(hr)) + goto exit; } - - hr = unlock_surface(src_surface, NULL, tmp_surface, FALSE); - IDirect3DSurface9_Release(src_surface); - if (FAILED(hr)) - goto exit; }
*dst_buffer = buffer;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/tests/texture.c | 36 +++++------- dlls/d3dx9_36/texture.c | 105 +++++++++++++++++++++++++--------- 2 files changed, 90 insertions(+), 51 deletions(-)
diff --git a/dlls/d3dx9_36/tests/texture.c b/dlls/d3dx9_36/tests/texture.c index 622d4ebc2e7..99f0038251b 100644 --- a/dlls/d3dx9_36/tests/texture.c +++ b/dlls/d3dx9_36/tests/texture.c @@ -3162,7 +3162,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) uint32_t expected_caps; uint32_t expected_caps2; uint32_t expected_buffer_size; - BOOL todo_hr; } tests[] = { /* Paletted format tests. */ @@ -3186,7 +3185,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT | DDSD_DEPTH), 4, 4, 0, 4, 3, (DDSCAPS_TEXTURE | DDSCAPS_PALETTE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX), DDSCAPS2_VOLUME, PALETTED_DDS_FILE_HEADER_SIZE + 73, - .todo_hr = TRUE }, /* D3DFMT_A8R8G8B8 textures with multiple levels. */ { @@ -3210,7 +3208,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) */ { D3DRTYPE_VOLUMETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 4, 4, 3, NULL, D3DERR_INVALIDCALL, - .todo_hr = TRUE }, /* D3DPOOL_SYSTEMMEM can be saved. */ { @@ -3219,7 +3216,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_DEPTH | DDSD_MIPMAPCOUNT), 4, 4, 0, 4, 3, (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_ALPHA | DDSCAPS_COMPLEX), DDSCAPS2_VOLUME, DDS_FILE_HEADER_SIZE + 292, - .todo_hr = TRUE }, /* Single mip level, no mip flags. */ { @@ -3242,7 +3238,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_DEPTH), 4, 4, 0, 4, 0, (DDSCAPS_TEXTURE | DDSCAPS_ALPHA), DDSCAPS2_VOLUME, DDS_FILE_HEADER_SIZE + 256, - .todo_hr = TRUE }, /* 10. */ /* Volume texture with a depth of 1. */ @@ -3252,7 +3247,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), 4, 4, 0, 0, 0, (DDSCAPS_TEXTURE | DDSCAPS_ALPHA), 0, DDS_FILE_HEADER_SIZE + 64, - .todo_hr = TRUE }, }; struct @@ -3302,7 +3296,7 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) }
hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, save_tex, tests[i].palette); - todo_wine_if(tests[i].todo_hr) ok(hr == tests[i].expected_hr, "Unexpected hr %#lx.\n", hr); + ok(hr == tests[i].expected_hr, "Unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { ok(ID3DXBuffer_GetBufferSize(buffer) == tests[i].expected_buffer_size, "Unexpected buffer size %lu.\n", @@ -3473,25 +3467,21 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) ID3DXBuffer_Release(buffer); }
- todo_wine { hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, (IDirect3DBaseTexture9 *)volume_texture, NULL); ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); - if (SUCCEEDED(hr)) - { - buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); - buffer_size = ID3DXBuffer_GetBufferSize(buffer); - hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); - ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK);
- ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); - ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); - ok(info.Depth == 256, "Got depth %u, expected %u\n", info.Depth, 256); - ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); - ok(info.ResourceType == D3DRTYPE_VOLUMETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_VOLUMETEXTURE); - ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); - ID3DXBuffer_Release(buffer); - } - } + buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); + buffer_size = ID3DXBuffer_GetBufferSize(buffer); + hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); + ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); + + ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); + ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); + ok(info.Depth == 256, "Got depth %u, expected %u\n", info.Depth, 256); + ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); + ok(info.ResourceType == D3DRTYPE_VOLUMETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_VOLUMETEXTURE); + ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); + ID3DXBuffer_Release(buffer);
IDirect3DVolumeTexture9_Release(volume_texture);
diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index 25f8ef6c6b4..9464cae6fa2 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -1940,9 +1940,26 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE break; }
+ case D3DRTYPE_VOLUMETEXTURE: + { + IDirect3DVolumeTexture9 *texture = (IDirect3DVolumeTexture9 *)src_texture; + D3DVOLUME_DESC desc; + + hr = IDirect3DVolumeTexture9_GetLevelDesc(texture, 0, &desc); + if (FAILED(hr)) + break; + + fmt_desc = get_format_info(desc.Format); + if (is_unknown_format(fmt_desc)) + return E_NOTIMPL; + + set_volume_struct(&size, desc.Width, desc.Height, desc.Depth); + break; + }
default: - return E_NOTIMPL; + assert(0); /* Should not happen. */ + return E_FAIL; }
if (is_index_format(fmt_desc) && !src_palette) @@ -1970,51 +1987,83 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE if (FAILED(hr)) goto exit;
- for (j = 0; j < image.layer_count; ++j) + if (type != D3DRTYPE_VOLUMETEXTURE) { + for (j = 0; j < image.layer_count; ++j) + { + for (i = 0; i < levels; ++i) + { + IDirect3DSurface9 *src_surface, *tmp_surface; + struct d3dx_pixels src_pixels, dst_pixels; + D3DSURFACE_DESC src_surface_desc; + D3DLOCKED_RECT src_locked_rect; + RECT src_rect; + + hr = d3dx_image_get_pixels(&image, j, i, &dst_pixels); + if (FAILED(hr)) + goto exit; + + hr = get_surface(type, src_texture, j, i, &src_surface); + if (FAILED(hr)) + goto exit; + + hr = lock_surface(src_surface, NULL, &src_locked_rect, &tmp_surface, FALSE); + if (FAILED(hr)) + { + IDirect3DSurface9_Release(src_surface); + goto exit; + } + + IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc); + SetRect(&src_rect, 0, 0, src_surface_desc.Width, src_surface_desc.Height); + set_d3dx_pixels(&src_pixels, src_locked_rect.pBits, src_locked_rect.Pitch, 0, src_palette, + src_surface_desc.Width, src_surface_desc.Height, 1, &src_rect); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, fmt_desc, D3DX_FILTER_NONE, 0); + if (FAILED(hr)) + { + unlock_surface(src_surface, NULL, tmp_surface, FALSE); + IDirect3DSurface9_Release(src_surface); + goto exit; + } + + hr = unlock_surface(src_surface, NULL, tmp_surface, FALSE); + IDirect3DSurface9_Release(src_surface); + if (FAILED(hr)) + goto exit; + } + } + } + else + { + IDirect3DVolumeTexture9 *volume_tex = (IDirect3DVolumeTexture9 *)src_texture; + for (i = 0; i < levels; ++i) { - IDirect3DSurface9 *src_surface, *tmp_surface; struct d3dx_pixels src_pixels, dst_pixels; - D3DSURFACE_DESC src_surface_desc; - D3DLOCKED_RECT src_locked_rect; + D3DVOLUME_DESC src_volume_desc; + D3DLOCKED_BOX src_locked_box; RECT src_rect;
- hr = d3dx_image_get_pixels(&image, j, i, &dst_pixels); + hr = d3dx_image_get_pixels(&image, 0, i, &dst_pixels); if (FAILED(hr)) goto exit;
- hr = get_surface(type, src_texture, j, i, &src_surface); + hr = IDirect3DVolumeTexture9_LockBox(volume_tex, i, &src_locked_box, NULL, D3DLOCK_READONLY); if (FAILED(hr)) goto exit;
- hr = lock_surface(src_surface, NULL, &src_locked_rect, &tmp_surface, FALSE); - if (FAILED(hr)) - { - IDirect3DSurface9_Release(src_surface); - goto exit; - } - - IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc); - SetRect(&src_rect, 0, 0, src_surface_desc.Width, src_surface_desc.Height); - set_d3dx_pixels(&src_pixels, src_locked_rect.pBits, src_locked_rect.Pitch, 0, src_palette, - src_surface_desc.Width, src_surface_desc.Height, 1, &src_rect); + IDirect3DVolumeTexture9_GetLevelDesc(volume_tex, i, &src_volume_desc); + SetRect(&src_rect, 0, 0, src_volume_desc.Width, src_volume_desc.Height); + set_d3dx_pixels(&src_pixels, src_locked_box.pBits, src_locked_box.RowPitch, src_locked_box.SlicePitch, + src_palette, src_volume_desc.Width, src_volume_desc.Height, src_volume_desc.Depth, &src_rect);
hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, fmt_desc, D3DX_FILTER_NONE, 0); - if (FAILED(hr)) - { - unlock_surface(src_surface, NULL, tmp_surface, FALSE); - IDirect3DSurface9_Release(src_surface); - goto exit; - } - - hr = unlock_surface(src_surface, NULL, tmp_surface, FALSE); - IDirect3DSurface9_Release(src_surface); + IDirect3DVolumeTexture9_UnlockBox(volume_tex, i); if (FAILED(hr)) goto exit; } } - *dst_buffer = buffer;
exit:
On Tue Mar 25 12:49:16 2025 +0000, Connor McAdams wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/7636/diffs?diff_id=166562&start_sha=8dd79ae5f8e3a200bd203f030a9f7fe5da16a3ee#d291f1fc6edcbc5e0c592d8a4adc268488525828_3509_3523)
I've updated the comments here and merged the 32/64 bit tests.
I checked the JPEG saving/decoding on d3dx10/d3dx11 32/64 bit. Both produce identical JPEG files (although different from the d3dx9 JPEG), and both decode them in the same way. The decoded image is still less accurate than 32-bit d3dx9.
On Tue Mar 25 12:56:59 2025 +0000, Matteo Bruni wrote:
Alright, at least with that we get a significant improvement. Does the file size also roughly fall in the same range as native?
If we up the quality to 95% in libjpeg, we produce a file that is 4 bytes smaller than native.
I got a bit curious and loaded an image produced in wine with the quality at 95% on native, 32-bit native decodes our image with a max_diff of 3. So it seems like even the decoders play a part somehow, what a mess :)
On Mon Mar 24 22:24:53 2025 +0000, Matteo Bruni wrote:
To be clear, here I was referring to the 2-space indentation, which I don't think we normally use elsewhere in d3d-style code.
I think I've changed this to be how you've described, I copied the indentation from the tests in d3dx10.
FWIW, we have 2-space indentation on quite a few tests in `surface.c`, i.e `test_dds_header_handling()`. I can do 4-space indentation from now on, I was just following what I've done in the past. :) Sorry for the mess!
On Tue Mar 25 12:56:59 2025 +0000, Connor McAdams wrote:
If we up the quality to 95% in libjpeg, we produce a file that is 4 bytes smaller than native. I got a bit curious and loaded an image produced in wine with the quality at 95% on native, 32-bit native decodes our image with a max_diff of 3. So it seems like even the decoders play a part somehow, what a mess :)
Good idea checking that. Yeah, I didn't expect so much variation on the decoding side either. I wonder if there are libjpeg knobs we can set for decoding as well, it might be possible to close the gap further.
At any rate, thanks for the whole investigative digression :sweat_smile:
On Tue Mar 25 12:54:09 2025 +0000, Connor McAdams wrote:
I've updated the comments here and merged the 32/64 bit tests. I checked the JPEG saving/decoding on d3dx10/d3dx11 32/64 bit. Both produce identical JPEG files (although different from the d3dx9 JPEG), and both decode them in the same way. The decoded image is still less accurate than 32-bit d3dx9.
Alright, nothing surprising there for a change :grinning:
This merge request was approved by Matteo Bruni.
On Wed Mar 26 00:10:15 2025 +0000, Connor McAdams wrote:
I think I've changed this to be how you've described, I copied the indentation from the tests in d3dx10. FWIW, we have 2-space indentation on quite a few tests in `surface.c`, i.e `test_dds_header_handling()`. I can do 4-space indentation from now on, I was just following what I've done in the past. :) Sorry for the mess!
It's no problem at all; I generally tend to miss or ignore this kind of things unless something else also brings my attention to it.