mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-09-12 18:50:22 -07:00
tests/shader-runner: Test shaders with dxcompiler.
The location of dxcompiler should be set during configuration with 'DXCOMPILER_LIBS=-L/path/to/dxcompiler', and then at runtime with LD_LIBRARY_PATH, WINEPATH or PATH as applicable. A new 'fail(sm<6)' decoration is needed on many shader declarations because dxcompiler succeeds on many shaders which fail with fxc. The opposite case is less common and is flagged with 'fail(sm>=6)'. A few tests cause dxcompiler to crash or hang, so these are avoided using [require], which now skips tests until reset instead of exiting. Also, 'todo(sm<6)' and 'todo(sm>=6)' are used to separate checking of results.
This commit is contained in:
committed by
Alexandre Julliard
parent
d211160b89
commit
57280673e5
Notes:
Alexandre Julliard
2023-10-11 22:53:48 +02:00
Approved-by: Giovanni Mascellani (@giomasce) Approved-by: Zebediah Figura (@zfigura) Approved-by: Henri Verbeet (@hverbeet) Approved-by: Alexandre Julliard (@julliard) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/346
@@ -60,6 +60,7 @@ typedef int HRESULT;
|
||||
#include "vkd3d_d3dcompiler.h"
|
||||
#include "vkd3d_test.h"
|
||||
#include "shader_runner.h"
|
||||
#include "dxcompiler.h"
|
||||
|
||||
struct test_options test_options = {0};
|
||||
|
||||
@@ -129,9 +130,11 @@ static bool match_directive_substring(const char *line, const char *token, const
|
||||
|
||||
static void parse_require_directive(struct shader_runner *runner, const char *line)
|
||||
{
|
||||
bool less_than = false;
|
||||
unsigned int i;
|
||||
|
||||
if (match_string(line, "shader model >=", &line))
|
||||
if (match_string(line, "shader model >=", &line)
|
||||
|| (less_than = match_string(line, "shader model <", &line)))
|
||||
{
|
||||
static const char *const model_strings[] =
|
||||
{
|
||||
@@ -141,13 +144,23 @@ static void parse_require_directive(struct shader_runner *runner, const char *li
|
||||
[SHADER_MODEL_4_1] = "4.1",
|
||||
[SHADER_MODEL_5_0] = "5.0",
|
||||
[SHADER_MODEL_5_1] = "5.1",
|
||||
[SHADER_MODEL_6_0] = "6.0",
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(model_strings); ++i)
|
||||
{
|
||||
if (match_string(line, model_strings[i], &line))
|
||||
{
|
||||
runner->minimum_shader_model = i;
|
||||
if (less_than)
|
||||
{
|
||||
if (!i)
|
||||
fatal_error("Shader model < '%s' is invalid.\n", line);
|
||||
runner->maximum_shader_model = min(runner->maximum_shader_model, i - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
runner->minimum_shader_model = max(runner->minimum_shader_model, i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -485,6 +498,10 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
|
||||
|
||||
if (match_string(line, "todo", &line))
|
||||
runner->is_todo = true;
|
||||
else if (match_string(line, "todo(sm<6)", &line))
|
||||
runner->is_todo = runner->minimum_shader_model < SHADER_MODEL_6_0;
|
||||
else if (match_string(line, "todo(sm>=6)", &line))
|
||||
runner->is_todo = runner->minimum_shader_model >= SHADER_MODEL_6_0;
|
||||
|
||||
if (match_string(line, "dispatch", &line))
|
||||
{
|
||||
@@ -802,9 +819,125 @@ const char *shader_type_string(enum shader_type type)
|
||||
return shader_types[type];
|
||||
}
|
||||
|
||||
static void compile_shader(struct shader_runner *runner, const char *source, size_t len, enum shader_type type,
|
||||
HRESULT expect)
|
||||
/* Avoid issues with calling convention mismatch and different methods for string
|
||||
* retrieval by copying all IDxcBlob objects to a new ID3D10Blob. */
|
||||
|
||||
static void d3d10_blob_from_dxc_blob_utf8(IDxcBlobUtf8 *blob, ID3D10Blob **blob_out)
|
||||
{
|
||||
ID3D10Blob *d3d_blob;
|
||||
size_t size;
|
||||
HRESULT hr;
|
||||
|
||||
size = IDxcBlobUtf8_GetStringLength(blob) + 1;
|
||||
if (FAILED(hr = D3DCreateBlob(size, (ID3DBlob **)&d3d_blob)))
|
||||
{
|
||||
trace("Failed to create blob, hr %#x.\n", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(ID3D10Blob_GetBufferPointer(d3d_blob), IDxcBlobUtf8_GetStringPointer(blob), size);
|
||||
*blob_out = d3d_blob;
|
||||
}
|
||||
|
||||
static HRESULT d3d10_blob_from_dxc_blob(IDxcBlob *blob, ID3D10Blob **blob_out)
|
||||
{
|
||||
ID3D10Blob *d3d_blob;
|
||||
size_t size;
|
||||
HRESULT hr;
|
||||
|
||||
size = IDxcBlob_GetBufferSize(blob);
|
||||
if (FAILED(hr = D3DCreateBlob(size, (ID3DBlob **)&d3d_blob)))
|
||||
{
|
||||
trace("Failed to create blob, hr %#x.\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
memcpy(ID3D10Blob_GetBufferPointer(d3d_blob), IDxcBlob_GetBufferPointer(blob), size);
|
||||
*blob_out = d3d_blob;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT dxc_compiler_compile_shader(void *dxc_compiler, enum shader_type type, unsigned int compile_options,
|
||||
const char *hlsl, ID3D10Blob **blob_out, ID3D10Blob **errors_out)
|
||||
{
|
||||
DxcBuffer src_buf = {hlsl, strlen(hlsl), 65001};
|
||||
IDxcCompiler3 *compiler = dxc_compiler;
|
||||
HRESULT hr, compile_hr;
|
||||
IDxcBlobUtf8 *errors;
|
||||
IDxcResult *result;
|
||||
size_t arg_count;
|
||||
IDxcBlob *blob;
|
||||
|
||||
static const WCHAR *const shader_profiles[] =
|
||||
{
|
||||
[SHADER_TYPE_CS] = L"cs_6_0",
|
||||
[SHADER_TYPE_PS] = L"ps_6_0",
|
||||
[SHADER_TYPE_VS] = L"vs_6_0",
|
||||
};
|
||||
const WCHAR *args[] =
|
||||
{
|
||||
L"/T",
|
||||
shader_profiles[type],
|
||||
L"/Qstrip_reflect",
|
||||
L"/Qstrip_debug",
|
||||
L"/flegacy-macro-expansion",
|
||||
L"/flegacy-resource-reservation",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
*blob_out = NULL;
|
||||
*errors_out = NULL;
|
||||
|
||||
arg_count = ARRAY_SIZE(args) - 3;
|
||||
if (compile_options & D3DCOMPILE_PACK_MATRIX_ROW_MAJOR)
|
||||
args[arg_count++] = L"/Zpr";
|
||||
if (compile_options & D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR)
|
||||
args[arg_count++] = L"/Zpc";
|
||||
if (compile_options & D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY)
|
||||
args[arg_count++] = L"/Gec";
|
||||
|
||||
if (FAILED(hr = IDxcCompiler3_Compile(compiler, &src_buf, args, arg_count, NULL, &IID_IDxcResult, (void **)&result)))
|
||||
{
|
||||
trace("Failed to compile shader, hr %#x.\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (IDxcResult_HasOutput(result, DXC_OUT_ERRORS)
|
||||
&& SUCCEEDED(hr = IDxcResult_GetOutput(result, DXC_OUT_ERRORS, &IID_IDxcBlobUtf8, (void **)&errors, NULL)))
|
||||
{
|
||||
if (IDxcBlobUtf8_GetStringLength(errors))
|
||||
d3d10_blob_from_dxc_blob_utf8(errors, errors_out);
|
||||
IDxcBlobUtf8_Release(errors);
|
||||
}
|
||||
|
||||
if (FAILED(hr = IDxcResult_GetStatus(result, &compile_hr)) || FAILED((hr = compile_hr)))
|
||||
{
|
||||
if (hr == DXC_E_LLVM_CAST_ERROR)
|
||||
hr = E_FAIL;
|
||||
goto result_release;
|
||||
}
|
||||
|
||||
if (FAILED(hr = IDxcResult_GetOutput(result, DXC_OUT_OBJECT, &IID_IDxcBlob, (void **)&blob, NULL)))
|
||||
goto result_release;
|
||||
|
||||
IDxcResult_Release(result);
|
||||
|
||||
hr = d3d10_blob_from_dxc_blob(blob, blob_out);
|
||||
IDxcBlob_Release(blob);
|
||||
return hr;
|
||||
|
||||
result_release:
|
||||
IDxcResult_Release(result);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void compile_shader(struct shader_runner *runner, IDxcCompiler3 *dxc_compiler, const char *source, size_t len,
|
||||
enum shader_type type, HRESULT expect)
|
||||
{
|
||||
bool use_dxcompiler = runner->minimum_shader_model >= SHADER_MODEL_6_0;
|
||||
ID3D10Blob *blob = NULL, *errors = NULL;
|
||||
char profile[7];
|
||||
HRESULT hr;
|
||||
@@ -817,10 +950,19 @@ static void compile_shader(struct shader_runner *runner, const char *source, siz
|
||||
[SHADER_MODEL_4_1] = "4_1",
|
||||
[SHADER_MODEL_5_0] = "5_0",
|
||||
[SHADER_MODEL_5_1] = "5_1",
|
||||
[SHADER_MODEL_6_0] = "6_0",
|
||||
};
|
||||
|
||||
sprintf(profile, "%s_%s", shader_type_string(type), shader_models[runner->minimum_shader_model]);
|
||||
hr = D3DCompile(source, len, NULL, NULL, NULL, "main", profile, runner->compile_options, 0, &blob, &errors);
|
||||
if (use_dxcompiler)
|
||||
{
|
||||
assert(dxc_compiler);
|
||||
hr = dxc_compiler_compile_shader(dxc_compiler, type, runner->compile_options, source, &blob, &errors);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(profile, "%s_%s", shader_type_string(type), shader_models[runner->minimum_shader_model]);
|
||||
hr = D3DCompile(source, len, NULL, NULL, NULL, "main", profile, runner->compile_options, 0, &blob, &errors);
|
||||
}
|
||||
hr = map_unidentified_hrs(hr);
|
||||
ok(hr == expect, "Got unexpected hr %#x.\n", hr);
|
||||
if (hr == S_OK)
|
||||
@@ -845,8 +987,11 @@ static enum parse_state read_shader_directive(struct shader_runner *runner, enum
|
||||
{
|
||||
while (*src && *src != ']')
|
||||
{
|
||||
/* 'todo' is not meaningful when dxcompiler is in use, so it has no '(sm<6) qualifier. */
|
||||
if (match_directive_substring(src, "todo", &src))
|
||||
{
|
||||
if (runner->minimum_shader_model >= SHADER_MODEL_6_0)
|
||||
continue;
|
||||
if (state == STATE_SHADER_COMPUTE)
|
||||
state = STATE_SHADER_COMPUTE_TODO;
|
||||
else if (state == STATE_SHADER_PIXEL)
|
||||
@@ -858,9 +1003,20 @@ static enum parse_state read_shader_directive(struct shader_runner *runner, enum
|
||||
{
|
||||
*expect_hr = E_FAIL;
|
||||
}
|
||||
else if (match_directive_substring(src, "notimpl", &src))
|
||||
else if (match_directive_substring(src, "fail(sm<6)", &src))
|
||||
{
|
||||
*expect_hr = E_NOTIMPL;
|
||||
if (runner->minimum_shader_model < SHADER_MODEL_6_0)
|
||||
*expect_hr = E_FAIL;
|
||||
}
|
||||
else if (match_directive_substring(src, "fail(sm>=6)", &src))
|
||||
{
|
||||
if (runner->minimum_shader_model >= SHADER_MODEL_6_0)
|
||||
*expect_hr = E_FAIL;
|
||||
}
|
||||
else if (match_directive_substring(src, "notimpl(sm<6)", &src))
|
||||
{
|
||||
if (runner->minimum_shader_model < SHADER_MODEL_6_0)
|
||||
*expect_hr = E_NOTIMPL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -874,7 +1030,8 @@ static enum parse_state read_shader_directive(struct shader_runner *runner, enum
|
||||
return state;
|
||||
}
|
||||
|
||||
void run_shader_tests(struct shader_runner *runner, const struct shader_runner_ops *ops)
|
||||
void run_shader_tests(struct shader_runner *runner, const struct shader_runner_ops *ops, void *dxc_compiler,
|
||||
enum shader_model minimum_shader_model, enum shader_model maximum_shader_model)
|
||||
{
|
||||
size_t shader_source_size = 0, shader_source_len = 0;
|
||||
struct resource_params current_resource;
|
||||
@@ -895,7 +1052,8 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o
|
||||
|
||||
memset(runner, 0, sizeof(*runner));
|
||||
runner->ops = ops;
|
||||
runner->minimum_shader_model = SHADER_MODEL_2_0;
|
||||
runner->minimum_shader_model = minimum_shader_model;
|
||||
runner->maximum_shader_model = maximum_shader_model;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -915,7 +1073,8 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o
|
||||
break;
|
||||
|
||||
case STATE_REQUIRE:
|
||||
if (runner->ops->check_requirements && !runner->ops->check_requirements(runner))
|
||||
if (runner->maximum_shader_model < runner->minimum_shader_model
|
||||
|| (runner->ops->check_requirements && !runner->ops->check_requirements(runner)))
|
||||
{
|
||||
skip_tests = true;
|
||||
}
|
||||
@@ -931,7 +1090,8 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o
|
||||
if (!skip_tests)
|
||||
{
|
||||
todo_if (state == STATE_SHADER_COMPUTE_TODO)
|
||||
compile_shader(runner, shader_source, shader_source_len, SHADER_TYPE_CS, expect_hr);
|
||||
compile_shader(runner, dxc_compiler, shader_source, shader_source_len, SHADER_TYPE_CS,
|
||||
expect_hr);
|
||||
}
|
||||
free(runner->cs_source);
|
||||
runner->cs_source = shader_source;
|
||||
@@ -945,7 +1105,8 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o
|
||||
if (!skip_tests)
|
||||
{
|
||||
todo_if (state == STATE_SHADER_PIXEL_TODO)
|
||||
compile_shader(runner, shader_source, shader_source_len, SHADER_TYPE_PS, expect_hr);
|
||||
compile_shader(runner, dxc_compiler, shader_source, shader_source_len, SHADER_TYPE_PS,
|
||||
expect_hr);
|
||||
}
|
||||
free(runner->ps_source);
|
||||
runner->ps_source = shader_source;
|
||||
@@ -959,7 +1120,8 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o
|
||||
if (!skip_tests)
|
||||
{
|
||||
todo_if (state == STATE_SHADER_VERTEX_TODO)
|
||||
compile_shader(runner, shader_source, shader_source_len, SHADER_TYPE_VS, expect_hr);
|
||||
compile_shader(runner, dxc_compiler, shader_source, shader_source_len, SHADER_TYPE_VS,
|
||||
expect_hr);
|
||||
}
|
||||
free(runner->vs_source);
|
||||
runner->vs_source = shader_source;
|
||||
@@ -1047,7 +1209,8 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o
|
||||
else if (!strcmp(line, "[require]\n"))
|
||||
{
|
||||
state = STATE_REQUIRE;
|
||||
runner->minimum_shader_model = SHADER_MODEL_2_0;
|
||||
runner->minimum_shader_model = minimum_shader_model;
|
||||
runner->maximum_shader_model = maximum_shader_model;
|
||||
runner->compile_options = 0;
|
||||
skip_tests = false;
|
||||
}
|
||||
@@ -1208,7 +1371,9 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o
|
||||
break;
|
||||
|
||||
case STATE_TEST:
|
||||
if (!skip_tests)
|
||||
/* Compilation which fails with dxcompiler is not 'todo', therefore the tests are
|
||||
* not 'todo' either. They cannot run, so skip them entirely. */
|
||||
if (!skip_tests && SUCCEEDED(expect_hr))
|
||||
parse_test_directive(runner, line);
|
||||
break;
|
||||
}
|
||||
@@ -1284,8 +1449,47 @@ out:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SONAME_LIBDXCOMPILER) && !defined(VKD3D_CROSSTEST)
|
||||
static IDxcCompiler3 *dxcompiler_create()
|
||||
{
|
||||
DxcCreateInstanceProc create_instance;
|
||||
IDxcCompiler3 *compiler;
|
||||
HRESULT hr;
|
||||
void *dll;
|
||||
|
||||
if (!(dll = vkd3d_dlopen(SONAME_LIBDXCOMPILER)))
|
||||
{
|
||||
trace("Failed to load dxcompiler library, %s.\n", vkd3d_dlerror());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(create_instance = (DxcCreateInstanceProc)vkd3d_dlsym(dll, "DxcCreateInstance")))
|
||||
{
|
||||
trace("Failed to get DxcCreateInstance() pointer.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (FAILED(hr = create_instance(&CLSID_DxcCompiler, &IID_IDxcCompiler3, (void **)&compiler)))
|
||||
{
|
||||
trace("Failed to create instance, hr %#x.\n", hr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return compiler;
|
||||
}
|
||||
#elif !defined(VKD3D_CROSSTEST)
|
||||
static IDxcCompiler3 *dxcompiler_create()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
START_TEST(shader_runner)
|
||||
{
|
||||
#ifndef VKD3D_CROSSTEST
|
||||
IDxcCompiler3 *dxc_compiler;
|
||||
#endif
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
#if defined(VKD3D_CROSSTEST)
|
||||
@@ -1298,7 +1502,7 @@ START_TEST(shader_runner)
|
||||
run_shader_tests_d3d11();
|
||||
|
||||
trace("Compiling shaders with d3dcompiler_47.dll and executing with d3d12.dll\n");
|
||||
run_shader_tests_d3d12();
|
||||
run_shader_tests_d3d12(NULL, SHADER_MODEL_4_0, SHADER_MODEL_5_1);
|
||||
|
||||
print_dll_version("d3dcompiler_47.dll");
|
||||
print_dll_version("dxgi.dll");
|
||||
@@ -1315,7 +1519,15 @@ START_TEST(shader_runner)
|
||||
run_shader_tests_d3d11();
|
||||
|
||||
trace("Compiling shaders with vkd3d-shader and executing with vkd3d\n");
|
||||
run_shader_tests_d3d12();
|
||||
run_shader_tests_d3d12(NULL, SHADER_MODEL_4_0, SHADER_MODEL_5_1);
|
||||
|
||||
if ((dxc_compiler = dxcompiler_create()))
|
||||
{
|
||||
trace("Compiling shaders with dxcompiler and executing with vkd3d\n");
|
||||
run_shader_tests_d3d12(dxc_compiler, SHADER_MODEL_6_0, SHADER_MODEL_6_0);
|
||||
IDxcCompiler3_Release(dxc_compiler);
|
||||
print_dll_version(SONAME_LIBDXCOMPILER);
|
||||
}
|
||||
|
||||
print_dll_version("d3d9.dll");
|
||||
print_dll_version("d3d11.dll");
|
||||
@@ -1326,6 +1538,13 @@ START_TEST(shader_runner)
|
||||
run_shader_tests_vulkan();
|
||||
|
||||
trace("Compiling shaders with vkd3d-shader and executing with vkd3d\n");
|
||||
run_shader_tests_d3d12();
|
||||
run_shader_tests_d3d12(NULL, SHADER_MODEL_4_0, SHADER_MODEL_5_1);
|
||||
|
||||
if ((dxc_compiler = dxcompiler_create()))
|
||||
{
|
||||
trace("Compiling shaders with dxcompiler and executing with vkd3d\n");
|
||||
run_shader_tests_d3d12(dxc_compiler, SHADER_MODEL_6_0, SHADER_MODEL_6_0);
|
||||
IDxcCompiler3_Release(dxc_compiler);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
Reference in New Issue
Block a user