Matteo Bruni : d3dx9: Search for a compatible pixel format in D3DXCheckTextureRequirements.

Alexandre Julliard julliard at winehq.org
Mon Oct 18 13:36:51 CDT 2010


Module: wine
Branch: master
Commit: ebbf519b782d1523f90c3e6e5bbb9161733daf18
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=ebbf519b782d1523f90c3e6e5bbb9161733daf18

Author: Matteo Bruni <mbruni at codeweavers.com>
Date:   Tue Oct  5 21:58:59 2010 +0200

d3dx9: Search for a compatible pixel format in D3DXCheckTextureRequirements.

---

 dlls/d3dx9_36/d3dx9_36_private.h |    2 +-
 dlls/d3dx9_36/tests/texture.c    |   43 +++++++++++++-
 dlls/d3dx9_36/texture.c          |  116 ++++++++++++++++++++++++++++++--------
 dlls/d3dx9_36/util.c             |    9 +++
 4 files changed, 143 insertions(+), 27 deletions(-)

diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h
index 9598090..6857196 100644
--- a/dlls/d3dx9_36/d3dx9_36_private.h
+++ b/dlls/d3dx9_36/d3dx9_36_private.h
@@ -48,7 +48,7 @@ HRESULT map_view_of_file(LPCWSTR filename, LPVOID *buffer, DWORD *length);
 HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, LPVOID *buffer, DWORD *length);
 
 const PixelFormatDesc *get_format_info(D3DFORMAT format);
-
+const PixelFormatDesc *get_format_info_idx(int idx);
 
 extern const ID3DXBufferVtbl D3DXBuffer_Vtbl;
 
diff --git a/dlls/d3dx9_36/tests/texture.c b/dlls/d3dx9_36/tests/texture.c
index 3764089..05ccec4 100644
--- a/dlls/d3dx9_36/tests/texture.c
+++ b/dlls/d3dx9_36/tests/texture.c
@@ -27,9 +27,12 @@
 static void test_D3DXCheckTextureRequirements(IDirect3DDevice9 *device)
 {
     UINT width, height, mipmaps;
-    D3DFORMAT format;
+    D3DFORMAT format, expected;
     D3DCAPS9 caps;
     HRESULT hr;
+    IDirect3D9 *d3d;
+    D3DDEVICE_CREATION_PARAMETERS params;
+    D3DDISPLAYMODE mode;
 
     IDirect3DDevice9_GetDeviceCaps(device, &caps);
 
@@ -145,15 +148,51 @@ static void test_D3DXCheckTextureRequirements(IDirect3DDevice9 *device)
     ok(hr == D3DERR_INVALIDCALL, "D3DXCheckTextureRequirements succeeded, but should've failed.\n");
 
     /* format */
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, NULL, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+
     format = D3DFMT_UNKNOWN;
     hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
     ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
     ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8);
 
-    format = 0;
+    format = D3DX_DEFAULT;
     hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
     ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
     ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8);
+
+    format = D3DFMT_R8G8B8;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == D3DFMT_X8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_X8R8G8B8);
+
+    IDirect3DDevice9_GetDirect3D(device, &d3d);
+    IDirect3DDevice9_GetCreationParameters(device, &params);
+    IDirect3DDevice9_GetDisplayMode(device, 0, &mode);
+
+    if(SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
+                                              mode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_R3G3B2)))
+        expected = D3DFMT_R3G3B2;
+    else
+        expected = D3DFMT_X4R4G4B4;
+
+    format = D3DFMT_R3G3B2;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == expected, "Returned format %u, expected %u\n", format, expected);
+
+    if(SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
+                                              mode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R3G3B2)))
+        expected = D3DFMT_A8R3G3B2;
+    else
+        expected = D3DFMT_A8R8G8B8;
+
+    format = D3DFMT_A8R3G3B2;
+    hr = D3DXCheckTextureRequirements(device, NULL, NULL, NULL, 0, &format, D3DPOOL_DEFAULT);
+    ok(hr == D3D_OK, "D3DXCheckTextureRequirements returned %#x, expected %#x\n", hr, D3D_OK);
+    ok(format == expected, "Returned format %u, expected %u\n", format, expected);
+
+    IDirect3D9_Release(d3d);
 }
 
 static void test_D3DXCreateTexture(IDirect3DDevice9 *device)
diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c
index 2ebc85a..4f7c284 100644
--- a/dlls/d3dx9_36/texture.c
+++ b/dlls/d3dx9_36/texture.c
@@ -122,6 +122,11 @@ HRESULT WINAPI D3DXCheckTextureRequirements(LPDIRECT3DDEVICE9 device,
     UINT w = (width && *width) ? *width : 1;
     UINT h = (height && *height) ? *height : 1;
     D3DCAPS9 caps;
+    D3DDEVICE_CREATION_PARAMETERS params;
+    IDirect3D9 *d3d = NULL;
+    D3DDISPLAYMODE mode;
+    HRESULT hr;
+    D3DFORMAT usedformat = D3DFMT_UNKNOWN;
 
     TRACE("(%p, %p, %p, %p, %u, %p, %u)\n", device, width, height, miplevels, usage, format, pool);
 
@@ -129,8 +134,9 @@ HRESULT WINAPI D3DXCheckTextureRequirements(LPDIRECT3DDEVICE9 device,
         return D3DERR_INVALIDCALL;
 
     /* usage */
-    if ((usage != D3DX_DEFAULT) &&
-        (usage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES | D3DUSAGE_NPATCHES)))
+    if (usage == D3DX_DEFAULT)
+        usage = 0;
+    if (usage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES | D3DUSAGE_NPATCHES))
         return D3DERR_INVALIDCALL;
 
     /* pool */
