d3d8: Improve ValidateVertexShader().

Based largely on a patch by Sebastian Lackner.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2019-02-08 02:09:37 +03:30 committed by Alexandre Julliard
parent 957a1f0216
commit 3ccbb762d2
2 changed files with 118 additions and 56 deletions

View File

@ -57,40 +57,50 @@ IDirect3D8 * WINAPI DECLSPEC_HOTPATCH Direct3DCreate8(UINT sdk_version)
return &object->IDirect3D8_iface;
}
/***********************************************************************
* ValidateVertexShader (D3D8.@)
*
* I've seen reserved1 and reserved2 always passed as 0's
* boolean seems always passed as 0 or 1, but other values work as well...
* toto result?
*/
HRESULT WINAPI ValidateVertexShader(DWORD* vertexshader, DWORD* reserved1, DWORD* reserved2, BOOL boolean, DWORD* toto)
/* FIXME: We should probably use libvkd3d-shader for validation. */
HRESULT WINAPI ValidateVertexShader(const DWORD *vs_code, const DWORD *declaration,
const D3DCAPS8 *caps, BOOL return_error, char **errors)
{
HRESULT ret;
static BOOL warned;
const char *message = "";
SIZE_T message_size;
HRESULT hr = E_FAIL;
if (TRACE_ON(d3d8) || !warned) {
FIXME("(%p %p %p %d %p): stub\n", vertexshader, reserved1, reserved2, boolean, toto);
warned = TRUE;
}
TRACE("vs_code %p, declaration %p, caps %p, return_error %#x, errors %p.\n",
vs_code, declaration, caps, return_error, errors);
if (!vertexshader)
return E_FAIL;
if (!vs_code)
{
message = "Invalid code pointer.\n";
goto done;
}
if (reserved1 || reserved2)
return E_FAIL;
switch(*vertexshader) {
case 0xFFFE0101:
case 0xFFFE0100:
ret=S_OK;
switch (*vs_code)
{
case D3DVS_VERSION(1, 1):
case D3DVS_VERSION(1, 0):
break;
default:
WARN("Invalid shader version token %#x.\n", *vertexshader);
ret=E_FAIL;
}
return ret;
default:
message = "Unsupported shader version.\n";
goto done;
}
if (caps && *vs_code > caps->VertexShaderVersion)
{
message = "Shader version not supported by caps.\n";
goto done;
}
hr = S_OK;
done:
if (!return_error)
message = "";
message_size = strlen(message) + 1;
if (errors && (*errors = heap_alloc(message_size)))
memcpy(*errors, message, message_size);
return hr;
}
/***********************************************************************

View File

@ -27,6 +27,7 @@
#include <initguid.h>
#include <d3d8.h>
#include "wine/test.h"
#include "wine/heap.h"
struct vec3
{
@ -51,7 +52,7 @@ struct device_desc
static DEVMODEW registry_mode;
static HRESULT (WINAPI *ValidateVertexShader)(DWORD *, DWORD *, DWORD *, int, DWORD *);
static HRESULT (WINAPI *ValidateVertexShader)(const DWORD *, const DWORD *, const D3DCAPS8 *, BOOL, char **);
static HRESULT (WINAPI *ValidatePixelShader)(DWORD *, DWORD *, int, DWORD *);
static BOOL (WINAPI *pGetCursorInfo)(PCURSORINFO);
@ -4365,7 +4366,7 @@ static void test_set_rt_vp_scissor(void)
static void test_validate_vs(void)
{
static DWORD vs[] =
static DWORD vs_code[] =
{
0xfffe0101, /* vs_1_1 */
0x00000009, 0xc0010000, 0x90e40000, 0xa0e40000, /* dp4 oPos.x, v0, c0 */
@ -4374,40 +4375,91 @@ static void test_validate_vs(void)
0x00000009, 0xc0080000, 0x90e40000, 0xa0e40003, /* dp4 oPos.w, v0, c3 */
0x0000ffff, /* end */
};
D3DCAPS8 caps;
char *errors;
HRESULT hr;
hr = ValidateVertexShader(0, 0, 0, 0, 0);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(0, 0, 0, 1, 0);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(vs, 0, 0, 0, 0);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
static DWORD declaration_valid1[] =
{
D3DVSD_STREAM(0),
D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT4),
D3DVSD_END()
};
static DWORD declaration_valid2[] =
{
D3DVSD_STREAM(0),
D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT2),
D3DVSD_END()
};
static DWORD declaration_invalid[] =
{
D3DVSD_STREAM(0),
D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT4),
D3DVSD_END()
};
hr = ValidateVertexShader(vs, 0, 0, 1, 0);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
/* Seems to do some version checking. */
*vs = 0xfffe0100; /* vs_1_0 */
hr = ValidateVertexShader(vs, 0, 0, 0, 0);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(NULL, NULL, NULL, FALSE, NULL);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(NULL, NULL, NULL, TRUE, NULL);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(NULL, NULL, NULL, FALSE, &errors);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
ok(!*errors, "Got unexpected string \"%s\".\n", errors);
heap_free(errors);
hr = ValidateVertexShader(NULL, NULL, NULL, TRUE, &errors);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
ok(!!*errors, "Got unexpected empty string.\n");
heap_free(errors);
*vs = 0xfffe0102; /* bogus version */
hr = ValidateVertexShader(vs, 0, 0, 1, 0);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
/* I've seen that applications always pass the 2nd and 3rd parameter as 0.
* Simple test with non-zero parameters. */
*vs = 0xfffe0101; /* vs_1_1 */
hr = ValidateVertexShader(vs, vs, 0, 1, 0);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(vs_code, NULL, NULL, FALSE, NULL);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(vs_code, NULL, NULL, TRUE, NULL);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(vs_code, NULL, NULL, TRUE, &errors);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
ok(!*errors, "Got unexpected string \"%s\".\n", errors);
heap_free(errors);
hr = ValidateVertexShader(vs, 0, vs, 1, 0);
hr = ValidateVertexShader(vs_code, declaration_valid1, NULL, FALSE, NULL);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(vs_code, declaration_valid2, NULL, FALSE, NULL);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(vs_code, declaration_invalid, NULL, FALSE, NULL);
todo_wine ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
memset(&caps, 0, sizeof(caps));
caps.VertexShaderVersion = D3DVS_VERSION(1, 1);
caps.MaxVertexShaderConst = 4;
hr = ValidateVertexShader(vs_code, NULL, &caps, FALSE, NULL);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
caps.VertexShaderVersion = D3DVS_VERSION(1, 0);
hr = ValidateVertexShader(vs_code, NULL, &caps, FALSE, NULL);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
/* I've seen the 4th parameter always passed as either 0 or 1, but passing
* other values doesn't seem to hurt. */
hr = ValidateVertexShader(vs, 0, 0, 12345, 0);
caps.VertexShaderVersion = D3DVS_VERSION(1, 2);
hr = ValidateVertexShader(vs_code, NULL, &caps, FALSE, NULL);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
/* What is the 5th parameter? The following seems to work ok. */
hr = ValidateVertexShader(vs, 0, 0, 1, vs);
caps.VertexShaderVersion = D3DVS_VERSION(8, 8);
hr = ValidateVertexShader(vs_code, NULL, &caps, FALSE, NULL);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
caps.VertexShaderVersion = D3DVS_VERSION(1, 1);
caps.MaxVertexShaderConst = 3;
hr = ValidateVertexShader(vs_code, NULL, &caps, FALSE, NULL);
todo_wine ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
*vs_code = D3DVS_VERSION(1, 0);
hr = ValidateVertexShader(vs_code, NULL, NULL, FALSE, NULL);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
*vs_code = D3DVS_VERSION(1, 2);
hr = ValidateVertexShader(vs_code, NULL, NULL, TRUE, NULL);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
hr = ValidateVertexShader(vs_code, NULL, NULL, FALSE, &errors);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
ok(!*errors, "Got unexpected string \"%s\".\n", errors);
heap_free(errors);
hr = ValidateVertexShader(vs_code, NULL, NULL, TRUE, &errors);
ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
ok(!!*errors, "Got unexpected empty string.\n");
heap_free(errors);
}
static void test_validate_ps(void)