[2/5] d3dx9: Implement D3DXSaveSurfaceToFileInMemory.

Józef Kucia joseph.kucia at gmail.com
Mon May 28 00:07:22 CDT 2012


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




More information about the wine-patches mailing list