@@ -202,44 +208,106 @@ HRESULT WINAPI D3DXCheckTextureRequirements(LPDIRECT3DDEVICE9 device,
     /* format */
     if (format)
     {
-        D3DDEVICE_CREATION_PARAMETERS params;
-        IDirect3D9 *d3d = NULL;
-        D3DDISPLAYMODE mode;
-        HRESULT hr;
+        TRACE("Requested format %x\n", *format);
+        usedformat = *format;
+    }
 
-        hr = IDirect3DDevice9_GetDirect3D(device, &d3d);
+    hr = IDirect3DDevice9_GetDirect3D(device, &d3d);
 
-        if (FAILED(hr))
-            goto cleanup;
+    if (FAILED(hr))
+        goto cleanup;
 
-        hr = IDirect3DDevice9_GetCreationParameters(device, &params);
+    hr = IDirect3DDevice9_GetCreationParameters(device, &params);
 
-        if (FAILED(hr))
-            goto cleanup;
+    if (FAILED(hr))
+        goto cleanup;
 
-        hr = IDirect3DDevice9_GetDisplayMode(device, 0, &mode);
+    hr = IDirect3DDevice9_GetDisplayMode(device, 0, &mode);
 
-        if (FAILED(hr))
+    if (FAILED(hr))
+        goto cleanup;
+
+    if ((usedformat == D3DFMT_UNKNOWN) || (usedformat == D3DX_DEFAULT))
+        usedformat = D3DFMT_A8R8G8B8;
+
+    hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType, mode.Format,
+        usage, D3DRTYPE_TEXTURE, usedformat);
+
+    if (FAILED(hr))
+    {
+        /* Heuristic to choose the fallback format */
+        const PixelFormatDesc *fmt = get_format_info(usedformat);
+        BOOL allow_24bits;
+        int bestscore = INT_MIN, i = 0, j;
+        unsigned int channels;
+        const PixelFormatDesc *curfmt;
+
+        if (!fmt)
+        {
+            FIXME("Pixel format %x not handled\n", usedformat);
             goto cleanup;
+        }
 
-        if ((*format == D3DFMT_UNKNOWN) || (*format == D3DX_DEFAULT))
-            *format = D3DFMT_A8R8G8B8;
+        allow_24bits = fmt->bytes_per_pixel == 3;
+        channels = (fmt->bits[0] ? 1 : 0) + (fmt->bits[1] ? 1 : 0)
+            + (fmt->bits[2] ? 1 : 0) + (fmt->bits[3] ? 1 : 0);
+        usedformat = D3DFMT_UNKNOWN;
 
-        hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType, mode.Format, usage,
-            D3DRTYPE_TEXTURE, *format);
+        while ((curfmt = get_format_info_idx(i)))
+        {
+            unsigned int curchannels = (curfmt->bits[0] ? 1 : 0) + (curfmt->bits[1] ? 1 : 0)
+                + (curfmt->bits[2] ? 1 : 0) + (curfmt->bits[3] ? 1 : 0);
+            int score;
 
-        if (FAILED(hr))
-            FIXME("Pixel format adjustment not implemented yet\n");
+            i++;
+
+            if (curchannels < channels)
+                continue;
+            if (curfmt->bytes_per_pixel == 3 && !allow_24bits)
+                continue;
+
+            hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
+                mode.Format, usage, D3DRTYPE_TEXTURE, curfmt->format);
+            if (FAILED(hr))
+                continue;
+
+            /* This format can be used, let's evaluate it.
+               Weights chosen quite arbitrarily... */
+            score = 16 - 4 * (curchannels - channels);
+
+            for (j = 0; j < 4; j++)
+            {
+                int diff = curfmt->bits[j] - fmt->bits[j];
+                score += 16 - (diff < 0 ? -diff * 4 : diff);
+            }
+
+            if (score > bestscore)
+            {
+                bestscore = score;
+                usedformat = curfmt->format;
+            }
+        }
+        hr = D3D_OK;
+    }
 
 cleanup:
 
-        if (d3d)
-            IDirect3D9_Release(d3d);
+    if (d3d)
+        IDirect3D9_Release(d3d);
 
-        if (FAILED(hr))
-            return D3DERR_INVALIDCALL;
+    if (FAILED(hr))
+        return hr;
+
+    if (usedformat == D3DFMT_UNKNOWN)
+    {
+        WARN("Couldn't find a suitable pixel format\n");
+        return D3DERR_NOTAVAILABLE;
     }
 
+    TRACE("Format chosen: %x\n", usedformat);
+    if (format)
+        *format = usedformat;
+
     return D3D_OK;
 }
 
diff --git a/dlls/d3dx9_36/util.c b/dlls/d3dx9_36/util.c
index 748e6d1..dc8e820 100644
--- a/dlls/d3dx9_36/util.c
+++ b/dlls/d3dx9_36/util.c
@@ -152,3 +152,12 @@ const PixelFormatDesc *get_format_info(D3DFORMAT format)
     while(formats[i].format != format && formats[i].format != D3DFMT_UNKNOWN) i++;
     return &formats[i];
 }
+
+const PixelFormatDesc *get_format_info_idx(int idx)
+{
+    if(idx >= sizeof(formats) / sizeof(formats[0]))
+        return NULL;
+    if(formats[idx].format == D3DFMT_UNKNOWN)
+        return NULL;
+    return &formats[idx];
+}




More information about the wine-cvs mailing list