wined3d: Implement check for shader creation if hardware supports requested version.

Pauli Nieminen suokkos at gmail.com
Wed Dec 17 06:04:48 CST 2008


This fixes civ 4 rendering problems if no pixelshader support is enabled.
Civ 4 doesn't check for caps so it doesn't know if shader is support if
creation doesn't fail.

Resending improved version of patch. Can someone test this in windows?
(I don't have access to windows machine.)
---
 dlls/d3d9/tests/shader.c    |  258 +++++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/pixelshader.c  |   36 ++++++
 dlls/wined3d/vertexshader.c |   35 ++++++
 3 files changed, 329 insertions(+), 0 deletions(-)

diff --git a/dlls/d3d9/tests/shader.c b/dlls/d3d9/tests/shader.c
index 522f128..fdcbab1 100644
--- a/dlls/d3d9/tests/shader.c
+++ b/dlls/d3d9/tests/shader.c
@@ -74,6 +74,262 @@ static int get_refcount(IUnknown *object)
     return IUnknown_Release(object);
 }
 
+static inline void test_create_vshader_version_check(IDirect3DDevice9 *device_ptr, const D3DCAPS9 *caps,
+        const DWORD version, const DWORD *shader_code)
+{
+    IDirect3DVertexShader9 *vshader_ptr = 0;
+    HRESULT hret = 0;
+
+    hret = IDirect3DDevice9_CreateVertexShader(device_ptr, shader_code, &vshader_ptr);
+
+
+    if( version <= caps->VertexShaderVersion )
+    {
+        ok(hret == D3D_OK && vshader_ptr != NULL, "Vertex shader (0x%x) creation failed but d3dcaps claim to support it. hret = 0x%x, vshader_ptr = %p", version, hret, vshader_ptr);
+        IDirect3DVertexShader9_Release(vshader_ptr);
+    } else {
+        ok(hret == D3DERR_INVALIDCALL && vshader_ptr == NULL,"Vertex shader (0x%x) creation succesed but d3dcaps claim not to support it. hret = 0x%x, vshader_ptr = %p", version, hret, vshader_ptr);
+    }
+
+}
+
+static inline void test_create_pshader_version_check(IDirect3DDevice9 *device_ptr, const D3DCAPS9 *caps,
+        const DWORD version, const DWORD *shader_code)
+{
+    IDirect3DPixelShader9 *pshader_ptr = 0;
+    HRESULT hret = 0;
+
+    hret = IDirect3DDevice9_CreatePixelShader(device_ptr, shader_code, &pshader_ptr);
+
+
+    if( version <= caps->PixelShaderVersion )
+    {
+        ok(hret == D3D_OK && pshader_ptr != NULL, "Pixel shader (0x%x) creation failed but d3dcaps claim to support it. hret = 0x%x, pshader_ptr = %p", version, hret, pshader_ptr);
+        IDirect3DPixelShader9_Release(pshader_ptr);
+    } else {
+        ok(hret == D3DERR_INVALIDCALL && pshader_ptr == NULL,"Pixel shader (0x%x) creation succesed but d3dcaps claim not to support it. hret = 0x%x, pshader_ptr = %p", version, hret, pshader_ptr);
+    }
+
+}
+
+static void test_create_shader_version_check(IDirect3DDevice9 *device_ptr,D3DCAPS9 *caps)
+{
+    const DWORD ps10_test_version[] =
+    {
+        0xffff0100,
+        /*    ps_1_0 */
+        0x00000042, 0xb00f0000, 0x00000001,
+        /*    tex t0 */
+        0x800f0000, 0xb0e40000, 0x0000ffff
+        /*    mov r0, t0 */
+    };
+
+    const DWORD ps11_test_version[] =
+    {
+        0xffff0101,
+        /*    ps_1_1 */
+        0x00000042, 0xb00f0000, 0x00000001,
+        /*    tex t0 */
+        0x800f0000, 0xb0e40000, 0x0000ffff
+        /*    mov r0, t0 */
+    };
+
+    const DWORD ps12_test_version[] =
+    {
+        0xffff0102,
+        /*    ps_1_0 */
+        0x00000042, 0xb00f0000, 0x00000001,
+        /*    tex t0 */
+        0x800f0000, 0xb0e40000, 0x0000ffff
+        /*    mov r0, t0 */
+    };
+
+    const DWORD ps13_test_version[] =
+    {
+        0xffff0103,
+        /*    ps_1_0 */
+        0x00000042, 0xb00f0000, 0x00000001,
+        /*    tex t0 */
+        0x800f0000, 0xb0e40000, 0x0000ffff
+        /*    mov r0, t0 */
+    };
+
+    const DWORD ps14_test_version[] =
+    {
+        0xffff0104,
+        /*    ps_1_4 */
+        0x00000042, 0x800f0004, 0xb0e40000, 0x00000001,
+        /*    texld r4, t0 */
+        0x800f0000, 0x80e40004, 0x0000ffff
+        /*    mov r0, r4 */
+    };
+
+    const DWORD ps20_test_version[] =
+    {
+        0xffff0200,
+        /*    ps_2_0 */
+        0x0200001f, 0x90000000, 0xa00f0800,
+        /*    dcl_2d s0 */
+        0x0200001f, 0x80000000, 0xb0030000, 0x03000042,
+        /*    dcl t0.xy */
+        0x800f0001, 0xb0e40000, 0xa0e40800, 0x02000001,
+        /*    texld r1, t0, s0 */
+        0x800f0800, 0x80e40001, 0x0000ffff
+        /*    mov oC0, r1 */
+    };
+
+    const DWORD ps2sw_test_version[] =
+    {
+        0xffff02ff,
+        /*    ps_2_sw */
+        0x0200001f, 0x90000000, 0xa00f0800,
+        /*    dcl_2d s0 */
+        0x0200001f, 0x80000000, 0xb0030000, 0x03000042,
+        /*    dcl t0.xy */
+        0x800f0001, 0xb0e40000, 0xa0e40800, 0x02000001,
+        /*    texld r1, t0, s0 */
+        0x800f0800, 0x80e40001, 0x0000ffff
+        /*    mov oC0, r1 */
+    };
+
+    const DWORD ps2x_test_version[] =
+    {
+        0xffff0201,
+        /*    ps_2_x */
+        0x0200001f, 0x90000000, 0xa00f0800,
+        /*    dcl_2d s0 */
+        0x0200001f, 0x80000000, 0xb0030000, 0x03000042,
+        /*    dcl t0.xy */
+        0x800f0001, 0xb0e40000, 0xa0e40800, 0x02000001,
+        /*    texld r1, t0, s0 */
+        0x800f0800, 0x80e40001, 0x0000ffff
+        /*    mov oC0, r1 */
+    };
+
+    const DWORD ps30_test_version[] =
+    {
+        0xffff0300,
+        /*    ps_3_0 */
+        0x0200001f, 0x90000000, 0xa00f0800,
+        /*    dcl_2d s0 */
+        0x0200001f, 0x80000000, 0x90030000, 0x03000042,
+        /*    dcl v0.xy */
+        0x800f0001, 0x90e40000, 0xa0e40800, 0x02000001,
+        /*    texld r1, v0, s0 */
+        0x800f0800, 0x80e40001, 0x0000ffff
+        /*    mov oC0, r1 */
+    };
+
+    const DWORD ps3sw_test_version[] =
+    {
+        0xffff03ff,
+        /*    ps_3_0 */
+        0x0200001f, 0x90000000, 0xa00f0800,
+        /*    dcl_2d s0 */
+        0x0200001f, 0x80000000, 0x90030000, 0x03000042,
+        /*    dcl v0.xy */
+        0x800f0001, 0x90e40000, 0xa0e40800, 0x02000001,
+        /*    texld r1, v0, s0 */
+        0x800f0800, 0x80e40001, 0x0000ffff
+        /*    mov oC0, r1 */
+    };
+
+    const DWORD vs10_test_version[] =
+    {
+        0xfffe0100,
+        /*    vs_1_0 */
+        0x00000001, 0xc00f0000, 0x90e40000, 0x0000ffff
+        /*    mov oPos, v0 */
+    };
+
+    const DWORD vs11_test_version[] =
+    {
+        0xfffe0101,
+        /*    vs_1_1 */
+        0x00000001, 0xc00f0000, 0x90e40000, 0x0000ffff
+        /*    mov oPos, v0 */
+    };
+
+    const DWORD vs20_test_version[] =
+    {
+        0xfffe0200,
+        /*    vs_2_0 */
+        0x02000001, 0xc00f0000, 0x90e40000, 0x0000ffff
+        /*    mov oPos, v0 */
+    };
+
+    const DWORD vs2sw_test_version[] =
+    {
+        0xfffe02ff,
+        /*    vs_2_sw */
+        0x02000001, 0xc00f0000, 0x90e40000, 0x0000ffff
+        /*    mov oPos, v0 */
+    };
+
+    const DWORD vs2x_test_version[] =
+    {
+        0xfffe0201,
+        /*    vs_2_x */
+        0x02000001, 0xc00f0000, 0x90e40000, 0x0000ffff
+        /*    mov oPos, v0 */
+    };
+
+    const DWORD vs30_test_version[] =
+    {
+        0xfffe0300,
+        /*    vs_3_0 */
+        0x02000001, 0xe00f0000, 0x90e40000, 0x0000ffff
+        /*    mov o0, v0 */
+    };
+
+    const DWORD vs3sw_test_version[] =
+    {
+        0xfffe03ff,
+        /*    vs_3_sw */
+        0x02000001, 0xe00f0000, 0x90e40000, 0x0000ffff
+        /*    mov o0, v0 */
+    };
+
+    /* Vertex shaders */
+    DWORD version = D3DVS_VERSION(1,0);
+    test_create_vshader_version_check(device_ptr, caps, version, vs10_test_version);
+    version = D3DVS_VERSION(1,1);
+    test_create_vshader_version_check(device_ptr, caps, version, vs11_test_version);
+    version = D3DVS_VERSION(2,0);
+    test_create_vshader_version_check(device_ptr, caps, version, vs20_test_version);
+    version = D3DVS_VERSION(2,1);
+    test_create_vshader_version_check(device_ptr, caps, version, vs2x_test_version);
+    version = D3DVS_VERSION(2,0xff);
+    test_create_vshader_version_check(device_ptr, caps, version, vs2sw_test_version);
+    version = D3DVS_VERSION(3,0);
+    test_create_vshader_version_check(device_ptr, caps, version, vs30_test_version);
+    version = D3DVS_VERSION(3,0xff);
+    test_create_vshader_version_check(device_ptr, caps, version, vs3sw_test_version);
+
+    /* Pixel shaders */
+    version = D3DPS_VERSION(1,0);
+    test_create_pshader_version_check(device_ptr, caps, version, ps10_test_version);
+    version = D3DPS_VERSION(1,1);
+    test_create_pshader_version_check(device_ptr, caps, version, ps11_test_version);
+    version = D3DPS_VERSION(1,2);
+    test_create_pshader_version_check(device_ptr, caps, version, ps12_test_version);
+    version = D3DPS_VERSION(1,3);
+    test_create_pshader_version_check(device_ptr, caps, version, ps13_test_version);
+    version = D3DPS_VERSION(1,4);
+    test_create_pshader_version_check(device_ptr, caps, version, ps14_test_version);
+    version = D3DPS_VERSION(2,0);
+    test_create_pshader_version_check(device_ptr, caps, version, ps20_test_version);
+    version = D3DPS_VERSION(2,1);
+    test_create_pshader_version_check(device_ptr, caps, version, ps2x_test_version);
+    version = D3DPS_VERSION(2,0xff);
+    test_create_pshader_version_check(device_ptr, caps, version, ps2sw_test_version);
+    version = D3DPS_VERSION(3,0);
+    test_create_pshader_version_check(device_ptr, caps, version, ps30_test_version);
+    version = D3DPS_VERSION(3,0xff);
+    test_create_pshader_version_check(device_ptr, caps, version, ps3sw_test_version);
+
+}
+
 static void test_get_set_vertex_shader(IDirect3DDevice9 *device_ptr)
 {
 
@@ -228,6 +484,8 @@ START_TEST(shader)
 
     IDirect3DDevice9_GetDeviceCaps(device_ptr, &caps);
 
+    test_create_shader_version_check(device_ptr, &caps);
+
     if (caps.VertexShaderVersion & 0xffff)
     {
         test_get_set_vertex_shader(device_ptr);
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index b6b84b0..6cf24fe 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -296,6 +296,30 @@ static void pshader_set_limits(
       }
 }
 
+/**
+ * checks if shader version supported that is required by new
+ * shader.
+ */
+static inline BOOL is_pshader_version_supported(IWineD3DDeviceImpl *deviceImpl, const DWORD *byte_code)
+{
+    struct shader_caps shader_caps;
+    const DWORD shader_version = *byte_code; /* First instruction should be shader version */
+    const WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info;
+
+    deviceImpl->shader_backend->shader_get_caps(deviceImpl->devType ,gl_info, &shader_caps);
+    // Check which shader this is
+    if(shader_is_pshader_version(shader_version))
+    {
+        // Check if high enough shader version is supported
+        return shader_caps.PixelShaderVersion >= shader_version;
+    }
+
+    ERR("First instruction in shader isn't correct shader version for pixel shader. (0x%x)\n", shader_version);
+
+    return FALSE;
+}
+
+
 static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *iface, CONST DWORD *pFunction) {
 
     IWineD3DPixelShaderImpl *This =(IWineD3DPixelShaderImpl *)iface;
@@ -309,6 +333,18 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *i
     /* First pass: trace shader */
     if (TRACE_ON(d3d_shader)) shader_trace_init(pFunction, This->baseShader.shader_ins);
 
+    /* If no hardware support this function should fail */
+    if (!is_pshader_version_supported(deviceImpl, pFunction))
+    {
+        static BOOL warned = FALSE;
+        if (!warned)
+        {
+            warned = TRUE;
+            ERR("No hardware support for pixel shader version (0x%x).\n",*pFunction);
+        }
+        return WINED3DERR_INVALIDCALL;
+    }
+
     /* Initialize immediate constant lists */
     list_init(&This->baseShader.constantsF);
     list_init(&This->baseShader.constantsB);
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index 063f576..b3c680b 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -419,6 +419,29 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_GetFunction(IWineD3DVertexShader*
     return WINED3D_OK;
 }
 
+/**
+ * checks if shader version supported that is required by new
+ * shader.
+ */
+static inline BOOL is_vshader_version_supported(IWineD3DDeviceImpl *deviceImpl, const DWORD *byte_code)
+{
+    struct shader_caps shader_caps;
+    const DWORD shader_version = *byte_code; /* First instruction should be shader version */
+    const WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info;
+
+    deviceImpl->shader_backend->shader_get_caps(deviceImpl->devType ,gl_info, &shader_caps);
+    // Check which shader this is
+    if(shader_is_vshader_version(shader_version))
+    {
+        // Check if high enough shader version is supported
+        return shader_caps.VertexShaderVersion >= shader_version;
+    }
+
+    ERR("First instruction in shader isn't correct shader version for vertex shader. (0x%x)\n", shader_version);
+
+    return FALSE;
+}
+
 /* Note that for vertex shaders CompileShader isn't called until the
  * shader is first used. The reason for this is that we need the vertex
  * declaration the shader will be used with in order to determine if
@@ -435,6 +458,18 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader
     /* First pass: trace shader */
     if (TRACE_ON(d3d_shader)) shader_trace_init(pFunction, This->baseShader.shader_ins);
 
+    /* If no hardware support this function should fail */
+    if (!is_vshader_version_supported(deviceImpl, pFunction))
+    {
+        static BOOL warned = FALSE;
+        if (!warned)
+        {
+            warned = TRUE;
+            ERR("No hardware support for vertex shader version (0x%x).\n",*pFunction);
+        }
+        return WINED3DERR_INVALIDCALL;
+    }
+
     /* Initialize immediate constant lists */
     list_init(&This->baseShader.constantsF);
     list_init(&This->baseShader.constantsB);
-- 
1.5.6.3




More information about the wine-patches mailing list