From: Józef Kucia Subject: [2/5] d3dx9: Implement D3DXSaveSurfaceToFileInMemory. Message-Id: <1338181645-11962-2-git-send-email-joseph.kucia@gmail.com> Date: Mon, 28 May 2012 07:07:22 +0200 Fixes bug 23706. --- dlls/d3dx9_36/d3dx9_36.spec | 2 +- dlls/d3dx9_36/d3dx9_36_private.h | 2 + dlls/d3dx9_36/surface.c | 93 ++++++++++++++++++++++++++++++++----- dlls/d3dx9_36/tests/surface.c | 27 +++++++++++ dlls/d3dx9_36/util.c | 19 ++++++++ include/d3dx9tex.h | 6 +++ 6 files changed, 135 insertions(+), 14 deletions(-) diff --git a/dlls/d3dx9_36/d3dx9_36.spec b/dlls/d3dx9_36/d3dx9_36.spec index aa2046a..44efaf5 100644 --- a/dlls/d3dx9_36/d3dx9_36.spec +++ b/dlls/d3dx9_36/d3dx9_36.spec @@ -264,7 +264,7 @@ @ stub D3DXSavePRTCompBufferToFileA(ptr ptr) @ stub D3DXSavePRTCompBufferToFileW(ptr ptr) @ stdcall D3DXSaveSurfaceToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveSurfaceToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveSurfaceToFileInMemory(ptr long ptr ptr ptr) @ stdcall D3DXSaveSurfaceToFileW(ptr long ptr ptr ptr) @ stub D3DXSaveTextureToFileA(ptr long ptr ptr) @ stub D3DXSaveTextureToFileInMemory(ptr long ptr ptr) diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h index be460f2..1cbb7cf 100644 --- a/dlls/d3dx9_36/d3dx9_36_private.h +++ b/dlls/d3dx9_36/d3dx9_36_private.h @@ -59,6 +59,8 @@ typedef struct _PixelFormatDesc { HRESULT map_view_of_file(LPCWSTR filename, LPVOID *buffer, DWORD *length) DECLSPEC_HIDDEN; HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, LPVOID *buffer, DWORD *length) DECLSPEC_HIDDEN; +HRESULT write_buffer_to_file(const WCHAR *filename, ID3DXBuffer *buffer) DECLSPEC_HIDDEN; + const PixelFormatDesc *get_format_info(D3DFORMAT format) DECLSPEC_HIDDEN; const PixelFormatDesc *get_format_info_idx(int idx) DECLSPEC_HIDDEN; diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index d490cef..1e0ae02 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -23,6 +23,7 @@ #include "d3dx9_36_private.h" #include "initguid.h" +#include "ole2.h" #include "wincodec.h" WINE_DEFAULT_DEBUG_CHANNEL(d3dx); @@ -1584,6 +1585,7 @@ HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFO int len; WCHAR *filename; HRESULT hr; + ID3DXBuffer *buffer; TRACE("(%s, %#x, %p, %p, %s): relay\n", wine_dbgstr_a(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); @@ -1595,7 +1597,12 @@ HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFO if (!filename) return E_OUTOFMEMORY; MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len); - hr = D3DXSaveSurfaceToFileW(filename, file_format, src_surface, src_palette, src_rect); + hr = D3DXSaveSurfaceToFileInMemory(&buffer, file_format, src_surface, src_palette, src_rect); + if (SUCCEEDED(hr)) + { + hr = write_buffer_to_file(filename, buffer); + ID3DXBuffer_Release(buffer); + } HeapFree(GetProcessHeap(), 0, filename); return hr; @@ -1604,11 +1611,33 @@ HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFO HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format, IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect) { + HRESULT hr; + ID3DXBuffer *buffer; + + TRACE("(%s, %#x, %p, %p, %s): relay\n", + wine_dbgstr_w(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); + + if (!dst_filename) return D3DERR_INVALIDCALL; + + hr = D3DXSaveSurfaceToFileInMemory(&buffer, file_format, src_surface, src_palette, src_rect); + if (SUCCEEDED(hr)) + { + hr = write_buffer_to_file(dst_filename, buffer); + ID3DXBuffer_Release(buffer); + } + + return hr; +} + +HRESULT WINAPI D3DXSaveSurfaceToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, + IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect) +{ IWICImagingFactory *factory; IWICBitmapEncoder *encoder = NULL; IWICBitmapFrameEncode *frame = NULL; IPropertyBag2 *encoder_options = NULL; - IWICStream *stream = NULL; + IStream *stream = NULL; + IWICStream *wic_stream = NULL; HRESULT hr; HRESULT initresult; const CLSID *encoder_clsid; @@ -1618,11 +1647,15 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF D3DSURFACE_DESC src_surface_desc; D3DLOCKED_RECT locked_rect; int width, height; + STATSTG stream_stats; + HGLOBAL stream_hglobal; + ID3DXBuffer *buffer; + DWORD size; - TRACE("(%s, %#x, %p, %p, %s)\n", - wine_dbgstr_w(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); + TRACE("(%p, %#x, %p, %p, %s)\n", + dst_buffer, file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); - if (!dst_filename || !src_surface) return D3DERR_INVALIDCALL; + if (!dst_buffer || !src_surface) return D3DERR_INVALIDCALL; if (src_palette) { @@ -1657,7 +1690,10 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF if (src_rect) { if (src_rect->left == src_rect->right || src_rect->top == src_rect->bottom) - return D3D_OK; + { + WARN("Invalid rectangle with 0 area\n"); + return D3DXCreateBuffer(64, dst_buffer); + } if (src_rect->left < 0 || src_rect->top < 0) return D3DERR_INVALIDCALL; if (src_rect->left > src_rect->right || src_rect->top > src_rect->bottom) @@ -1680,20 +1716,25 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF &IID_IWICImagingFactory, (void **)&factory); if (FAILED(hr)) goto cleanup_err; - hr = IWICImagingFactory_CreateStream(factory, &stream); + hr = IWICImagingFactory_CreateStream(factory, &wic_stream); IWICImagingFactory_Release(factory); if (FAILED(hr)) goto cleanup_err; - hr = IWICStream_InitializeFromFilename(stream, dst_filename, GENERIC_WRITE); + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); if (FAILED(hr)) goto cleanup_err; + hr = IWICStream_InitializeFromIStream(wic_stream, stream); + if (FAILED(hr)) + { + IStream_Release(stream); + goto cleanup_err; + } + hr = CoCreateInstance(encoder_clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IWICBitmapEncoder, (void **)&encoder); if (FAILED(hr)) goto cleanup_err; - hr = IWICBitmapEncoder_Initialize(encoder, (IStream *)stream, WICBitmapEncoderNoCache); - IStream_Release((IStream *)stream); - stream = NULL; + hr = IWICBitmapEncoder_Initialize(encoder, (IStream *)wic_stream, WICBitmapEncoderNoCache); if (FAILED(hr)) goto cleanup_err; hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame, &encoder_options); @@ -1783,11 +1824,37 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF } else WARN("Unsupported pixel format %#x\n", src_surface_desc.Format); + /* copy data from stream to ID3DXBuffer */ + hr = IStream_Stat(stream, &stream_stats, STATFLAG_NONAME); + if (FAILED(hr)) goto cleanup_err; + + if (stream_stats.cbSize.u.HighPart != 0) + { + hr = D3DXERR_INVALIDDATA; + goto cleanup; + } + size = stream_stats.cbSize.u.LowPart; + + hr = D3DXCreateBuffer(size, &buffer); + if (FAILED(hr)) goto cleanup; + + hr = GetHGlobalFromStream(stream, &stream_hglobal); + if (SUCCEEDED(hr)) + { + void *buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); + void *stream_data = GlobalLock(stream_hglobal); + memcpy(buffer_pointer, stream_data, size); + GlobalUnlock(stream_hglobal); + *dst_buffer = buffer; + } + else ID3DXBuffer_Release(buffer); + cleanup_err: - if (FAILED(hr)) hr = D3DERR_INVALIDCALL; + if (FAILED(hr) && hr != E_OUTOFMEMORY) + hr = D3DERR_INVALIDCALL; cleanup: - if (stream) IStream_Release((IStream *)stream); + if (wic_stream) IWICStream_Release(wic_stream); if (frame) IWICBitmapFrameEncode_Release(frame); if (encoder_options) IPropertyBag2_Release(encoder_options); diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 2f1f2a8..78ec0ca 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -920,6 +920,32 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) if(testbitmap_ok) DeleteFileA("testbitmap.bmp"); } +static void test_D3DXSaveSurfaceToFileInMemory(IDirect3DDevice9 *device) +{ + HRESULT hr; + RECT rect; + ID3DXBuffer *buffer; + IDirect3DSurface9 *surface; + + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surface, NULL); + if (FAILED(hr)) { + skip("Couldn't create surface\n"); + return; + } + + SetRect(&rect, 0, 0, 0, 0); + hr = D3DXSaveSurfaceToFileInMemory(&buffer, D3DXIFF_BMP, surface, NULL, &rect); + /* fails with the debug version of d3d9 */ + ok(hr == D3D_OK || broken(hr == D3DERR_INVALIDCALL), "D3DXSaveSurfaceToFileInMemory returned %#x, expected %#x\n", hr, D3D_OK); + if (SUCCEEDED(hr)) { + DWORD size = ID3DXBuffer_GetBufferSize(buffer); + ok(size > 0, "ID3DXBuffer_GetBufferSize returned %u, expected > 0\n", size); + ID3DXBuffer_Release(buffer); + } + + IDirect3DSurface9_Release(surface); +} + static void test_D3DXSaveSurfaceToFile(IDirect3DDevice9 *device) { HRESULT hr; @@ -1037,6 +1063,7 @@ START_TEST(surface) test_D3DXGetImageInfo(); test_D3DXLoadSurface(device); + test_D3DXSaveSurfaceToFileInMemory(device); test_D3DXSaveSurfaceToFile(device); check_release((IUnknown*)device, 0); diff --git a/dlls/d3dx9_36/util.c b/dlls/d3dx9_36/util.c index d936fb9..cf974cf 100644 --- a/dlls/d3dx9_36/util.c +++ b/dlls/d3dx9_36/util.c @@ -158,6 +158,25 @@ HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, LPVOID *buffer, return S_OK; } +HRESULT write_buffer_to_file(const WCHAR *dst_filename, ID3DXBuffer *buffer) +{ + HRESULT hr = S_OK; + void *buffer_pointer; + DWORD buffer_size; + HANDLE file = CreateFileW(dst_filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32(GetLastError()); + + buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); + buffer_size = ID3DXBuffer_GetBufferSize(buffer); + + if (!WriteFile(file, buffer_pointer, buffer_size, NULL, NULL)) + hr = HRESULT_FROM_WIN32(GetLastError()); + + CloseHandle(file); + return hr; +} + /************************************************************ * get_format_info diff --git a/include/d3dx9tex.h b/include/d3dx9tex.h index 7cfd896..0e89021 100644 --- a/include/d3dx9tex.h +++ b/include/d3dx9tex.h @@ -168,6 +168,12 @@ 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); +HRESULT WINAPI D3DXSaveSurfaceToFileInMemory( LPD3DXBUFFER *destbuffer, + D3DXIMAGE_FILEFORMAT destformat, + LPDIRECT3DSURFACE9 srcsurface, + CONST PALETTEENTRY *srcpalette, + CONST RECT *srcrect); + HRESULT WINAPI D3DXSaveSurfaceToFileA( LPCSTR destfile, D3DXIMAGE_FILEFORMAT destformat, LPDIRECT3DSURFACE9 srcsurface, -- 1.7.8.6