This series of patches introduces a new set of structures and functions that will enable code to be re-used across various functions in d3dx9, and eventually d3dx10-d3dx11. It might be possible to split this further, but I feel like this initial set gives better context as to where things are heading.
I have a [branch](https://gitlab.winehq.org/cmcadams/wine/-/commits/WIP/d3dx-shared-source-v03...) that uses these structures and functions in d3dx10 if further context would be useful. There are a lot of changes here, but after playing around with different approaches this was the best/cleanest way I could come up with for code sharing. I'm sure there will be things I missed or potentially ways to improve this, I'm open to suggestions of course. :)
-- v5: d3dx9: Use d3dx_load_pixels_from_pixels() in D3DXLoadVolumeFromMemory(). d3dx9: Use d3dx_pixels structure in decompression helper function. d3dx9: Introduce d3dx_load_pixels_from_pixels() helper function. d3dx9: Use d3dx_image structure in D3DXLoadSurfaceFromFileInMemory(). d3dx9: Introduce d3dx_image structure for use in D3DXGetImageInfoFromFileInMemory(). d3dx9: Refactor WIC image info retrieval code in D3DXGetImageInfoFromFileInMemory(). d3dx9: Refactor WIC GUID to D3DXIMAGE_FILEFORMAT conversion code.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 80 +++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 18 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index ef6cd57c7da..483cb61dd4e 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -923,6 +923,59 @@ static BOOL image_is_argb(IWICBitmapFrameDecode *frame, const D3DXIMAGE_INFO *in return FALSE; }
+struct d3dx_wic_file_format +{ + const GUID *wic_container_guid; + D3DXIMAGE_FILEFORMAT d3dx_file_format; +}; + +/* Sorted by GUID. */ +static const struct d3dx_wic_file_format file_formats[] = +{ + { &GUID_ContainerFormatBmp, D3DXIFF_BMP }, + { &GUID_WineContainerFormatTga, D3DXIFF_TGA }, + { &GUID_ContainerFormatJpeg, D3DXIFF_JPG }, + { &GUID_ContainerFormatPng, D3DXIFF_PNG }, +}; + +static int __cdecl d3dx_wic_file_format_guid_compare(const void *a, const void *b) +{ + const struct d3dx_wic_file_format *format = b; + const GUID *guid = a; + + return memcmp(guid, format->wic_container_guid, sizeof(*guid)); +} + +static D3DXIMAGE_FILEFORMAT wic_container_guid_to_d3dx_file_format(GUID *container_format) +{ + struct d3dx_wic_file_format *format; + + if ((format = bsearch(container_format, file_formats, ARRAY_SIZE(file_formats), sizeof(*format), + d3dx_wic_file_format_guid_compare))) + return format->d3dx_file_format; + return D3DXIFF_FORCE_DWORD; +} + +static const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format) +{ + switch (format) + { +#define FMT_TO_STR(format) case format: return #format + FMT_TO_STR(D3DXIFF_BMP); + FMT_TO_STR(D3DXIFF_JPG); + FMT_TO_STR(D3DXIFF_TGA); + FMT_TO_STR(D3DXIFF_PNG); + FMT_TO_STR(D3DXIFF_DDS); + FMT_TO_STR(D3DXIFF_PPM); + FMT_TO_STR(D3DXIFF_DIB); + FMT_TO_STR(D3DXIFF_HDR); + FMT_TO_STR(D3DXIFF_PFM); +#undef FMT_TO_STR + default: + return "unrecognized"; + } +} + /************************************************************ * D3DXGetImageInfoFromFileInMemory * @@ -993,27 +1046,18 @@ HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize,
hr = IWICBitmapDecoder_GetContainerFormat(decoder, &container_format); if (SUCCEEDED(hr)) { - if (IsEqualGUID(&container_format, &GUID_ContainerFormatBmp)) { - if (dib) { - TRACE("File type is DIB\n"); - info->ImageFileFormat = D3DXIFF_DIB; - } else { - TRACE("File type is BMP\n"); - info->ImageFileFormat = D3DXIFF_BMP; - } - } else if (IsEqualGUID(&container_format, &GUID_ContainerFormatPng)) { - TRACE("File type is PNG\n"); - info->ImageFileFormat = D3DXIFF_PNG; - } else if(IsEqualGUID(&container_format, &GUID_ContainerFormatJpeg)) { - TRACE("File type is JPG\n"); - info->ImageFileFormat = D3DXIFF_JPG; - } else if(IsEqualGUID(&container_format, &GUID_WineContainerFormatTga)) { - TRACE("File type is TGA\n"); - info->ImageFileFormat = D3DXIFF_TGA; - } else { + D3DXIMAGE_FILEFORMAT file_format = wic_container_guid_to_d3dx_file_format(&container_format); + + if (dib && file_format == D3DXIFF_BMP) + file_format = D3DXIFF_DIB; + if (file_format == D3DXIFF_FORCE_DWORD) { WARN("Unsupported image file format %s\n", debugstr_guid(&container_format)); hr = D3DXERR_INVALIDDATA; } + else { + info->ImageFileFormat = file_format; + TRACE("File type is %s.\n", debug_d3dx_image_file_format(file_format)); + } }
if (SUCCEEDED(hr))
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 197 +++++++++++++++++++++------------------- 1 file changed, 106 insertions(+), 91 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 483cb61dd4e..892cffba363 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -976,6 +976,110 @@ static const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format) } }
+static HRESULT get_image_info_from_wic(const void *src_data, uint32_t src_data_size, D3DXIMAGE_INFO *info) +{ + IWICBitmapFrameDecode *bitmap_frame = NULL; + IWICBitmapDecoder *bitmap_decoder = NULL; + uint32_t src_image_size = src_data_size; + IWICImagingFactory *wic_factory = NULL; + const void *src_image = src_data; + WICPixelFormatGUID pixel_format; + IWICStream *wic_stream = NULL; + uint32_t frame_count = 0; + GUID container_format; + BOOL is_dib = FALSE; + HRESULT hr; + + hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &wic_factory); + if (FAILED(hr)) + return hr; + + is_dib = convert_dib_to_bmp(&src_image, &src_image_size); + hr = IWICImagingFactory_CreateStream(wic_factory, &wic_stream); + if (FAILED(hr)) + goto exit; + + hr = IWICStream_InitializeFromMemory(wic_stream, (BYTE *)src_image, src_image_size); + if (FAILED(hr)) + goto exit; + + hr = IWICImagingFactory_CreateDecoderFromStream(wic_factory, (IStream *)wic_stream, NULL, 0, &bitmap_decoder); + if (FAILED(hr)) + { + if ((src_image_size >= 2) && (!memcmp(src_image, "P3", 2) || !memcmp(src_image, "P6", 2))) + FIXME("File type PPM is not supported yet.\n"); + else if ((src_image_size >= 10) && !memcmp(src_image, "#?RADIANCE", 10)) + FIXME("File type HDR is not supported yet.\n"); + else if ((src_image_size >= 2) && (!memcmp(src_image, "PF", 2) || !memcmp(src_image, "Pf", 2))) + FIXME("File type PFM is not supported yet.\n"); + goto exit; + } + + hr = IWICBitmapDecoder_GetContainerFormat(bitmap_decoder, &container_format); + if (FAILED(hr)) + goto exit; + + info->ImageFileFormat = wic_container_guid_to_d3dx_file_format(&container_format); + if (is_dib && info->ImageFileFormat == D3DXIFF_BMP) + { + info->ImageFileFormat = D3DXIFF_DIB; + } + else if (info->ImageFileFormat == D3DXIFF_FORCE_DWORD) + { + WARN("Unsupported image file format %s.\n", debugstr_guid(&container_format)); + hr = D3DXERR_INVALIDDATA; + goto exit; + } + + TRACE("File type is %s.\n", debug_d3dx_image_file_format(info->ImageFileFormat)); + hr = IWICBitmapDecoder_GetFrameCount(bitmap_decoder, &frame_count); + if (FAILED(hr) || (SUCCEEDED(hr) && !frame_count)) + { + hr = D3DXERR_INVALIDDATA; + goto exit; + } + + hr = IWICBitmapDecoder_GetFrame(bitmap_decoder, 0, &bitmap_frame); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &info->Width, &info->Height); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameDecode_GetPixelFormat(bitmap_frame, &pixel_format); + if (FAILED(hr)) + goto exit; + + if ((info->Format = wic_guid_to_d3dformat(&pixel_format)) == D3DFMT_UNKNOWN) + { + WARN("Unsupported pixel format %s.\n", debugstr_guid(&pixel_format)); + hr = D3DXERR_INVALIDDATA; + goto exit; + } + + if (image_is_argb(bitmap_frame, info)) + info->Format = D3DFMT_A8R8G8B8; + + info->Depth = 1; + info->MipLevels = 1; + info->ResourceType = D3DRTYPE_TEXTURE; + +exit: + if (is_dib) + free((void *)src_image); + if (bitmap_frame) + IWICBitmapFrameDecode_Release(bitmap_frame); + if (bitmap_decoder) + IWICBitmapDecoder_Release(bitmap_decoder); + if (wic_stream) + IWICStream_Release(wic_stream); + if (wic_factory) + IWICImagingFactory_Release(wic_factory); + + return hr; +} + /************************************************************ * D3DXGetImageInfoFromFileInMemory * @@ -999,11 +1103,7 @@ static const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format) */ HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, D3DXIMAGE_INFO *info) { - IWICImagingFactory *factory; - IWICBitmapDecoder *decoder = NULL; - IWICStream *stream; HRESULT hr; - BOOL dib;
TRACE("(%p, %d, %p)\n", data, datasize, info);
@@ -1016,93 +1116,8 @@ HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, if ((datasize >= 4) && !strncmp(data, "DDS ", 4)) { TRACE("File type is DDS\n"); return get_image_info_from_dds(data, datasize, info); - } - - /* In case of DIB file, convert it to BMP */ - dib = convert_dib_to_bmp(&data, &datasize); - - hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); - - if (SUCCEEDED(hr)) { - IWICImagingFactory_CreateStream(factory, &stream); - IWICStream_InitializeFromMemory(stream, (BYTE*)data, datasize); - hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder); - IWICStream_Release(stream); - IWICImagingFactory_Release(factory); - } - - if (FAILED(hr)) { - if ((datasize >= 2) && (!strncmp(data, "P3", 2) || !strncmp(data, "P6", 2))) - FIXME("File type PPM is not supported yet\n"); - else if ((datasize >= 10) && !strncmp(data, "#?RADIANCE", 10)) - FIXME("File type HDR is not supported yet\n"); - else if ((datasize >= 2) && (!strncmp(data, "PF", 2) || !strncmp(data, "Pf", 2))) - FIXME("File type PFM is not supported yet\n"); - } - - if (SUCCEEDED(hr)) { - GUID container_format; - UINT frame_count; - - hr = IWICBitmapDecoder_GetContainerFormat(decoder, &container_format); - if (SUCCEEDED(hr)) { - D3DXIMAGE_FILEFORMAT file_format = wic_container_guid_to_d3dx_file_format(&container_format); - - if (dib && file_format == D3DXIFF_BMP) - file_format = D3DXIFF_DIB; - if (file_format == D3DXIFF_FORCE_DWORD) { - WARN("Unsupported image file format %s\n", debugstr_guid(&container_format)); - hr = D3DXERR_INVALIDDATA; - } - else { - info->ImageFileFormat = file_format; - TRACE("File type is %s.\n", debug_d3dx_image_file_format(file_format)); - } - } - - if (SUCCEEDED(hr)) - hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count); - if (SUCCEEDED(hr) && !frame_count) - hr = D3DXERR_INVALIDDATA; - - if (SUCCEEDED(hr)) { - IWICBitmapFrameDecode *frame = NULL; - - hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); - - if (SUCCEEDED(hr)) - hr = IWICBitmapFrameDecode_GetSize(frame, &info->Width, &info->Height); - - if (SUCCEEDED(hr)) { - WICPixelFormatGUID pixel_format; - - hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &pixel_format); - if (SUCCEEDED(hr)) { - info->Format = wic_guid_to_d3dformat(&pixel_format); - if (info->Format == D3DFMT_UNKNOWN) { - WARN("Unsupported pixel format %s\n", debugstr_guid(&pixel_format)); - hr = D3DXERR_INVALIDDATA; - } - } - } - - if (SUCCEEDED(hr) && image_is_argb(frame, info)) - info->Format = D3DFMT_A8R8G8B8; - - if (frame) - IWICBitmapFrameDecode_Release(frame); - - info->Depth = 1; - info->MipLevels = 1; - info->ResourceType = D3DRTYPE_TEXTURE; - } - } - - if (decoder) - IWICBitmapDecoder_Release(decoder); - - if (dib) - free((void*)data); + } else + hr = get_image_info_from_wic(data, datasize, info);
if (FAILED(hr)) { TRACE("Invalid or unsupported image file\n");
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 13 +++ dlls/d3dx9_36/surface.c | 193 +++++++++++++++++----------------- 2 files changed, 109 insertions(+), 97 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 668fbb27b28..e28661bf9dd 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -68,6 +68,19 @@ struct pixel_format_desc { void (*to_rgba)(const struct vec4 *src, struct vec4 *dst, const PALETTEENTRY *palette); };
+struct d3dx_image +{ + D3DRESOURCETYPE resource_type; + D3DFORMAT format; + + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t mip_levels; + + D3DXIMAGE_FILEFORMAT image_file_format; +}; + struct d3dx_include_from_file { ID3DXInclude ID3DXInclude_iface; diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 892cffba363..18f57841fdf 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -481,78 +481,6 @@ static UINT calculate_dds_file_size(D3DFORMAT format, UINT width, UINT height, U return file_size; }
-/************************************************************ -* get_image_info_from_dds -* -* Fills a D3DXIMAGE_INFO structure with information -* about a DDS file stored in the memory. -* -* PARAMS -* buffer [I] pointer to DDS data -* length [I] size of DDS data -* info [O] pointer to D3DXIMAGE_INFO structure -* -* RETURNS -* Success: D3D_OK -* Failure: D3DXERR_INVALIDDATA -* -*/ -static HRESULT get_image_info_from_dds(const void *buffer, UINT length, D3DXIMAGE_INFO *info) -{ - UINT faces = 1; - UINT expected_length; - const struct dds_header *header = buffer; - - if (length < sizeof(*header) || !info) - return D3DXERR_INVALIDDATA; - - if (header->pixel_format.size != sizeof(header->pixel_format)) - return D3DXERR_INVALIDDATA; - - info->Width = header->width; - info->Height = header->height; - info->Depth = 1; - info->MipLevels = header->miplevels ? header->miplevels : 1; - - info->Format = dds_pixel_format_to_d3dformat(&header->pixel_format); - if (info->Format == D3DFMT_UNKNOWN) - return D3DXERR_INVALIDDATA; - - TRACE("Pixel format is %#x\n", info->Format); - - if (header->caps2 & DDS_CAPS2_VOLUME) - { - info->Depth = header->depth; - info->ResourceType = D3DRTYPE_VOLUMETEXTURE; - } - else if (header->caps2 & DDS_CAPS2_CUBEMAP) - { - DWORD face; - faces = 0; - for (face = DDS_CAPS2_CUBEMAP_POSITIVEX; face <= DDS_CAPS2_CUBEMAP_NEGATIVEZ; face <<= 1) - { - if (header->caps2 & face) - faces++; - } - info->ResourceType = D3DRTYPE_CUBETEXTURE; - } - else - { - info->ResourceType = D3DRTYPE_TEXTURE; - } - - expected_length = calculate_dds_file_size(info->Format, info->Width, info->Height, info->Depth, - info->MipLevels, faces); - if (length < expected_length) - { - WARN("File is too short %u, expected at least %u bytes\n", length, expected_length); - return D3DXERR_INVALIDDATA; - } - - info->ImageFileFormat = D3DXIFF_DDS; - return D3D_OK; -} - static HRESULT load_surface_from_dds(IDirect3DSurface9 *dst_surface, const PALETTEENTRY *dst_palette, const RECT *dst_rect, const void *src_data, const RECT *src_rect, DWORD filter, D3DCOLOR color_key, const D3DXIMAGE_INFO *src_info) @@ -822,6 +750,59 @@ HRESULT load_volume_texture_from_dds(IDirect3DVolumeTexture9 *volume_texture, co return D3D_OK; }
+static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src_data_size, + struct d3dx_image *image) +{ + const struct dds_header *header = src_data; + uint32_t expected_src_data_size; + uint32_t faces = 1; + + if (src_data_size < sizeof(*header) || header->pixel_format.size != sizeof(header->pixel_format)) + return D3DXERR_INVALIDDATA; + + TRACE("File type is DDS.\n"); + image->width = header->width; + image->height = header->height; + image->depth = 1; + image->mip_levels = header->miplevels ? header->miplevels : 1; + image->format = dds_pixel_format_to_d3dformat(&header->pixel_format); + + if (image->format == D3DFMT_UNKNOWN) + return D3DXERR_INVALIDDATA; + + TRACE("Pixel format is %#x.\n", image->format); + if (header->caps2 & DDS_CAPS2_VOLUME) + { + image->depth = header->depth; + image->resource_type = D3DRTYPE_VOLUMETEXTURE; + } + else if (header->caps2 & DDS_CAPS2_CUBEMAP) + { + DWORD face; + + faces = 0; + for (face = DDS_CAPS2_CUBEMAP_POSITIVEX; face <= DDS_CAPS2_CUBEMAP_NEGATIVEZ; face <<= 1) + { + if (header->caps2 & face) + faces++; + } + image->resource_type = D3DRTYPE_CUBETEXTURE; + } + else + image->resource_type = D3DRTYPE_TEXTURE; + + expected_src_data_size = calculate_dds_file_size(image->format, image->width, image->height, + image->depth, image->mip_levels, faces); + if (src_data_size < expected_src_data_size) + { + WARN("File is too short %u, expected at least %u bytes.\n", src_data_size, expected_src_data_size); + return D3DXERR_INVALIDDATA; + } + + image->image_file_format = D3DXIFF_DDS; + return D3D_OK; +} + static BOOL convert_dib_to_bmp(const void **data, unsigned int *size) { ULONG header_size; @@ -889,28 +870,28 @@ static BOOL convert_dib_to_bmp(const void **data, unsigned int *size)
/* windowscodecs always returns xRGB, but we should return ARGB if and only if * at least one pixel has a non-zero alpha component. */ -static BOOL image_is_argb(IWICBitmapFrameDecode *frame, const D3DXIMAGE_INFO *info) +static BOOL image_is_argb(IWICBitmapFrameDecode *frame, struct d3dx_image *image) { unsigned int size, i; BYTE *buffer; HRESULT hr;
- if (info->Format != D3DFMT_X8R8G8B8 || (info->ImageFileFormat != D3DXIFF_BMP - && info->ImageFileFormat != D3DXIFF_TGA)) + if (image->format != D3DFMT_X8R8G8B8 || (image->image_file_format != D3DXIFF_BMP + && image->image_file_format != D3DXIFF_TGA)) return FALSE;
- size = info->Width * info->Height * 4; + size = image->width * image->height * 4; if (!(buffer = malloc(size))) return FALSE;
- if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, info->Width * 4, size, buffer))) + if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, image->width * 4, size, buffer))) { ERR("Failed to copy pixels, hr %#lx.\n", hr); free(buffer); return FALSE; }
- for (i = 0; i < info->Width * info->Height; ++i) + for (i = 0; i < image->width * image->height; ++i) { if (buffer[i * 4 + 3]) { @@ -976,7 +957,8 @@ static const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format) } }
-static HRESULT get_image_info_from_wic(const void *src_data, uint32_t src_data_size, D3DXIMAGE_INFO *info) +static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src_data_size, + struct d3dx_image *image) { IWICBitmapFrameDecode *bitmap_frame = NULL; IWICBitmapDecoder *bitmap_decoder = NULL; @@ -1019,19 +1001,19 @@ static HRESULT get_image_info_from_wic(const void *src_data, uint32_t src_data_s if (FAILED(hr)) goto exit;
- info->ImageFileFormat = wic_container_guid_to_d3dx_file_format(&container_format); - if (is_dib && info->ImageFileFormat == D3DXIFF_BMP) + image->image_file_format = wic_container_guid_to_d3dx_file_format(&container_format); + if (is_dib && image->image_file_format == D3DXIFF_BMP) { - info->ImageFileFormat = D3DXIFF_DIB; + image->image_file_format = D3DXIFF_DIB; } - else if (info->ImageFileFormat == D3DXIFF_FORCE_DWORD) + else if (image->image_file_format == D3DXIFF_FORCE_DWORD) { WARN("Unsupported image file format %s.\n", debugstr_guid(&container_format)); hr = D3DXERR_INVALIDDATA; goto exit; }
- TRACE("File type is %s.\n", debug_d3dx_image_file_format(info->ImageFileFormat)); + TRACE("File type is %s.\n", debug_d3dx_image_file_format(image->image_file_format)); hr = IWICBitmapDecoder_GetFrameCount(bitmap_decoder, &frame_count); if (FAILED(hr) || (SUCCEEDED(hr) && !frame_count)) { @@ -1043,7 +1025,7 @@ static HRESULT get_image_info_from_wic(const void *src_data, uint32_t src_data_s if (FAILED(hr)) goto exit;
- hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &info->Width, &info->Height); + hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &image->width, &image->height); if (FAILED(hr)) goto exit;
@@ -1051,19 +1033,19 @@ static HRESULT get_image_info_from_wic(const void *src_data, uint32_t src_data_s if (FAILED(hr)) goto exit;
- if ((info->Format = wic_guid_to_d3dformat(&pixel_format)) == D3DFMT_UNKNOWN) + if ((image->format = wic_guid_to_d3dformat(&pixel_format)) == D3DFMT_UNKNOWN) { WARN("Unsupported pixel format %s.\n", debugstr_guid(&pixel_format)); hr = D3DXERR_INVALIDDATA; goto exit; }
- if (image_is_argb(bitmap_frame, info)) - info->Format = D3DFMT_A8R8G8B8; + if (image_is_argb(bitmap_frame, image)) + image->format = D3DFMT_A8R8G8B8;
- info->Depth = 1; - info->MipLevels = 1; - info->ResourceType = D3DRTYPE_TEXTURE; + image->depth = 1; + image->mip_levels = 1; + image->resource_type = D3DRTYPE_TEXTURE;
exit: if (is_dib) @@ -1080,6 +1062,19 @@ exit: return hr; }
+static HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, + struct d3dx_image *image) +{ + if (!src_data || !src_data_size || !image) + return D3DERR_INVALIDCALL; + + memset(image, 0, sizeof(*image)); + if ((src_data_size >= 4) && !memcmp(src_data, "DDS ", 4)) + return d3dx_initialize_image_from_dds(src_data, src_data_size, image); + + return d3dx_initialize_image_from_wic(src_data, src_data_size, image); +} + /************************************************************ * D3DXGetImageInfoFromFileInMemory * @@ -1103,6 +1098,7 @@ exit: */ HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, D3DXIMAGE_INFO *info) { + struct d3dx_image image; HRESULT hr;
TRACE("(%p, %d, %p)\n", data, datasize, info); @@ -1113,17 +1109,20 @@ HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, if (!info) return D3D_OK;
- if ((datasize >= 4) && !strncmp(data, "DDS ", 4)) { - TRACE("File type is DDS\n"); - return get_image_info_from_dds(data, datasize, info); - } else - hr = get_image_info_from_wic(data, datasize, info); - + hr = d3dx_image_init(data, datasize, &image); if (FAILED(hr)) { TRACE("Invalid or unsupported image file\n"); return D3DXERR_INVALIDDATA; }
+ info->ImageFileFormat = image.image_file_format; + info->Width = image.width; + info->Height = image.height; + info->Depth = image.depth; + info->MipLevels = image.mip_levels; + info->Format = image.format; + info->ResourceType = image.resource_type; + return D3D_OK; }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 28 +++ dlls/d3dx9_36/surface.c | 348 +++++++++++++++------------------- 2 files changed, 183 insertions(+), 193 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index e28661bf9dd..be88e227515 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -45,6 +45,13 @@ struct volume UINT depth; };
+static inline void set_volume_struct(struct volume *volume, uint32_t width, uint32_t height, uint32_t depth) +{ + volume->width = width; + volume->height = height; + volume->depth = depth; +} + /* for internal use */ enum format_type { FORMAT_ARGB, /* unsigned */ @@ -68,6 +75,17 @@ struct pixel_format_desc { void (*to_rgba)(const struct vec4 *src, struct vec4 *dst, const PALETTEENTRY *palette); };
+struct d3dx_pixels +{ + const void *data; + uint32_t row_pitch; + uint32_t slice_pitch; + const PALETTEENTRY *palette; + + struct volume size; +}; + +#define D3DX_IMAGE_INFO_ONLY 1 struct d3dx_image { D3DRESOURCETYPE resource_type; @@ -78,6 +96,16 @@ struct d3dx_image uint32_t depth; uint32_t mip_levels;
+ BYTE *pixels; + + /* + * image_buf and palette are pointers to allocated memory used to store + * image data. If they are non-NULL, they need to be freed when no longer + * in use. + */ + void *image_buf; + PALETTEENTRY *palette; + D3DXIMAGE_FILEFORMAT image_file_format; };
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 18f57841fdf..26d7c0f8458 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -437,10 +437,11 @@ static HRESULT d3dformat_to_dds_pixel_format(struct dds_pixel_format *pixel_form return E_NOTIMPL; }
-static HRESULT calculate_dds_surface_size(D3DFORMAT format, UINT width, UINT height, - UINT *pitch, UINT *size) +static HRESULT d3dx_calculate_pixels_size(D3DFORMAT format, uint32_t width, uint32_t height, + uint32_t *pitch, uint32_t *size) { const struct pixel_format_desc *format_desc = get_format_info(format); + if (format_desc->type == FORMAT_UNKNOWN) return E_NOTIMPL;
@@ -468,7 +469,7 @@ static UINT calculate_dds_file_size(D3DFORMAT format, UINT width, UINT height, U for (i = 0; i < miplevels; i++) { UINT pitch, size = 0; - calculate_dds_surface_size(format, width, height, &pitch, &size); + d3dx_calculate_pixels_size(format, width, height, &pitch, &size); size *= depth; file_size += size; width = max(1, width / 2); @@ -481,25 +482,6 @@ static UINT calculate_dds_file_size(D3DFORMAT format, UINT width, UINT height, U return file_size; }
-static HRESULT load_surface_from_dds(IDirect3DSurface9 *dst_surface, const PALETTEENTRY *dst_palette, - const RECT *dst_rect, const void *src_data, const RECT *src_rect, DWORD filter, D3DCOLOR color_key, - const D3DXIMAGE_INFO *src_info) -{ - UINT size; - UINT src_pitch; - const struct dds_header *header = src_data; - const BYTE *pixels = (BYTE *)(header + 1); - - if (src_info->ResourceType != D3DRTYPE_TEXTURE) - return D3DXERR_INVALIDDATA; - - if (FAILED(calculate_dds_surface_size(src_info->Format, src_info->Width, src_info->Height, &src_pitch, &size))) - return E_NOTIMPL; - - return D3DXLoadSurfaceFromMemory(dst_surface, dst_palette, dst_rect, pixels, src_info->Format, - src_pitch, NULL, src_rect, filter, color_key); -} - static HRESULT save_dds_surface_to_memory(ID3DXBuffer **dst_buffer, IDirect3DSurface9 *src_surface, const RECT *src_rect) { HRESULT hr; @@ -527,7 +509,7 @@ static HRESULT save_dds_surface_to_memory(ID3DXBuffer **dst_buffer, IDirect3DSur
file_size = calculate_dds_file_size(src_desc.Format, src_desc.Width, src_desc.Height, 1, 1, 1);
- hr = calculate_dds_surface_size(src_desc.Format, src_desc.Width, src_desc.Height, &dst_pitch, &surface_size); + hr = d3dx_calculate_pixels_size(src_desc.Format, src_desc.Width, src_desc.Height, &dst_pitch, &surface_size); if (FAILED(hr)) return hr;
hr = D3DXCreateBuffer(file_size, &buffer); @@ -581,7 +563,7 @@ HRESULT load_volume_from_dds(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *d if (src_info->ResourceType != D3DRTYPE_VOLUMETEXTURE) return D3DXERR_INVALIDDATA;
- if (FAILED(calculate_dds_surface_size(src_info->Format, src_info->Width, src_info->Height, &row_pitch, &slice_pitch))) + if (FAILED(d3dx_calculate_pixels_size(src_info->Format, src_info->Width, src_info->Height, &row_pitch, &slice_pitch))) return E_NOTIMPL;
return D3DXLoadVolumeFromMemory(dst_volume, dst_palette, dst_box, pixels, src_info->Format, @@ -620,7 +602,7 @@ HRESULT load_texture_from_dds(IDirect3DTexture9 *texture, const void *src_data, mip_levels = 1; for (mip_level = 0; mip_level < mip_levels + skip_levels; ++mip_level) { - hr = calculate_dds_surface_size(src_info->Format, width, height, &src_pitch, &mip_level_size); + hr = d3dx_calculate_pixels_size(src_info->Format, width, height, &src_pitch, &mip_level_size); if (FAILED(hr)) return hr;
if (mip_level >= skip_levels) @@ -675,7 +657,7 @@ HRESULT load_cube_texture_from_dds(IDirect3DCubeTexture9 *cube_texture, const vo size = src_info->Width; for (mip_level = 0; mip_level < src_info->MipLevels; mip_level++) { - hr = calculate_dds_surface_size(src_info->Format, size, size, &src_pitch, &mip_level_size); + hr = d3dx_calculate_pixels_size(src_info->Format, size, size, &src_pitch, &mip_level_size); if (FAILED(hr)) return hr;
/* if texture has fewer mip levels than DDS file, skip excessive mip levels */ @@ -722,7 +704,7 @@ HRESULT load_volume_texture_from_dds(IDirect3DVolumeTexture9 *volume_texture, co
for (mip_level = 0; mip_level < mip_levels; mip_level++) { - hr = calculate_dds_surface_size(src_info->Format, width, height, &src_row_pitch, &src_slice_pitch); + hr = d3dx_calculate_pixels_size(src_info->Format, width, height, &src_row_pitch, &src_slice_pitch); if (FAILED(hr)) return hr;
hr = IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, mip_level, &volume); @@ -799,6 +781,7 @@ static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src return D3DXERR_INVALIDDATA; }
+ image->pixels = ((BYTE *)src_data) + sizeof(*header); image->image_file_format = D3DXIFF_DDS; return D3D_OK; } @@ -957,8 +940,88 @@ static const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format) } }
+static HRESULT d3dx_image_wic_frame_decode(struct d3dx_image *image, + IWICImagingFactory *wic_factory, IWICBitmapFrameDecode *bitmap_frame) +{ + const struct pixel_format_desc *fmt_desc; + uint32_t row_pitch, slice_pitch; + IWICPalette *wic_palette = NULL; + PALETTEENTRY *palette = NULL; + WICColor *colors = NULL; + BYTE *buffer = NULL; + HRESULT hr; + + fmt_desc = get_format_info(image->format); + hr = d3dx_calculate_pixels_size(image->format, image->width, image->height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + /* Allocate a buffer for our image. */ + if (!(buffer = malloc(slice_pitch))) + return E_OUTOFMEMORY; + + hr = IWICBitmapFrameDecode_CopyPixels(bitmap_frame, NULL, row_pitch, slice_pitch, buffer); + if (FAILED(hr)) + { + free(buffer); + return hr; + } + + if (fmt_desc->type == FORMAT_INDEX) + { + uint32_t nb_colors, i; + + hr = IWICImagingFactory_CreatePalette(wic_factory, &wic_palette); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameDecode_CopyPalette(bitmap_frame, wic_palette); + if (FAILED(hr)) + goto exit; + + hr = IWICPalette_GetColorCount(wic_palette, &nb_colors); + if (FAILED(hr)) + goto exit; + + colors = malloc(nb_colors * sizeof(colors[0])); + palette = malloc(nb_colors * sizeof(palette[0])); + if (!colors || !palette) + { + hr = E_OUTOFMEMORY; + goto exit; + } + + hr = IWICPalette_GetColors(wic_palette, nb_colors, colors, &nb_colors); + if (FAILED(hr)) + goto exit; + + /* Convert colors from WICColor (ARGB) to PALETTEENTRY (ABGR) */ + for (i = 0; i < nb_colors; i++) + { + palette[i].peRed = (colors[i] >> 16) & 0xff; + palette[i].peGreen = (colors[i] >> 8) & 0xff; + palette[i].peBlue = colors[i] & 0xff; + palette[i].peFlags = (colors[i] >> 24) & 0xff; /* peFlags is the alpha component in DX8 and higher */ + } + } + + image->image_buf = image->pixels = buffer; + image->palette = palette; + +exit: + free(colors); + if (image->image_buf != buffer) + free(buffer); + if (image->palette != palette) + free(palette); + if (wic_palette) + IWICPalette_Release(wic_palette); + + return hr; +} + static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src_data_size, - struct d3dx_image *image) + struct d3dx_image *image, uint32_t flags) { IWICBitmapFrameDecode *bitmap_frame = NULL; IWICBitmapDecoder *bitmap_decoder = NULL; @@ -1043,6 +1106,13 @@ static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src if (image_is_argb(bitmap_frame, image)) image->format = D3DFMT_A8R8G8B8;
+ if (!(flags & D3DX_IMAGE_INFO_ONLY)) + { + hr = d3dx_image_wic_frame_decode(image, wic_factory, bitmap_frame); + if (FAILED(hr)) + goto exit; + } + image->depth = 1; image->mip_levels = 1; image->resource_type = D3DRTYPE_TEXTURE; @@ -1063,7 +1133,7 @@ exit: }
static HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, - struct d3dx_image *image) + struct d3dx_image *image, uint32_t flags) { if (!src_data || !src_data_size || !image) return D3DERR_INVALIDCALL; @@ -1072,7 +1142,42 @@ static HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, if ((src_data_size >= 4) && !memcmp(src_data, "DDS ", 4)) return d3dx_initialize_image_from_dds(src_data, src_data_size, image);
- return d3dx_initialize_image_from_wic(src_data, src_data_size, image); + return d3dx_initialize_image_from_wic(src_data, src_data_size, image, flags); +} + +static void d3dx_image_cleanup(struct d3dx_image *image) +{ + free(image->image_buf); + free(image->palette); +} + +static HRESULT d3dx_image_get_pixels(struct d3dx_image *image, struct d3dx_pixels *pixels) +{ + uint32_t row_pitch, slice_pitch; + HRESULT hr = S_OK; + + hr = d3dx_calculate_pixels_size(image->format, image->width, image->height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + pixels->data = image->pixels; + pixels->row_pitch = row_pitch; + pixels->slice_pitch = slice_pitch; + pixels->palette = image->palette; + set_volume_struct(&pixels->size, image->width, image->height, image->depth); + + return D3D_OK; +} + +static void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image) +{ + info->ImageFileFormat = image->image_file_format; + info->Width = image->width; + info->Height = image->height; + info->Depth = image->depth; + info->MipLevels = image->mip_levels; + info->Format = image->format; + info->ResourceType = image->resource_type; }
/************************************************************ @@ -1109,20 +1214,13 @@ HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, if (!info) return D3D_OK;
- hr = d3dx_image_init(data, datasize, &image); + hr = d3dx_image_init(data, datasize, &image, D3DX_IMAGE_INFO_ONLY); if (FAILED(hr)) { TRACE("Invalid or unsupported image file\n"); return D3DXERR_INVALIDDATA; }
- info->ImageFileFormat = image.image_file_format; - info->Width = image.width; - info->Height = image.height; - info->Depth = image.depth; - info->MipLevels = image.mip_levels; - info->Format = image.format; - info->ResourceType = image.resource_type; - + d3dximage_info_from_d3dx_image(info, &image); return D3D_OK; }
@@ -1251,18 +1349,12 @@ HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface, const PALETTEENTRY *pDestPalette, const RECT *pDestRect, const void *pSrcData, UINT SrcDataSize, const RECT *pSrcRect, DWORD dwFilter, D3DCOLOR Colorkey, D3DXIMAGE_INFO *pSrcInfo) { - D3DXIMAGE_INFO imginfo; + struct d3dx_pixels pixels = { 0 }; + struct d3dx_image image; + D3DXIMAGE_INFO img_info; + RECT src_rect; HRESULT hr;
- IWICImagingFactory *factory = NULL; - IWICBitmapDecoder *decoder; - IWICBitmapFrameDecode *bitmapframe; - IWICStream *stream; - - const struct pixel_format_desc *formatdesc; - WICRect wicrect; - RECT rect; - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_data %p, src_data_size %u, " "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", pDestSurface, pDestPalette, wine_dbgstr_rect(pDestRect), pSrcData, SrcDataSize, @@ -1271,151 +1363,28 @@ HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface, if (!pDestSurface || !pSrcData || !SrcDataSize) return D3DERR_INVALIDCALL;
- hr = D3DXGetImageInfoFromFileInMemory(pSrcData, SrcDataSize, &imginfo); - + hr = d3dx_image_init(pSrcData, SrcDataSize, &image, 0); if (FAILED(hr)) - return hr; + return D3DXERR_INVALIDDATA;
+ d3dximage_info_from_d3dx_image(&img_info, &image); if (pSrcRect) - { - wicrect.X = pSrcRect->left; - wicrect.Y = pSrcRect->top; - wicrect.Width = pSrcRect->right - pSrcRect->left; - wicrect.Height = pSrcRect->bottom - pSrcRect->top; - } + src_rect = *pSrcRect; else - { - wicrect.X = 0; - wicrect.Y = 0; - wicrect.Width = imginfo.Width; - wicrect.Height = imginfo.Height; - } - - SetRect(&rect, wicrect.X, wicrect.Y, wicrect.X + wicrect.Width, wicrect.Y + wicrect.Height); - - if (imginfo.ImageFileFormat == D3DXIFF_DDS) - { - hr = load_surface_from_dds(pDestSurface, pDestPalette, pDestRect, pSrcData, &rect, - dwFilter, Colorkey, &imginfo); - if (SUCCEEDED(hr) && pSrcInfo) - *pSrcInfo = imginfo; - return hr; - } - - if (imginfo.ImageFileFormat == D3DXIFF_DIB) - convert_dib_to_bmp(&pSrcData, &SrcDataSize); - - if (FAILED(WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory))) - goto cleanup_err; - - if (FAILED(IWICImagingFactory_CreateStream(factory, &stream))) - { - IWICImagingFactory_Release(factory); - factory = NULL; - goto cleanup_err; - } - - IWICStream_InitializeFromMemory(stream, (BYTE*)pSrcData, SrcDataSize); - - hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder); - - IWICStream_Release(stream); + SetRect(&src_rect, 0, 0, img_info.Width, img_info.Height);
+ hr = d3dx_image_get_pixels(&image, &pixels); if (FAILED(hr)) - goto cleanup_err; - - hr = IWICBitmapDecoder_GetFrame(decoder, 0, &bitmapframe); - - if (FAILED(hr)) - goto cleanup_bmp; - - formatdesc = get_format_info(imginfo.Format); - - if (formatdesc->type == FORMAT_UNKNOWN) - { - FIXME("Unsupported pixel format\n"); - hr = D3DXERR_INVALIDDATA; - } - else - { - BYTE *buffer; - DWORD pitch; - PALETTEENTRY *palette = NULL; - WICColor *colors = NULL; - - pitch = formatdesc->bytes_per_pixel * wicrect.Width; - buffer = malloc(pitch * wicrect.Height); - - hr = IWICBitmapFrameDecode_CopyPixels(bitmapframe, &wicrect, pitch, - pitch * wicrect.Height, buffer); - - if (SUCCEEDED(hr) && (formatdesc->type == FORMAT_INDEX)) - { - IWICPalette *wic_palette = NULL; - UINT nb_colors; - - hr = IWICImagingFactory_CreatePalette(factory, &wic_palette); - if (SUCCEEDED(hr)) - hr = IWICBitmapFrameDecode_CopyPalette(bitmapframe, wic_palette); - if (SUCCEEDED(hr)) - hr = IWICPalette_GetColorCount(wic_palette, &nb_colors); - if (SUCCEEDED(hr)) - { - colors = malloc(nb_colors * sizeof(colors[0])); - palette = malloc(nb_colors * sizeof(palette[0])); - if (!colors || !palette) - hr = E_OUTOFMEMORY; - } - if (SUCCEEDED(hr)) - hr = IWICPalette_GetColors(wic_palette, nb_colors, colors, &nb_colors); - if (SUCCEEDED(hr)) - { - UINT i; - - /* Convert colors from WICColor (ARGB) to PALETTEENTRY (ABGR) */ - for (i = 0; i < nb_colors; i++) - { - palette[i].peRed = (colors[i] >> 16) & 0xff; - palette[i].peGreen = (colors[i] >> 8) & 0xff; - palette[i].peBlue = colors[i] & 0xff; - palette[i].peFlags = (colors[i] >> 24) & 0xff; /* peFlags is the alpha component in DX8 and higher */ - } - } - if (wic_palette) - IWICPalette_Release(wic_palette); - } - - if (SUCCEEDED(hr)) - { - hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect, - buffer, imginfo.Format, pitch, - palette, &rect, dwFilter, Colorkey); - } - - free(colors); - free(palette); - free(buffer); - } - - IWICBitmapFrameDecode_Release(bitmapframe); - -cleanup_bmp: - IWICBitmapDecoder_Release(decoder); - -cleanup_err: - if (factory) - IWICImagingFactory_Release(factory); - - if (imginfo.ImageFileFormat == D3DXIFF_DIB) - free((void*)pSrcData); - - if (FAILED(hr)) - return D3DXERR_INVALIDDATA; + goto exit;
- if (pSrcInfo) - *pSrcInfo = imginfo; + hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect, pixels.data, img_info.Format, + pixels.row_pitch, pixels.palette, &src_rect, dwFilter, Colorkey); + if (SUCCEEDED(hr) && pSrcInfo) + *pSrcInfo = img_info;
- return D3D_OK; +exit: + d3dx_image_cleanup(&image); + return FAILED(hr) ? D3DXERR_INVALIDDATA : D3D_OK; }
HRESULT WINAPI D3DXLoadSurfaceFromFileA(IDirect3DSurface9 *dst_surface, @@ -1996,13 +1965,6 @@ exit: return S_OK; }
-static void set_volume_struct(struct volume *volume, uint32_t width, uint32_t height, uint32_t depth) -{ - volume->width = width; - volume->height = height; - volume->depth = depth; -} - static HRESULT d3dx_load_image_from_memory(void *dst_memory, uint32_t dst_row_pitch, const struct pixel_format_desc *dst_desc, const PALETTEENTRY *dst_palette, const RECT *dst_rect, const RECT *dst_rect_aligned, const void *src_memory, uint32_t src_row_pitch, const struct pixel_format_desc *src_desc, const PALETTEENTRY *src_palette, const RECT *src_rect,
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 13 +++ dlls/d3dx9_36/surface.c | 178 +++++++++++++++++++++++----------- 2 files changed, 136 insertions(+), 55 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index be88e227515..722ed73ae0f 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -83,8 +83,21 @@ struct d3dx_pixels const PALETTEENTRY *palette;
struct volume size; + RECT unaligned_rect; };
+static inline void set_d3dx_pixels(struct d3dx_pixels *pixels, const void *data, uint32_t row_pitch, + uint32_t slice_pitch, const PALETTEENTRY *palette, uint32_t width, uint32_t height, uint32_t depth, + const RECT *unaligned_rect) +{ + pixels->data = data; + pixels->row_pitch = row_pitch; + pixels->slice_pitch = slice_pitch; + pixels->palette = palette; + set_volume_struct(&pixels->size, width, height, depth); + pixels->unaligned_rect = *unaligned_rect; +} + #define D3DX_IMAGE_INFO_ONLY 1 struct d3dx_image { diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 26d7c0f8458..327af791489 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1154,17 +1154,16 @@ static void d3dx_image_cleanup(struct d3dx_image *image) static HRESULT d3dx_image_get_pixels(struct d3dx_image *image, struct d3dx_pixels *pixels) { uint32_t row_pitch, slice_pitch; + RECT unaligned_rect; HRESULT hr = S_OK;
hr = d3dx_calculate_pixels_size(image->format, image->width, image->height, &row_pitch, &slice_pitch); if (FAILED(hr)) return hr;
- pixels->data = image->pixels; - pixels->row_pitch = row_pitch; - pixels->slice_pitch = slice_pitch; - pixels->palette = image->palette; - set_volume_struct(&pixels->size, image->width, image->height, image->depth); + SetRect(&unaligned_rect, 0, 0, image->width, image->height); + set_d3dx_pixels(pixels, image->pixels, row_pitch, slice_pitch, image->palette, image->width, image->height, + image->depth, &unaligned_rect);
return D3D_OK; } @@ -1965,40 +1964,91 @@ exit: return S_OK; }
-static HRESULT d3dx_load_image_from_memory(void *dst_memory, uint32_t dst_row_pitch, const struct pixel_format_desc *dst_desc, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, const RECT *dst_rect_aligned, const void *src_memory, - uint32_t src_row_pitch, const struct pixel_format_desc *src_desc, const PALETTEENTRY *src_palette, const RECT *src_rect, - uint32_t filter_flags, uint32_t color_key) +static HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, + const PALETTEENTRY *palette, D3DFORMAT format, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, + uint32_t front, uint32_t back, struct d3dx_pixels *pixels) +{ + const struct pixel_format_desc *fmt_desc = get_format_info(format); + const BYTE *ptr = data; + RECT unaligned_rect; + + memset(pixels, 0, sizeof(*pixels)); + if (fmt_desc->type == FORMAT_UNKNOWN) + { + FIXME("Unsupported format %#x.\n", format); + return E_NOTIMPL; + } + + ptr += front * slice_pitch; + ptr += (top / fmt_desc->block_height) * row_pitch; + ptr += (left / fmt_desc->block_width) * fmt_desc->block_byte_count; + + if (fmt_desc->type == FORMAT_DXT) + { + uint32_t left_aligned, top_aligned; + + top_aligned = top & ~(fmt_desc->block_height - 1); + left_aligned = left & ~(fmt_desc->block_width - 1); + SetRect(&unaligned_rect, left, top, right, bottom); + OffsetRect(&unaligned_rect, -left_aligned, -top_aligned); + } + else + { + SetRect(&unaligned_rect, 0, 0, (right - left), (bottom - top)); + } + + set_d3dx_pixels(pixels, ptr, row_pitch, slice_pitch, palette, (right - left), (bottom - top), (back - front), + &unaligned_rect); + + return S_OK; +} + +static const char *debug_d3dx_pixels(struct d3dx_pixels *pixels) +{ + if (!pixels) + return "(null)"; + return wine_dbg_sprintf("(data %p, row_pitch %d, slice_pitch %d, palette %p, width %d, height %d, depth %d, " + "unaligned_rect %s)", pixels->data, pixels->row_pitch, pixels->slice_pitch, pixels->palette, + pixels->size.width, pixels->size.height, pixels->size.depth, wine_dbgstr_rect(&pixels->unaligned_rect)); +} + +static HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, + const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, + const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key) { struct volume src_size, dst_size, dst_size_aligned; - const BYTE *src_memory_offset = src_memory; HRESULT hr = S_OK;
- TRACE("dst_memory %p, dst_row_pitch %d, dst_desc %p, dst_palette %p, dst_rect %s, dst_rect_aligned %s, src_memory %p, " - "src_row_pitch %d, src_desc %p, src_palette %p, src_rect %s, filter %#x, color_key 0x%08x.\n", - dst_memory, dst_row_pitch, dst_desc, dst_palette, wine_dbgstr_rect(dst_rect), wine_dbgstr_rect(dst_rect_aligned), - src_memory, src_row_pitch, src_desc, src_palette, wine_dbgstr_rect(src_rect), filter_flags, color_key); + TRACE("dst_pixels %s, dst_desc %p, src_pixels %s, src_desc %p, filter_flags %#x, color_key %#x.\n", + debug_d3dx_pixels(dst_pixels), dst_desc, debug_d3dx_pixels(src_pixels), src_desc, + filter_flags, color_key);
- set_volume_struct(&src_size, (src_rect->right - src_rect->left), (src_rect->bottom - src_rect->top), 1); - set_volume_struct(&dst_size, (dst_rect->right - dst_rect->left), (dst_rect->bottom - dst_rect->top), 1); - set_volume_struct(&dst_size_aligned, (dst_rect_aligned->right - dst_rect_aligned->left), - (dst_rect_aligned->bottom - dst_rect_aligned->top), 1); + if (src_desc->type == FORMAT_DXT) + set_volume_struct(&src_size, (src_pixels->unaligned_rect.right - src_pixels->unaligned_rect.left), + (src_pixels->unaligned_rect.bottom - src_pixels->unaligned_rect.top), src_pixels->size.depth); + else + src_size = src_pixels->size;
- src_memory_offset += (src_rect->top / src_desc->block_height) * src_row_pitch; - src_memory_offset += (src_rect->left / src_desc->block_width) * src_desc->block_byte_count; + dst_size_aligned = dst_pixels->size; + if (dst_desc->type == FORMAT_DXT) + set_volume_struct(&dst_size, (dst_pixels->unaligned_rect.right - dst_pixels->unaligned_rect.left), + (dst_pixels->unaligned_rect.bottom - dst_pixels->unaligned_rect.top), dst_pixels->size.depth); + else + dst_size = dst_size_aligned;
/* Everything matches, simply copy the pixels. */ if (src_desc->format == dst_desc->format && (dst_size.width == src_size.width && !(dst_size.width % dst_desc->block_width)) && (dst_size.height == src_size.height && !(dst_size.height % dst_desc->block_height)) && color_key == 0 - && !(src_rect->left & (src_desc->block_width - 1)) - && !(src_rect->top & (src_desc->block_height - 1)) - && !(dst_rect->left & (dst_desc->block_width - 1)) - && !(dst_rect->top & (dst_desc->block_height - 1))) + && !(src_pixels->unaligned_rect.left & (src_desc->block_width - 1)) + && !(src_pixels->unaligned_rect.top & (src_desc->block_height - 1)) + && !(dst_pixels->unaligned_rect.left & (dst_desc->block_width - 1)) + && !(dst_pixels->unaligned_rect.top & (dst_desc->block_height - 1))) { TRACE("Simple copy.\n"); - copy_pixels(src_memory_offset, src_row_pitch, 0, dst_memory, dst_row_pitch, 0, &src_size, src_desc); + copy_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, (void *)dst_pixels->data, + dst_pixels->row_pitch, dst_pixels->slice_pitch, &src_size, src_desc); return S_OK; }
@@ -2021,37 +2071,45 @@ static HRESULT d3dx_load_image_from_memory(void *dst_memory, uint32_t dst_row_pi void *uncompressed_mem = NULL; RECT uncompressed_rect;
- hr = d3dx_image_decompress(src_memory, src_row_pitch, src_rect, NULL, &src_size, src_desc, - &uncompressed_mem, &uncompressed_row_pitch, &uncompressed_rect, &uncompressed_desc); + hr = d3dx_image_decompress(src_pixels->data, src_pixels->row_pitch, &src_pixels->unaligned_rect, NULL, + &src_size, src_desc, &uncompressed_mem, &uncompressed_row_pitch, &uncompressed_rect, &uncompressed_desc); if (SUCCEEDED(hr)) { - hr = d3dx_load_image_from_memory(dst_memory, dst_row_pitch, dst_desc, dst_palette, dst_rect, dst_rect_aligned, - uncompressed_mem, uncompressed_row_pitch, uncompressed_desc, src_palette, &uncompressed_rect, + struct d3dx_pixels uncompressed_pixels; + + d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, 0, NULL, uncompressed_desc->format, + 0, 0, src_pixels->size.width, src_pixels->size.height, 0, src_pixels->size.depth, + &uncompressed_pixels); + + hr = d3dx_load_pixels_from_pixels(dst_pixels, dst_desc, &uncompressed_pixels, uncompressed_desc, filter_flags, color_key); } free(uncompressed_mem); - return hr; + goto exit; }
/* Same as the above, need to decompress the destination prior to modifying. */ if (dst_desc->type == FORMAT_DXT) { const struct pixel_format_desc *uncompressed_desc; + struct d3dx_pixels uncompressed_pixels; + RECT uncompressed_rect, aligned_rect; uint32_t uncompressed_row_pitch; void *uncompressed_mem = NULL; - BYTE *uncompressed_mem_offset; - RECT uncompressed_rect;
- hr = d3dx_image_decompress(dst_memory, dst_row_pitch, dst_rect_aligned, dst_rect, &dst_size_aligned, dst_desc, - &uncompressed_mem, &uncompressed_row_pitch, &uncompressed_rect, &uncompressed_desc); + SetRect(&aligned_rect, 0, 0, dst_pixels->size.width, dst_pixels->size.height); + hr = d3dx_image_decompress(dst_pixels->data, dst_pixels->row_pitch, &aligned_rect, + &dst_pixels->unaligned_rect, &dst_size_aligned, dst_desc, &uncompressed_mem, &uncompressed_row_pitch, + &uncompressed_rect, &uncompressed_desc); if (FAILED(hr)) - return hr; + goto exit; + + d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, 0, NULL, + uncompressed_desc->format, dst_pixels->unaligned_rect.left, dst_pixels->unaligned_rect.top, + dst_pixels->unaligned_rect.right, dst_pixels->unaligned_rect.bottom, 0, 1, &uncompressed_pixels);
- uncompressed_mem_offset = (BYTE *)uncompressed_mem + (dst_rect->top - dst_rect_aligned->top) * uncompressed_row_pitch - + (dst_rect->left - dst_rect_aligned->left) * uncompressed_desc->bytes_per_pixel; - hr = d3dx_load_image_from_memory(uncompressed_mem_offset, uncompressed_row_pitch, uncompressed_desc, dst_palette, - &uncompressed_rect, &uncompressed_rect, src_memory, src_row_pitch, src_desc, src_palette, - src_rect, filter_flags, color_key); + hr = d3dx_load_pixels_from_pixels(&uncompressed_pixels, uncompressed_desc, src_pixels, src_desc, filter_flags, + color_key); if (SUCCEEDED(hr)) { GLenum gl_format = 0; @@ -2074,16 +2132,17 @@ static HRESULT d3dx_load_image_from_memory(void *dst_memory, uint32_t dst_row_pi ERR("Unexpected destination compressed format %u.\n", dst_desc->format); } tx_compress_dxtn(4, dst_size_aligned.width, dst_size_aligned.height, uncompressed_mem, gl_format, - dst_memory, dst_row_pitch); + (BYTE *)dst_pixels->data, dst_pixels->row_pitch); } free(uncompressed_mem); - return hr; + goto exit; }
if ((filter_flags & 0xf) == D3DX_FILTER_NONE) { - convert_argb_pixels(src_memory_offset, src_row_pitch, 0, &src_size, src_desc, - dst_memory, dst_row_pitch, 0, &dst_size, dst_desc, color_key, src_palette); + convert_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, src_desc, + (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, dst_desc, + color_key, src_pixels->palette); } else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ { @@ -2092,10 +2151,14 @@ static HRESULT d3dx_load_image_from_memory(void *dst_memory, uint32_t dst_row_pi
/* Always apply a point filter until D3DX_FILTER_LINEAR, * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ - point_filter_argb_pixels(src_memory_offset, src_row_pitch, 0, &src_size, src_desc, dst_memory, dst_row_pitch, 0, - &dst_size, dst_desc, color_key, src_palette); + point_filter_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, + src_desc, (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, + dst_desc, color_key, src_pixels->palette); }
+exit: + if (FAILED(hr)) + WARN("Failed to load pixels, hr %#lx.\n", hr); return hr; }
@@ -2136,8 +2199,9 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, D3DFORMAT src_format, UINT src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect, DWORD filter, D3DCOLOR color_key) { - RECT dst_rect_temp, dst_rect_aligned, dst_locked_rect, dst_locked_rect_aligned; const struct pixel_format_desc *srcformatdesc, *destformatdesc; + struct d3dx_pixels src_pixels, dst_pixels; + RECT dst_rect_temp, dst_rect_aligned; IDirect3DSurface9 *surface; D3DSURFACE_DESC surfdesc; D3DLOCKED_RECT lockrect; @@ -2209,17 +2273,21 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, if (filter == D3DX_DEFAULT) filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER;
+ hr = d3dx_pixels_init(src_memory, src_pitch, 0, src_palette, srcformatdesc->format, + src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1, &src_pixels); + if (FAILED(hr)) + return hr; + if (FAILED(hr = lock_surface(dst_surface, &dst_rect_aligned, &lockrect, &surface, TRUE))) return hr;
- dst_locked_rect_aligned = dst_rect_aligned; - dst_locked_rect = *dst_rect; - OffsetRect(&dst_locked_rect_aligned, -dst_rect_aligned.left, -dst_rect_aligned.top); - OffsetRect(&dst_locked_rect, -dst_rect_aligned.left, -dst_rect_aligned.top); - hr = d3dx_load_image_from_memory(lockrect.pBits, lockrect.Pitch, destformatdesc, dst_palette, &dst_locked_rect, - &dst_locked_rect_aligned, src_memory, src_pitch, srcformatdesc, src_palette, src_rect, filter, color_key); - if (FAILED(hr)) - WARN("d3dx_load_image_from_memory failed with hr %#lx\n", hr); + + set_d3dx_pixels(&dst_pixels, lockrect.pBits, lockrect.Pitch, 0, dst_palette, + (dst_rect_aligned.right - dst_rect_aligned.left), (dst_rect_aligned.bottom - dst_rect_aligned.top), 1, + dst_rect); + OffsetRect(&dst_pixels.unaligned_rect, -dst_rect_aligned.left, -dst_rect_aligned.top); + + d3dx_load_pixels_from_pixels(&dst_pixels, destformatdesc, &src_pixels, srcformatdesc, filter, color_key);
return unlock_surface(dst_surface, &dst_rect_aligned, surface, TRUE); }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 52 ++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 21 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 327af791489..a249fedde84 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1901,12 +1901,12 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic } }
-static HRESULT d3dx_image_decompress(const void *memory, uint32_t row_pitch, const RECT *rect, - const RECT *unaligned_rect, const struct volume *size, const struct pixel_format_desc *desc, - void **out_memory, uint32_t *out_row_pitch, RECT *out_rect, const struct pixel_format_desc **out_desc) +static HRESULT d3dx_pixels_decompress(struct d3dx_pixels *pixels, const struct pixel_format_desc *desc, + BOOL is_dst, void **out_memory, uint32_t *out_row_pitch, const struct pixel_format_desc **out_desc) { void (*fetch_dxt_texel)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); const struct pixel_format_desc *uncompressed_desc = NULL; + const struct volume *size = &pixels->size; uint32_t x, y, tmp_pitch; BYTE *uncompressed_mem;
@@ -1934,11 +1934,26 @@ static HRESULT d3dx_image_decompress(const void *memory, uint32_t row_pitch, con if (!(uncompressed_mem = malloc(size->width * size->height * size->depth * uncompressed_desc->bytes_per_pixel))) return E_OUTOFMEMORY;
- if (unaligned_rect && EqualRect(rect, unaligned_rect)) - goto exit; + /* + * For compressed destination pixels, width/height will represent + * the entire set of compressed blocks our destination rectangle touches. + * If we're only updating a sub-area of any blocks, we need to decompress + * the pixels outside of the sub-area. + */ + if (is_dst) + { + const RECT aligned_rect = { 0, 0, size->width, size->height };
- TRACE("Decompressing image.\n"); - tmp_pitch = row_pitch * desc->block_width / desc->block_byte_count; + /* + * If our destination covers the entire set of blocks, no + * decompression needs to be done, just return the allocated memory. + */ + if (EqualRect(&aligned_rect, &pixels->unaligned_rect)) + goto exit; + } + + TRACE("Decompressing pixels.\n"); + tmp_pitch = pixels->row_pitch * desc->block_width / desc->block_byte_count; for (y = 0; y < size->height; ++y) { BYTE *ptr = &uncompressed_mem[y * size->width * uncompressed_desc->bytes_per_pixel]; @@ -1946,8 +1961,11 @@ static HRESULT d3dx_image_decompress(const void *memory, uint32_t row_pitch, con { const POINT pt = { x, y };
- if (!PtInRect(unaligned_rect, pt)) - fetch_dxt_texel(tmp_pitch, (BYTE *)memory, x + rect->left, y + rect->top, ptr); + if (!is_dst) + fetch_dxt_texel(tmp_pitch, (BYTE *)pixels->data, x + pixels->unaligned_rect.left, + y + pixels->unaligned_rect.top, ptr); + else if (!PtInRect(&pixels->unaligned_rect, pt)) + fetch_dxt_texel(tmp_pitch, (BYTE *)pixels->data, x, y, ptr); ptr += uncompressed_desc->bytes_per_pixel; } } @@ -1955,10 +1973,6 @@ static HRESULT d3dx_image_decompress(const void *memory, uint32_t row_pitch, con exit: *out_memory = uncompressed_mem; *out_row_pitch = size->width * uncompressed_desc->bytes_per_pixel; - if (unaligned_rect) - *out_rect = *unaligned_rect; - else - SetRect(out_rect, 0, 0, size->width, size->height); *out_desc = uncompressed_desc;
return S_OK; @@ -2069,10 +2083,9 @@ static HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, const struct pixel_format_desc *uncompressed_desc; uint32_t uncompressed_row_pitch; void *uncompressed_mem = NULL; - RECT uncompressed_rect;
- hr = d3dx_image_decompress(src_pixels->data, src_pixels->row_pitch, &src_pixels->unaligned_rect, NULL, - &src_size, src_desc, &uncompressed_mem, &uncompressed_row_pitch, &uncompressed_rect, &uncompressed_desc); + hr = d3dx_pixels_decompress(src_pixels, src_desc, FALSE, &uncompressed_mem, &uncompressed_row_pitch, + &uncompressed_desc); if (SUCCEEDED(hr)) { struct d3dx_pixels uncompressed_pixels; @@ -2093,14 +2106,11 @@ static HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, { const struct pixel_format_desc *uncompressed_desc; struct d3dx_pixels uncompressed_pixels; - RECT uncompressed_rect, aligned_rect; uint32_t uncompressed_row_pitch; void *uncompressed_mem = NULL;
- SetRect(&aligned_rect, 0, 0, dst_pixels->size.width, dst_pixels->size.height); - hr = d3dx_image_decompress(dst_pixels->data, dst_pixels->row_pitch, &aligned_rect, - &dst_pixels->unaligned_rect, &dst_size_aligned, dst_desc, &uncompressed_mem, &uncompressed_row_pitch, - &uncompressed_rect, &uncompressed_desc); + hr = d3dx_pixels_decompress(dst_pixels, dst_desc, TRUE, &uncompressed_mem, &uncompressed_row_pitch, + &uncompressed_desc); if (FAILED(hr)) goto exit;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 8 ++ dlls/d3dx9_36/surface.c | 105 +++++++++++++++---------- dlls/d3dx9_36/tests/volume.c | 2 +- dlls/d3dx9_36/volume.c | 142 ++++++++++++---------------------- 4 files changed, 122 insertions(+), 135 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 722ed73ae0f..001a7f26f4f 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -182,6 +182,14 @@ 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); +HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, + const PALETTEENTRY *palette, D3DFORMAT format, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, + uint32_t front, uint32_t back, struct d3dx_pixels *pixels); +HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, + const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, + const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key); +void get_aligned_rect(uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t width, uint32_t height, + const struct pixel_format_desc *fmt_desc, RECT *aligned_rect);
unsigned short float_32_to_16(const float in); float float_16_to_32(const unsigned short in); diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index a249fedde84..dd84528a0d5 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1902,12 +1902,13 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic }
static HRESULT d3dx_pixels_decompress(struct d3dx_pixels *pixels, const struct pixel_format_desc *desc, - BOOL is_dst, void **out_memory, uint32_t *out_row_pitch, const struct pixel_format_desc **out_desc) + BOOL is_dst, void **out_memory, uint32_t *out_row_pitch, uint32_t *out_slice_pitch, + const struct pixel_format_desc **out_desc) { void (*fetch_dxt_texel)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); + uint32_t x, y, z, tmp_pitch, uncompressed_slice_pitch, uncompressed_row_pitch; const struct pixel_format_desc *uncompressed_desc = NULL; const struct volume *size = &pixels->size; - uint32_t x, y, tmp_pitch; BYTE *uncompressed_mem;
switch (desc->format) @@ -1931,7 +1932,9 @@ static HRESULT d3dx_pixels_decompress(struct d3dx_pixels *pixels, const struct p return E_NOTIMPL; }
- if (!(uncompressed_mem = malloc(size->width * size->height * size->depth * uncompressed_desc->bytes_per_pixel))) + uncompressed_row_pitch = size->width * uncompressed_desc->bytes_per_pixel; + uncompressed_slice_pitch = uncompressed_row_pitch * size->height; + if (!(uncompressed_mem = malloc(size->depth * uncompressed_slice_pitch))) return E_OUTOFMEMORY;
/* @@ -1954,31 +1957,37 @@ static HRESULT d3dx_pixels_decompress(struct d3dx_pixels *pixels, const struct p
TRACE("Decompressing pixels.\n"); tmp_pitch = pixels->row_pitch * desc->block_width / desc->block_byte_count; - for (y = 0; y < size->height; ++y) + for (z = 0; z < size->depth; ++z) { - BYTE *ptr = &uncompressed_mem[y * size->width * uncompressed_desc->bytes_per_pixel]; - for (x = 0; x < size->width; ++x) + const BYTE *slice_data = ((BYTE *)pixels->data) + (pixels->slice_pitch * z); + + for (y = 0; y < size->height; ++y) { - const POINT pt = { x, y }; - - if (!is_dst) - fetch_dxt_texel(tmp_pitch, (BYTE *)pixels->data, x + pixels->unaligned_rect.left, - y + pixels->unaligned_rect.top, ptr); - else if (!PtInRect(&pixels->unaligned_rect, pt)) - fetch_dxt_texel(tmp_pitch, (BYTE *)pixels->data, x, y, ptr); - ptr += uncompressed_desc->bytes_per_pixel; + BYTE *ptr = &uncompressed_mem[(z * uncompressed_slice_pitch) + (y * uncompressed_row_pitch)]; + for (x = 0; x < size->width; ++x) + { + const POINT pt = { x, y }; + + if (!is_dst) + fetch_dxt_texel(tmp_pitch, slice_data, x + pixels->unaligned_rect.left, + y + pixels->unaligned_rect.top, ptr); + else if (!PtInRect(&pixels->unaligned_rect, pt)) + fetch_dxt_texel(tmp_pitch, slice_data, x, y, ptr); + ptr += uncompressed_desc->bytes_per_pixel; + } } }
exit: *out_memory = uncompressed_mem; - *out_row_pitch = size->width * uncompressed_desc->bytes_per_pixel; + *out_row_pitch = uncompressed_row_pitch; + *out_slice_pitch = uncompressed_slice_pitch; *out_desc = uncompressed_desc;
return S_OK; }
-static HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, +HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, const PALETTEENTRY *palette, D3DFORMAT format, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t front, uint32_t back, struct d3dx_pixels *pixels) { @@ -2026,7 +2035,7 @@ static const char *debug_d3dx_pixels(struct d3dx_pixels *pixels) pixels->size.width, pixels->size.height, pixels->size.depth, wine_dbgstr_rect(&pixels->unaligned_rect)); }
-static HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, +HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key) { @@ -2054,6 +2063,7 @@ static HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, if (src_desc->format == dst_desc->format && (dst_size.width == src_size.width && !(dst_size.width % dst_desc->block_width)) && (dst_size.height == src_size.height && !(dst_size.height % dst_desc->block_height)) + && (dst_size.depth == src_size.depth) && color_key == 0 && !(src_pixels->unaligned_rect.left & (src_desc->block_width - 1)) && !(src_pixels->unaligned_rect.top & (src_desc->block_height - 1)) @@ -2080,19 +2090,19 @@ static HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, */ if (src_desc->type == FORMAT_DXT) { + uint32_t uncompressed_row_pitch, uncompressed_slice_pitch; const struct pixel_format_desc *uncompressed_desc; - uint32_t uncompressed_row_pitch; void *uncompressed_mem = NULL;
hr = d3dx_pixels_decompress(src_pixels, src_desc, FALSE, &uncompressed_mem, &uncompressed_row_pitch, - &uncompressed_desc); + &uncompressed_slice_pitch, &uncompressed_desc); if (SUCCEEDED(hr)) { struct d3dx_pixels uncompressed_pixels;
- d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, 0, NULL, uncompressed_desc->format, - 0, 0, src_pixels->size.width, src_pixels->size.height, 0, src_pixels->size.depth, - &uncompressed_pixels); + d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, + uncompressed_desc->format, 0, 0, src_pixels->size.width, src_pixels->size.height, + 0, src_pixels->size.depth, &uncompressed_pixels);
hr = d3dx_load_pixels_from_pixels(dst_pixels, dst_desc, &uncompressed_pixels, uncompressed_desc, filter_flags, color_key); @@ -2104,25 +2114,27 @@ static HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, /* Same as the above, need to decompress the destination prior to modifying. */ if (dst_desc->type == FORMAT_DXT) { + uint32_t uncompressed_row_pitch, uncompressed_slice_pitch; const struct pixel_format_desc *uncompressed_desc; struct d3dx_pixels uncompressed_pixels; - uint32_t uncompressed_row_pitch; void *uncompressed_mem = NULL;
hr = d3dx_pixels_decompress(dst_pixels, dst_desc, TRUE, &uncompressed_mem, &uncompressed_row_pitch, - &uncompressed_desc); + &uncompressed_slice_pitch, &uncompressed_desc); if (FAILED(hr)) goto exit;
- d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, 0, NULL, + d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, uncompressed_desc->format, dst_pixels->unaligned_rect.left, dst_pixels->unaligned_rect.top, - dst_pixels->unaligned_rect.right, dst_pixels->unaligned_rect.bottom, 0, 1, &uncompressed_pixels); + dst_pixels->unaligned_rect.right, dst_pixels->unaligned_rect.bottom, 0, dst_pixels->size.depth, + &uncompressed_pixels);
hr = d3dx_load_pixels_from_pixels(&uncompressed_pixels, uncompressed_desc, src_pixels, src_desc, filter_flags, color_key); if (SUCCEEDED(hr)) { GLenum gl_format = 0; + uint32_t i;
TRACE("Compressing DXTn surface.\n"); switch (dst_desc->format) @@ -2141,8 +2153,15 @@ static HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, default: ERR("Unexpected destination compressed format %u.\n", dst_desc->format); } - tx_compress_dxtn(4, dst_size_aligned.width, dst_size_aligned.height, uncompressed_mem, gl_format, - (BYTE *)dst_pixels->data, dst_pixels->row_pitch); + + for (i = 0; i < dst_size_aligned.depth; ++i) + { + BYTE *uncompressed_mem_slice = (BYTE *)uncompressed_mem + (i * uncompressed_slice_pitch); + BYTE *dst_memory_slice = ((BYTE *)dst_pixels->data) + (i * dst_pixels->slice_pitch); + + tx_compress_dxtn(4, dst_size_aligned.width, dst_size_aligned.height, uncompressed_mem_slice, gl_format, + dst_memory_slice, dst_pixels->row_pitch); + } } free(uncompressed_mem); goto exit; @@ -2172,6 +2191,22 @@ exit: return hr; }
+void get_aligned_rect(uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t width, uint32_t height, + const struct pixel_format_desc *fmt_desc, RECT *aligned_rect) +{ + SetRect(aligned_rect, left, top, right, bottom); + if (aligned_rect->left & (fmt_desc->block_width - 1)) + aligned_rect->left = aligned_rect->left & ~(fmt_desc->block_width - 1); + if (aligned_rect->top & (fmt_desc->block_height - 1)) + aligned_rect->top = aligned_rect->top & ~(fmt_desc->block_height - 1); + if (aligned_rect->right & (fmt_desc->block_width - 1) && aligned_rect->right != width) + aligned_rect->right = min((aligned_rect->right + fmt_desc->block_width - 1) + & ~(fmt_desc->block_width - 1), width); + if (aligned_rect->bottom & (fmt_desc->block_height - 1) && aligned_rect->bottom != height) + aligned_rect->bottom = min((aligned_rect->bottom + fmt_desc->block_height - 1) + & ~(fmt_desc->block_height - 1), height); +} + /************************************************************ * D3DXLoadSurfaceFromMemory * @@ -2268,18 +2303,6 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, } }
- dst_rect_aligned = *dst_rect; - if (dst_rect_aligned.left & (destformatdesc->block_width - 1)) - dst_rect_aligned.left = dst_rect_aligned.left & ~(destformatdesc->block_width - 1); - if (dst_rect_aligned.top & (destformatdesc->block_height - 1)) - dst_rect_aligned.top = dst_rect_aligned.top & ~(destformatdesc->block_height - 1); - if (dst_rect_aligned.right & (destformatdesc->block_width - 1) && dst_rect_aligned.right != surfdesc.Width) - dst_rect_aligned.right = min((dst_rect_aligned.right + destformatdesc->block_width - 1) - & ~(destformatdesc->block_width - 1), surfdesc.Width); - if (dst_rect_aligned.bottom & (destformatdesc->block_height - 1) && dst_rect_aligned.bottom != surfdesc.Height) - dst_rect_aligned.bottom = min((dst_rect_aligned.bottom + destformatdesc->block_height - 1) - & ~(destformatdesc->block_height - 1), surfdesc.Height); - if (filter == D3DX_DEFAULT) filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER;
@@ -2288,6 +2311,8 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, if (FAILED(hr)) return hr;
+ get_aligned_rect(dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, surfdesc.Width, surfdesc.Height, + destformatdesc, &dst_rect_aligned); if (FAILED(hr = lock_surface(dst_surface, &dst_rect_aligned, &lockrect, &surface, TRUE))) return hr;
diff --git a/dlls/d3dx9_36/tests/volume.c b/dlls/d3dx9_36/tests/volume.c index 52075aa6314..f990221f06b 100644 --- a/dlls/d3dx9_36/tests/volume.c +++ b/dlls/d3dx9_36/tests/volume.c @@ -205,7 +205,7 @@ static void test_D3DXLoadVolumeFromMemory(IDirect3DDevice9 *device) set_box(&src_box, 1, 1, 7, 7, 0, 1); set_box(&dst_box, 1, 1, 7, 7, 0, 1); hr = D3DXLoadVolumeFromMemory(volume, NULL, &dst_box, pixels, D3DFMT_A8R8G8B8, 16, 32, NULL, &src_box, D3DX_DEFAULT, 0); - todo_wine ok(hr == D3D_OK, "D3DXLoadVolumeFromMemory returned %#lx, expected %#lx\n", hr, D3D_OK); + ok(hr == D3D_OK, "D3DXLoadVolumeFromMemory returned %#lx, expected %#lx\n", hr, D3D_OK);
IDirect3DVolume9_Release(volume); IDirect3DVolumeTexture9_Release(volume_texture); diff --git a/dlls/d3dx9_36/volume.c b/dlls/d3dx9_36/volume.c index 4d29cfe1e31..0006a521532 100644 --- a/dlls/d3dx9_36/volume.c +++ b/dlls/d3dx9_36/volume.c @@ -71,16 +71,29 @@ HRESULT WINAPI D3DXLoadVolumeFromFileW(IDirect3DVolume9 *dst_volume, const PALET return hr; }
+static void set_d3dbox(D3DBOX *box, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t front, + uint32_t back) +{ + box->Left = left; + box->Top = top; + box->Right = right; + box->Bottom = bottom; + box->Front = front; + box->Back = back; +} + HRESULT WINAPI D3DXLoadVolumeFromMemory(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *dst_palette, const D3DBOX *dst_box, const void *src_memory, D3DFORMAT src_format, UINT src_row_pitch, UINT src_slice_pitch, const PALETTEENTRY *src_palette, const D3DBOX *src_box, DWORD filter, D3DCOLOR color_key) { - HRESULT hr; - D3DVOLUME_DESC desc; - D3DLOCKED_BOX locked_box; - struct volume dst_size, src_size; const struct pixel_format_desc *src_format_desc, *dst_format_desc; + struct d3dx_pixels src_pixels, dst_pixels; + RECT dst_rect_aligned, dst_rect_unaligned; + D3DBOX dst_box_aligned, dst_box_tmp; + D3DLOCKED_BOX locked_box; + D3DVOLUME_DESC desc; + HRESULT hr;
TRACE("dst_volume %p, dst_palette %p, dst_box %p, src_memory %p, src_format %#x, " "src_row_pitch %u, src_slice_pitch %u, src_palette %p, src_box %p, filter %#lx, color_key 0x%08lx.\n", @@ -98,17 +111,19 @@ HRESULT WINAPI D3DXLoadVolumeFromMemory(IDirect3DVolume9 *dst_volume, if (filter == D3DX_DEFAULT) filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER;
- IDirect3DVolume9_GetDesc(dst_volume, &desc); + src_format_desc = get_format_info(src_format); + if (src_format_desc->type == FORMAT_UNKNOWN) + return E_NOTIMPL;
- src_size.width = src_box->Right - src_box->Left; - src_size.height = src_box->Bottom - src_box->Top; - src_size.depth = src_box->Back - src_box->Front; + IDirect3DVolume9_GetDesc(dst_volume, &desc); + dst_format_desc = get_format_info(desc.Format); + if (dst_format_desc->type == FORMAT_UNKNOWN) + return E_NOTIMPL;
if (!dst_box) { - dst_size.width = desc.Width; - dst_size.height = desc.Height; - dst_size.depth = desc.Depth; + set_d3dbox(&dst_box_tmp, 0, 0, desc.Width, desc.Height, 0, desc.Depth); + dst_box = &dst_box_tmp; } else { @@ -118,94 +133,33 @@ HRESULT WINAPI D3DXLoadVolumeFromMemory(IDirect3DVolume9 *dst_volume, return D3DERR_INVALIDCALL; if (dst_box->Front >= dst_box->Back || dst_box->Back > desc.Depth) return D3DERR_INVALIDCALL; - - dst_size.width = dst_box->Right - dst_box->Left; - dst_size.height = dst_box->Bottom - dst_box->Top; - dst_size.depth = dst_box->Back - dst_box->Front; }
- src_format_desc = get_format_info(src_format); - if (src_format_desc->type == FORMAT_UNKNOWN) - return E_NOTIMPL; + hr = d3dx_pixels_init(src_memory, src_row_pitch, src_slice_pitch, + src_palette, src_format, src_box->Left, src_box->Top, src_box->Right, src_box->Bottom, + src_box->Front, src_box->Back, &src_pixels); + if (FAILED(hr)) + return hr;
- dst_format_desc = get_format_info(desc.Format); - if (dst_format_desc->type == FORMAT_UNKNOWN) - return E_NOTIMPL; + get_aligned_rect(dst_box->Left, dst_box->Top, dst_box->Right, dst_box->Bottom, desc.Width, desc.Height, + dst_format_desc, &dst_rect_aligned); + set_d3dbox(&dst_box_aligned, dst_rect_aligned.left, dst_rect_aligned.top, dst_rect_aligned.right, + dst_rect_aligned.bottom, dst_box->Front, dst_box->Back);
- if (desc.Format == src_format - && dst_size.width == src_size.width - && dst_size.height == src_size.height - && dst_size.depth == src_size.depth - && color_key == 0) - { - const BYTE *src_addr; - - if (src_box->Left & (src_format_desc->block_width - 1) - || src_box->Top & (src_format_desc->block_height - 1) - || (src_box->Right & (src_format_desc->block_width - 1) - && src_size.width != desc.Width) - || (src_box->Bottom & (src_format_desc->block_height - 1) - && src_size.height != desc.Height)) - { - FIXME("Source box (%u, %u, %u, %u) is misaligned\n", - src_box->Left, src_box->Top, src_box->Right, src_box->Bottom); - return E_NOTIMPL; - } - - src_addr = src_memory; - src_addr += src_box->Front * src_slice_pitch; - src_addr += (src_box->Top / src_format_desc->block_height) * src_row_pitch; - src_addr += (src_box->Left / src_format_desc->block_width) * src_format_desc->block_byte_count; - - hr = IDirect3DVolume9_LockBox(dst_volume, &locked_box, dst_box, 0); - if (FAILED(hr)) return hr; - - copy_pixels(src_addr, src_row_pitch, src_slice_pitch, - locked_box.pBits, locked_box.RowPitch, locked_box.SlicePitch, - &dst_size, dst_format_desc); - - IDirect3DVolume9_UnlockBox(dst_volume); - } - else - { - const BYTE *src_addr; - - if (!is_conversion_from_supported(src_format_desc) - || !is_conversion_to_supported(dst_format_desc)) - { - FIXME("Pixel format conversion is not implemented %#x -> %#x\n", - src_format_desc->format, dst_format_desc->format); - return E_NOTIMPL; - } - - src_addr = src_memory; - src_addr += src_box->Front * src_slice_pitch; - src_addr += src_box->Top * src_row_pitch; - src_addr += src_box->Left * src_format_desc->bytes_per_pixel; - - hr = IDirect3DVolume9_LockBox(dst_volume, &locked_box, dst_box, 0); - if (FAILED(hr)) return hr; - - if ((filter & 0xf) == D3DX_FILTER_NONE) - { - convert_argb_pixels(src_memory, src_row_pitch, src_slice_pitch, &src_size, src_format_desc, - locked_box.pBits, locked_box.RowPitch, locked_box.SlicePitch, &dst_size, dst_format_desc, color_key, - src_palette); - } - else - { - if ((filter & 0xf) != D3DX_FILTER_POINT) - FIXME("Unhandled filter %#lx.\n", filter); - - point_filter_argb_pixels(src_addr, src_row_pitch, src_slice_pitch, &src_size, src_format_desc, - locked_box.pBits, locked_box.RowPitch, locked_box.SlicePitch, &dst_size, dst_format_desc, color_key, - src_palette); - } - - IDirect3DVolume9_UnlockBox(dst_volume); - } + hr = IDirect3DVolume9_LockBox(dst_volume, &locked_box, &dst_box_aligned, 0); + if (FAILED(hr)) + return hr;
- return D3D_OK; + SetRect(&dst_rect_unaligned, dst_box->Left, dst_box->Top, dst_box->Right, dst_box->Bottom); + OffsetRect(&dst_rect_unaligned, -dst_rect_aligned.left, -dst_rect_aligned.top); + set_d3dx_pixels(&dst_pixels, locked_box.pBits, locked_box.RowPitch, locked_box.SlicePitch, dst_palette, + (dst_box_aligned.Right - dst_box_aligned.Left), (dst_box_aligned.Bottom - dst_box_aligned.Top), + (dst_box_aligned.Back - dst_box_aligned.Front), &dst_rect_unaligned); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_format_desc, &src_pixels, src_format_desc, filter, + color_key); + IDirect3DVolume9_UnlockBox(dst_volume); + return hr; }
HRESULT WINAPI D3DXLoadVolumeFromFileInMemory(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *dst_palette,
On Thu May 30 14:57:54 2024 +0000, Connor McAdams wrote:
I remember at some point I deep dived into how this worked and was also confused by the usage of min here. I _think_ if block_height was 0 it might be necessary? But AFAICT, block height is always set to at least 1.
actually I take that back, that would only make sense if it was `max()`. I can't figure out what use the `min()` here serves.
On Thu May 30 18:30:18 2024 +0000, Connor McAdams wrote:
actually I take that back, that would only make sense if it was `max()`. I can't figure out what use the `min()` here serves. Actually, I _think_ it's because you can have a surface that has a non block-aligned width/height. E.g if you had a 3x3 DXT5 surface, you specified a 2x2 destination rectangle, this would round up to 4, but we should cap it at 3.
Ahhh yes, that's probably it. Thanks for making sense of my old code! :sweat_smile:
On Thu May 30 18:30:18 2024 +0000, Matteo Bruni wrote:
Ahhh yes, that's probably it. Thanks for making sense of my old code! :sweat_smile:
Ha no problem, it started to bug me while I was taking a walk because I _knew_ at some point I had questioned why this was here and came up with a reason, but I couldn't remember it exactly. Sorry for the amount of edits/comments :)
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/d3dx9_private.h:
void (*to_rgba)(const struct vec4 *src, struct vec4 *dst, const PALETTEENTRY *palette);
};
+struct d3dx_image +{
- D3DRESOURCETYPE resource_type;
- D3DFORMAT format;
- uint32_t width;
- uint32_t height;
- uint32_t depth;
We might want to use `struct volume` here as well, at some point.
This merge request was approved by Matteo Bruni.
Very unimportant comment: the MR subject isn't entirely accurate at this point :slight_smile: