Currently we are not properly handling register(cX) reservations for SM1, this is one of the things required for the SNK shaders (CW Bug Bug 18092).
register(cX) reservations also change the offset in the $Globals buffer in SM4, so support for this is also included.
---
Patch 1/4 is required to specify: ``` [require] shader model < 4.0 ``` so that the tests that follow do not get run with the vulkan backend on SM4. I think nobody disagreed with that patch.
-- v4: vkd3d-shader/hlsl: Turn register(cX) reservations into buffer offset for SM4. vkd3d-shader/hlsl: Make register(cX) reservations work for SM1. tests: Test register(cX) reservations. tests: Rename register-reservations.shader_test to register-reservations-resources.shader_test. tests/vkd3d-shader: Allow passing (sm<4) and (sm>=4) to "fail" and "todo" qualifiers. tests/shader-runner: Discern between the minimum_shader_model and the selected_shader_model. tests/shader-runner: Add missing requirement checks for backends. ci: Execute the shader runner on the correct test data on Windows. ci: Deduplicate the CI configuration for Windows.
From: Giovanni Mascellani gmascellani@codeweavers.com
--- gitlab/test.yml | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-)
diff --git a/gitlab/test.yml b/gitlab/test.yml index 97bebba53..cfc4906f5 100644 --- a/gitlab/test.yml +++ b/gitlab/test.yml @@ -1,4 +1,4 @@ -test-win-64: +.test-win: stage: test rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' @@ -9,27 +9,17 @@ test-win-64: - win10-21h2 script: - ./artifacts/driver.cross64.exe - variables: - TEST_ARCH: "64" artifacts: when: always paths: - artifacts
+test-win-64: + extends: .test-win + variables: + TEST_ARCH: "64" + test-win-32: - stage: test - rules: - - if: $CI_PIPELINE_SOURCE == 'merge_request_event' - interruptible: true - needs: - - job: build-crosstest - tags: - - win10-21h2 - script: - - ./artifacts/driver.cross64.exe + extends: .test-win variables: TEST_ARCH: "32" - artifacts: - when: always - paths: - - artifacts
From: Giovanni Mascellani gmascellani@codeweavers.com
--- gitlab/test.yml | 3 ++- tests/driver.c | 52 ++++++++++++++++++++++++++----------------------- 2 files changed, 30 insertions(+), 25 deletions(-)
diff --git a/gitlab/test.yml b/gitlab/test.yml index cfc4906f5..65a75d0e9 100644 --- a/gitlab/test.yml +++ b/gitlab/test.yml @@ -8,7 +8,8 @@ tags: - win10-21h2 script: - - ./artifacts/driver.cross64.exe + - git rebase $CI_MERGE_REQUEST_DIFF_BASE_SHA --exec './artifacts/driver.cross64.exe $(git cherry $CI_MERGE_REQUEST_DIFF_BASE_SHA HEAD^ | wc -l) $(git rev-parse --short HEAD)' + - if (Test-Path "pipeline_failed") { exit 1 } artifacts: when: always paths: diff --git a/tests/driver.c b/tests/driver.c index 553417ada..00bf227a4 100644 --- a/tests/driver.c +++ b/tests/driver.c @@ -18,6 +18,7 @@
#include <stdio.h> #include <stdbool.h> +#include <stdlib.h> #include <windows.h> #include <shlobj.h>
@@ -215,40 +216,43 @@ static bool run_tests_for_directory(const char *commit_dir) printf("# FAIL: %u\n", test_count - success_count);
if (test_count != success_count) - ret = false; + { + HANDLE handle; + + handle = CreateFileA("pipeline_failed", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "Cannot create failure file, last error %ld.\n", GetLastError()); + ret = false; + } + else + { + if (!CloseHandle(handle)) + fprintf(stderr, "Cannot close failure file, last error %ld.\n", GetLastError()); + } + }
return ret; }
-int wmain(void) +int wmain(int argc, WCHAR **wargv) { - WIN32_FIND_DATAA find_data; - HANDLE find_handle; - bool ret = true; + char commit_num[16], commit_hash[16], commit_dir[16];
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
- find_handle = FindFirstFileA("artifacts/*-*", &find_data); - if (find_handle == INVALID_HANDLE_VALUE) + if (argc != 3) { - fprintf(stderr, "Cannot list commits, last error %ld.\n", GetLastError()); - ret = false; + fprintf(stderr, "Call with commit number and hash.\n"); + return 1; } - else - { - do - { - ret &= run_tests_for_directory(find_data.cFileName); - } while (FindNextFileA(find_handle, &find_data));
- if (GetLastError() != ERROR_NO_MORE_FILES) - { - fprintf(stderr, "Cannot list tests, last error %ld.\n", GetLastError()); - ret = false; - } - - FindClose(find_handle); - } + WideCharToMultiByte(CP_ACP, 0, wargv[1], -1, commit_num, sizeof(commit_num), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, wargv[2], -1, commit_hash, sizeof(commit_hash), NULL, NULL); + commit_num[sizeof(commit_num) - 1] = '\0'; + commit_hash[sizeof(commit_hash) - 1] = '\0'; + snprintf(commit_dir, sizeof(commit_dir), "%03d-%s", atoi(commit_num), commit_hash); + commit_dir[sizeof(commit_dir) - 1] = '\0';
- return !ret; + return !run_tests_for_directory(commit_dir); }
From: Francisco Casas fcasas@codeweavers.com
We need these checks to properly handle tests that require target profiles 3.0 and lower, or tests that require target profile 6.0 and higher.
Since all backeds require an ops->check_requirements now, expect it to always be defined. --- tests/shader_runner.c | 3 ++- tests/shader_runner.h | 4 ++-- tests/shader_runner_d3d11.c | 13 +++++++++++++ tests/shader_runner_d3d12.c | 14 ++++++++++++++ tests/shader_runner_vulkan.c | 13 +++++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/tests/shader_runner.c b/tests/shader_runner.c index dadfe3338..43949c01a 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -1089,8 +1089,9 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o break;
case STATE_REQUIRE: + assert(runner->ops->check_requirements); if (runner->maximum_shader_model < runner->minimum_shader_model - || (runner->ops->check_requirements && !runner->ops->check_requirements(runner))) + || !runner->ops->check_requirements(runner)) { skip_tests = true; } diff --git a/tests/shader_runner.h b/tests/shader_runner.h index bda44a429..ee0e9094d 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -142,9 +142,9 @@ struct shader_runner
struct shader_runner_ops { - /* Returns false if unable to run the given tests. If NULL, all tests are - * run. */ + /* Returns false if unable to run the given tests. */ bool (*check_requirements)(struct shader_runner *runner); + struct resource *(*create_resource)(struct shader_runner *runner, const struct resource_params *params); void (*destroy_resource)(struct shader_runner *runner, struct resource *resource); bool (*draw)(struct shader_runner *runner, D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count); diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index bd9d363ce..7a8f8dac0 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -100,6 +100,18 @@ static ID3D10Blob *compile_shader(const struct d3d11_shader_runner *runner, cons return blob; }
+static bool d3d11_runner_check_requirements(struct shader_runner *r) +{ + struct d3d11_shader_runner *runner = d3d11_shader_runner(r); + + if (runner->r.maximum_shader_model < SHADER_MODEL_4_0) + return false; + if (runner->r.minimum_shader_model >= SHADER_MODEL_6_0) + return false; + + return true; +} + static IDXGIAdapter *create_adapter(void) { IDXGIFactory4 *factory4; @@ -724,6 +736,7 @@ static void d3d11_runner_release_readback(struct shader_runner *r, struct resour
static const struct shader_runner_ops d3d11_runner_ops = { + .check_requirements = d3d11_runner_check_requirements, .create_resource = d3d11_runner_create_resource, .destroy_resource = d3d11_runner_destroy_resource, .dispatch = d3d11_runner_dispatch, diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index a05dfd059..bb50564fa 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -96,6 +96,19 @@ static ID3D10Blob *compile_shader(const struct d3d12_shader_runner *runner, cons return blob; }
+static bool d3d12_runner_check_requirements(struct shader_runner *r) +{ + struct d3d12_shader_runner *runner = d3d12_shader_runner(r); + + if (runner->r.maximum_shader_model < SHADER_MODEL_4_0) + return false; + + if (runner->r.minimum_shader_model >= SHADER_MODEL_6_0 && !runner->dxc_compiler) + return false; + + return true; +} + #define MAX_RESOURCE_DESCRIPTORS (MAX_RESOURCES * 2)
static struct resource *d3d12_runner_create_resource(struct shader_runner *r, const struct resource_params *params) @@ -561,6 +574,7 @@ static void d3d12_runner_release_readback(struct shader_runner *r, struct resour
static const struct shader_runner_ops d3d12_runner_ops = { + .check_requirements = d3d12_runner_check_requirements, .create_resource = d3d12_runner_create_resource, .destroy_resource = d3d12_runner_destroy_resource, .dispatch = d3d12_runner_dispatch, diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index f89b4d624..ec2d1fc9e 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -83,6 +83,18 @@ static struct vulkan_shader_runner *vulkan_shader_runner(struct shader_runner *r
#define VK_CALL(f) (runner->f)
+static bool vulkan_runner_check_requirements(struct shader_runner *r) +{ + struct vulkan_shader_runner *runner = vulkan_shader_runner(r); + + if (runner->r.maximum_shader_model < SHADER_MODEL_4_0) + return false; + if (runner->r.minimum_shader_model >= SHADER_MODEL_6_0) + return false; + + return true; +} + static void begin_command_buffer(struct vulkan_shader_runner *runner) { VkCommandBufferBeginInfo buffer_begin_desc = {.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; @@ -1157,6 +1169,7 @@ static void vulkan_runner_release_readback(struct shader_runner *r, struct resou
static const struct shader_runner_ops vulkan_runner_ops = { + .check_requirements = vulkan_runner_check_requirements, .create_resource = vulkan_runner_create_resource, .destroy_resource = vulkan_runner_destroy_resource, .dispatch = vulkan_runner_dispatch,
From: Francisco Casas fcasas@codeweavers.com
In case that the backend selects a shader model that is higher than the minimum in the provided range, it doesn't make sense to check todos(...), fails(...), or notimpl(...) against the minimum.
So the backend must report the selected model for the given range (if any). This is done through the check_requirements() function. --- tests/shader_runner.c | 26 +++++++++++++++----------- tests/shader_runner.h | 6 ++++-- tests/shader_runner_d3d11.c | 8 ++++---- tests/shader_runner_d3d12.c | 12 ++++++------ tests/shader_runner_d3d9.c | 6 ++++-- tests/shader_runner_vulkan.c | 8 ++++---- 6 files changed, 37 insertions(+), 29 deletions(-)
diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 43949c01a..b9adec8b4 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -501,9 +501,9 @@ 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; + runner->is_todo = runner->selected_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; + runner->is_todo = runner->selected_shader_model >= SHADER_MODEL_6_0;
if (match_string(line, "dispatch", &line)) { @@ -940,7 +940,7 @@ result_release: 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; + bool use_dxcompiler = runner->selected_shader_model >= SHADER_MODEL_6_0; ID3D10Blob *blob = NULL, *errors = NULL; char profile[7]; HRESULT hr; @@ -972,9 +972,9 @@ static void compile_shader(struct shader_runner *runner, IDxcCompiler3 *dxc_comp else { if (type == SHADER_TYPE_FX) - sprintf(profile, "%s_%s", shader_type_string(type), effect_models[runner->minimum_shader_model]); + sprintf(profile, "%s_%s", shader_type_string(type), effect_models[runner->selected_shader_model]); else - sprintf(profile, "%s_%s", shader_type_string(type), shader_models[runner->minimum_shader_model]); + sprintf(profile, "%s_%s", shader_type_string(type), shader_models[runner->selected_shader_model]); hr = D3DCompile(source, len, NULL, NULL, NULL, "main", profile, runner->compile_options, 0, &blob, &errors); } hr = map_unidentified_hrs(hr); @@ -1004,7 +1004,7 @@ static enum parse_state read_shader_directive(struct shader_runner *runner, enum /* '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) + if (runner->selected_shader_model >= SHADER_MODEL_6_0) continue; if (state == STATE_SHADER_COMPUTE) state = STATE_SHADER_COMPUTE_TODO; @@ -1021,17 +1021,17 @@ static enum parse_state read_shader_directive(struct shader_runner *runner, enum } else if (match_directive_substring(src, "fail(sm<6)", &src)) { - if (runner->minimum_shader_model < SHADER_MODEL_6_0) + if (runner->selected_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) + if (runner->selected_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) + if (runner->selected_shader_model < SHADER_MODEL_6_0) *expect_hr = E_NOTIMPL; } else @@ -1070,6 +1070,10 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o runner->ops = ops; runner->minimum_shader_model = minimum_shader_model; runner->maximum_shader_model = maximum_shader_model; + runner->selected_shader_model = minimum_shader_model; + + assert(runner->ops->check_requirements); + skip_tests = !runner->ops->check_requirements(runner, &runner->selected_shader_model);
for (;;) { @@ -1089,9 +1093,8 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o break;
case STATE_REQUIRE: - assert(runner->ops->check_requirements); if (runner->maximum_shader_model < runner->minimum_shader_model - || !runner->ops->check_requirements(runner)) + || !runner->ops->check_requirements(runner, &runner->selected_shader_model)) { skip_tests = true; } @@ -1249,6 +1252,7 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o state = STATE_REQUIRE; runner->minimum_shader_model = minimum_shader_model; runner->maximum_shader_model = maximum_shader_model; + runner->selected_shader_model = minimum_shader_model; runner->compile_options = 0; skip_tests = false; } diff --git a/tests/shader_runner.h b/tests/shader_runner.h index ee0e9094d..89a01abff 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -122,6 +122,7 @@ struct shader_runner char *fx_source; enum shader_model minimum_shader_model; enum shader_model maximum_shader_model; + enum shader_model selected_shader_model;
bool last_render_failed;
@@ -142,8 +143,9 @@ struct shader_runner
struct shader_runner_ops { - /* Returns false if unable to run the given tests. */ - bool (*check_requirements)(struct shader_runner *runner); + /* Returns false if unable to run the given tests. Otherwise, it also outputs the lowest model + * supported within the range provided in the runner. */ + bool (*check_requirements)(struct shader_runner *runner, enum shader_model *model);
struct resource *(*create_resource)(struct shader_runner *runner, const struct resource_params *params); void (*destroy_resource)(struct shader_runner *runner, struct resource *resource); diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index 7a8f8dac0..df704da8c 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -80,15 +80,13 @@ static ID3D10Blob *compile_shader(const struct d3d11_shader_runner *runner, cons
static const char *const shader_models[] = { - [SHADER_MODEL_2_0] = "4_0", - [SHADER_MODEL_3_0] = "4_0", [SHADER_MODEL_4_0] = "4_0", [SHADER_MODEL_4_1] = "4_1", [SHADER_MODEL_5_0] = "5_0", [SHADER_MODEL_5_1] = "5_1", };
- sprintf(profile, "%s_%s", type, shader_models[runner->r.minimum_shader_model]); + sprintf(profile, "%s_%s", type, shader_models[runner->r.selected_shader_model]); hr = D3DCompile(source, strlen(source), NULL, NULL, NULL, "main", profile, runner->r.compile_options, 0, &blob, &errors); ok(hr == S_OK, "Failed to compile shader, hr %#lx.\n", hr); if (errors) @@ -100,7 +98,7 @@ static ID3D10Blob *compile_shader(const struct d3d11_shader_runner *runner, cons return blob; }
-static bool d3d11_runner_check_requirements(struct shader_runner *r) +static bool d3d11_runner_check_requirements(struct shader_runner *r, enum shader_model *model) { struct d3d11_shader_runner *runner = d3d11_shader_runner(r);
@@ -109,6 +107,8 @@ static bool d3d11_runner_check_requirements(struct shader_runner *r) if (runner->r.minimum_shader_model >= SHADER_MODEL_6_0) return false;
+ *model = max(SHADER_MODEL_4_0, runner->r.minimum_shader_model); + return true; }
diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index bb50564fa..2fd89d74e 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -67,8 +67,6 @@ static ID3D10Blob *compile_shader(const struct d3d12_shader_runner *runner, cons
static const char *const shader_models[] = { - [SHADER_MODEL_2_0] = "4_0", - [SHADER_MODEL_3_0] = "4_0", [SHADER_MODEL_4_0] = "4_0", [SHADER_MODEL_4_1] = "4_1", [SHADER_MODEL_5_0] = "5_0", @@ -76,14 +74,14 @@ static ID3D10Blob *compile_shader(const struct d3d12_shader_runner *runner, cons [SHADER_MODEL_6_0] = "6_0", };
- if (runner->r.minimum_shader_model >= SHADER_MODEL_6_0) + if (runner->r.selected_shader_model >= SHADER_MODEL_6_0) { assert(runner->dxc_compiler); hr = dxc_compiler_compile_shader(runner->dxc_compiler, type, runner->r.compile_options, source, &blob, &errors); } else { - sprintf(profile, "%s_%s", shader_type_string(type), shader_models[runner->r.minimum_shader_model]); + sprintf(profile, "%s_%s", shader_type_string(type), shader_models[runner->r.selected_shader_model]); hr = D3DCompile(source, strlen(source), NULL, NULL, NULL, "main", profile, runner->r.compile_options, 0, &blob, &errors); } ok(FAILED(hr) == !blob, "Got unexpected hr %#x, blob %p.\n", hr, blob); @@ -96,7 +94,7 @@ static ID3D10Blob *compile_shader(const struct d3d12_shader_runner *runner, cons return blob; }
-static bool d3d12_runner_check_requirements(struct shader_runner *r) +static bool d3d12_runner_check_requirements(struct shader_runner *r, enum shader_model *model) { struct d3d12_shader_runner *runner = d3d12_shader_runner(r);
@@ -106,6 +104,8 @@ static bool d3d12_runner_check_requirements(struct shader_runner *r) if (runner->r.minimum_shader_model >= SHADER_MODEL_6_0 && !runner->dxc_compiler) return false;
+ *model = max(SHADER_MODEL_4_0, runner->r.minimum_shader_model); + return true; }
@@ -334,7 +334,7 @@ static bool d3d12_runner_dispatch(struct shader_runner *r, unsigned int x, unsig size_t i;
cs_code = compile_shader(runner, runner->r.cs_source, SHADER_TYPE_CS); - todo_if(runner->r.is_todo && runner->r.minimum_shader_model < SHADER_MODEL_6_0) ok(cs_code, "Failed to compile shader.\n"); + todo_if(runner->r.is_todo && runner->r.selected_shader_model < SHADER_MODEL_6_0) ok(cs_code, "Failed to compile shader.\n"); if (!cs_code) return false;
diff --git a/tests/shader_runner_d3d9.c b/tests/shader_runner_d3d9.c index 0b33c1c53..fbd7d6b5b 100644 --- a/tests/shader_runner_d3d9.c +++ b/tests/shader_runner_d3d9.c @@ -68,7 +68,7 @@ static ID3D10Blob *compile_shader(const struct d3d9_shader_runner *runner, const [SHADER_MODEL_3_0] = "3_0", };
- sprintf(profile, "%s_%s", type, shader_models[runner->r.minimum_shader_model]); + sprintf(profile, "%s_%s", type, shader_models[runner->r.selected_shader_model]); hr = D3DCompile(source, strlen(source), NULL, NULL, NULL, "main", profile, runner->r.compile_options, 0, &blob, &errors); ok(hr == S_OK, "Failed to compile shader, hr %#lx.\n", hr); if (errors) @@ -183,13 +183,15 @@ static D3DTEXTUREADDRESS sampler_address_to_d3d9(D3D12_TEXTURE_ADDRESS_MODE addr vkd3d_unreachable(); }
-static bool d3d9_runner_check_requirements(struct shader_runner *r) +static bool d3d9_runner_check_requirements(struct shader_runner *r, enum shader_model *model) { struct d3d9_shader_runner *runner = d3d9_shader_runner(r);
if (runner->r.minimum_shader_model >= SHADER_MODEL_4_0) return false;
+ *model = runner->r.minimum_shader_model; + return true; }
diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index ec2d1fc9e..131e394b0 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -83,7 +83,7 @@ static struct vulkan_shader_runner *vulkan_shader_runner(struct shader_runner *r
#define VK_CALL(f) (runner->f)
-static bool vulkan_runner_check_requirements(struct shader_runner *r) +static bool vulkan_runner_check_requirements(struct shader_runner *r, enum shader_model *model) { struct vulkan_shader_runner *runner = vulkan_shader_runner(r);
@@ -92,6 +92,8 @@ static bool vulkan_runner_check_requirements(struct shader_runner *r) if (runner->r.minimum_shader_model >= SHADER_MODEL_6_0) return false;
+ *model = max(SHADER_MODEL_4_0, runner->r.minimum_shader_model); + return true; }
@@ -407,8 +409,6 @@ static bool compile_shader(const struct vulkan_shader_runner *runner, const char
static const char *const shader_models[] = { - [SHADER_MODEL_2_0] = "4_0", - [SHADER_MODEL_3_0] = "4_0", [SHADER_MODEL_4_0] = "4_0", [SHADER_MODEL_4_1] = "4_1", [SHADER_MODEL_5_0] = "5_0", @@ -451,7 +451,7 @@ static bool compile_shader(const struct vulkan_shader_runner *runner, const char }
hlsl_info.entry_point = "main"; - sprintf(profile, "%s_%s", type, shader_models[runner->r.minimum_shader_model]); + sprintf(profile, "%s_%s", type, shader_models[runner->r.selected_shader_model]); hlsl_info.profile = profile;
ret = vkd3d_shader_compile(&info, dxbc, &messages);
From: Francisco Casas fcasas@codeweavers.com
--- tests/shader_runner.c | 48 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-)
diff --git a/tests/shader_runner.c b/tests/shader_runner.c index b9adec8b4..745f17b3a 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -500,6 +500,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<4)", &line)) + runner->is_todo = runner->selected_shader_model < SHADER_MODEL_4_0; + else if (match_string(line, "todo(sm>=4)", &line)) + runner->is_todo = runner->selected_shader_model >= SHADER_MODEL_4_0; else if (match_string(line, "todo(sm<6)", &line)) runner->is_todo = runner->selected_shader_model < SHADER_MODEL_6_0; else if (match_string(line, "todo(sm>=6)", &line)) @@ -996,6 +1000,18 @@ static void compile_shader(struct shader_runner *runner, IDxcCompiler3 *dxc_comp } }
+static enum parse_state get_parse_state_todo(enum parse_state state) +{ + if (state == STATE_SHADER_COMPUTE) + return STATE_SHADER_COMPUTE_TODO; + else if (state == STATE_SHADER_PIXEL) + return STATE_SHADER_PIXEL_TODO; + else if (state == STATE_SHADER_VERTEX) + return STATE_SHADER_VERTEX_TODO; + else + return STATE_SHADER_EFFECT_TODO; +} + static enum parse_state read_shader_directive(struct shader_runner *runner, enum parse_state state, const char *line, const char *src, HRESULT *expect_hr) { @@ -1006,19 +1022,35 @@ static enum parse_state read_shader_directive(struct shader_runner *runner, enum { if (runner->selected_shader_model >= SHADER_MODEL_6_0) continue; - if (state == STATE_SHADER_COMPUTE) - state = STATE_SHADER_COMPUTE_TODO; - else if (state == STATE_SHADER_PIXEL) - state = STATE_SHADER_PIXEL_TODO; - else if (state == STATE_SHADER_VERTEX) - state = STATE_SHADER_VERTEX_TODO; - else - state = STATE_SHADER_EFFECT_TODO; + state = get_parse_state_todo(state); + } + else if (match_directive_substring(src, "todo(sm<4)", &src)) + { + if (runner->selected_shader_model >= SHADER_MODEL_4_0) + continue; + state = get_parse_state_todo(state); + } + else if (match_directive_substring(src, "todo(sm>=4)", &src)) + { + if (runner->selected_shader_model >= SHADER_MODEL_6_0 + || runner->selected_shader_model < SHADER_MODEL_4_0) + continue; + state = get_parse_state_todo(state); } else if (match_directive_substring(src, "fail", &src)) { *expect_hr = E_FAIL; } + else if (match_directive_substring(src, "fail(sm<4)", &src)) + { + if (runner->selected_shader_model < SHADER_MODEL_4_0) + *expect_hr = E_FAIL; + } + else if (match_directive_substring(src, "fail(sm>=4)", &src)) + { + if (runner->selected_shader_model >= SHADER_MODEL_4_0) + *expect_hr = E_FAIL; + } else if (match_directive_substring(src, "fail(sm<6)", &src)) { if (runner->selected_shader_model < SHADER_MODEL_6_0)
From: Francisco Casas fcasas@codeweavers.com
--- Makefile.am | 2 +- ....shader_test => register-reservations-resources.shader_test} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/hlsl/{register-reservations.shader_test => register-reservations-resources.shader_test} (100%)
diff --git a/Makefile.am b/Makefile.am index 14b5cf096..dbaac9373 100644 --- a/Makefile.am +++ b/Makefile.am @@ -143,7 +143,7 @@ vkd3d_shader_tests = \ tests/hlsl/object-references.shader_test \ tests/hlsl/pow.shader_test \ tests/hlsl/reflect.shader_test \ - tests/hlsl/register-reservations.shader_test \ + tests/hlsl/register-reservations-resources.shader_test \ tests/hlsl/return-implicit-conversion.shader_test \ tests/hlsl/return.shader_test \ tests/hlsl/round.shader_test \ diff --git a/tests/hlsl/register-reservations.shader_test b/tests/hlsl/register-reservations-resources.shader_test similarity index 100% rename from tests/hlsl/register-reservations.shader_test rename to tests/hlsl/register-reservations-resources.shader_test
From: Francisco Casas fcasas@codeweavers.com
--- Makefile.am | 1 + .../register-reservations-numeric.shader_test | 236 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 tests/hlsl/register-reservations-numeric.shader_test
diff --git a/Makefile.am b/Makefile.am index dbaac9373..b27211540 100644 --- a/Makefile.am +++ b/Makefile.am @@ -143,6 +143,7 @@ vkd3d_shader_tests = \ tests/hlsl/object-references.shader_test \ tests/hlsl/pow.shader_test \ tests/hlsl/reflect.shader_test \ + tests/hlsl/register-reservations-numeric.shader_test \ tests/hlsl/register-reservations-resources.shader_test \ tests/hlsl/return-implicit-conversion.shader_test \ tests/hlsl/return.shader_test \ diff --git a/tests/hlsl/register-reservations-numeric.shader_test b/tests/hlsl/register-reservations-numeric.shader_test new file mode 100644 index 000000000..0a8f63d21 --- /dev/null +++ b/tests/hlsl/register-reservations-numeric.shader_test @@ -0,0 +1,236 @@ +[pixel shader fail(sm<6) todo] +// Overlapping register(cX) reservations are not allowed except on SM6, where they are aliased. +float a : register(c0); +float b : register(c0); + +float4 main() : sv_target +{ + return a + b; +} + + +[pixel shader] +// It is not required to provide a register(cX) for all elements in the $Globals buffer. +float4 a; // will get register(c1) +float4 b : register(c0); + +float4 main() : sv_target +{ + return float4(a.xw, b.yz); +} + +[test] +uniform 0 float4 0.1 0.2 0.3 0.4 +uniform 4 float4 1.1 1.2 1.3 1.4 +draw quad +todo(sm<6) probe all rgba (1.1, 1.4, 0.2, 0.3) + + +[pixel shader] +float4 a[3]; // will get register(c3) +float4 b[2] : register(c1); + +float4 main() : sv_target +{ + return float4(a[1].xy, b[0].zw); +} + +[test] +uniform 0 float4 0.1 0.2 0.3 0.4 +uniform 4 float4 1.1 1.2 1.3 1.4 +uniform 8 float4 2.1 2.2 2.3 2.4 +uniform 12 float4 3.1 3.2 3.3 3.4 +uniform 16 float4 4.1 4.2 4.3 4.4 +draw quad +todo(sm<6) probe all rgba (4.1, 4.2, 1.3, 1.4) + + +[require] +shader model >= 6.0 + +[pixel shader] +// Variables with overlapping register(cX) reservations are aliased in SM6. +float2 a : register(c2); +float3 b : register(c2); + +float4 main() : sv_target +{ + return float4(a, b.yz); +} + +[test] +uniform 0 float4 0.1 0.2 0.3 0.4 +uniform 4 float4 1.1 1.2 1.3 1.4 +uniform 8 float4 2.1 2.2 2.3 2.4 +draw quad +probe all rgba (2.1, 2.2, 2.2, 2.3) + + +% Results differ between SM1 and SM4 because in the latter variables can share the same register, +% using different writemasks. +[require] +shader model < 4.0 + +[pixel shader] +struct +{ + float2 a; + float b; +} apple : register(c2); + +float4 main() : sv_target +{ + return float4(apple.a, apple.b, 0); +} + +[test] +uniform 0 float4 0.1 0.2 0.3 0.4 +uniform 4 float4 1.1 1.2 1.3 1.4 +uniform 8 float4 2.1 2.2 2.3 2.4 +uniform 12 float4 3.1 3.2 3.3 3.4 +draw quad +todo probe all rgba (2.1, 2.2, 3.1, 0.0) + + +[require] +shader model >= 4.0 + +[pixel shader] +struct +{ + float2 a; + float b; +} apple : register(c2); + +float4 main() : sv_target +{ + return float4(apple.a, apple.b, 0); +} + +[test] +uniform 0 float4 0.1 0.2 0.3 0.4 +uniform 4 float4 1.1 1.2 1.3 1.4 +uniform 8 float4 2.1 2.2 2.3 2.4 +uniform 12 float4 3.1 3.2 3.3 3.4 +draw quad +todo(sm<6) probe all rgba (2.1, 2.2, 2.3, 0.0) + + +[pixel shader] +// On SM4, register(cX) has no effect unless in the $Globals buffer. +cbuffer extra +{ + float a : register(c1); +}; + +float4 main() : sv_target +{ + return a; +} + +[test] +uniform 0 float 100 +uniform 4 float 101 +draw quad +probe all rgba (100, 100, 100, 100) + + +[pixel shader fail(sm>=6)] +// On SM4 register(cX) has no effect unless in the $Globals buffer. +float4 main(uniform float a : register(c1)) : sv_target +{ + return a; +} + +[test] +uniform 0 float 100 +uniform 4 float 101 +draw quad +probe all rgba (100, 100, 100, 100) + +[pixel shader todo] +cbuffer c +{ + float a : packoffset(c1); + float b : packoffset(c2) : register(c1); + // ^ register(c1) ignored for cbuffer that is not $Globals. +} + +float4 main() : sv_target +{ + return float4(a, b, 0, 0); +} + +[test] +uniform 0 float 200 +uniform 4 float 201 +uniform 8 float 202 +todo(sm<6) draw quad +todo(sm<6) probe all rgba (201.0, 202.0, 0.0, 0.0) + + +[pixel shader fail(sm<4)] +int k : register(i0); // register(cX) is also required. + +float4 main() : sv_target +{ + return k; +} + + +[require] +% All shader models. + +% In SM1, most variables are needed in the "c" register group, for float operations. +% If a variable is needed in the "c" register group, register() reservations in other groups can be +% provided only if a register(cX) reservation is also provided. + +[pixel shader fail(sm<4)] +int k : register(i0); +// ^^ register(cX) is also required in SM1. + +float4 main() : sv_target +{ + return k; +} + +[pixel shader todo] +int k : register(i0) : register(c1); +// Shader compiles because a "c" register reservation is provided for "k". + +float4 main() : sv_target +{ + return k; +} + + +[require] +shader model >= 3.0 +% model 2.0 doesn't support unrollable loops. + +[pixel shader todo(sm<4)] +int k : register(i0); +// ^^ register(cX) is not required since "k" is just needed in the "i" register group. + +float4 main() : sv_target +{ + float f = 0; + + for (int i = 0; i < k; ++i) + f += i; + return f; +} + + +[pixel shader todo] +int k : register(c0) : register(b0); +// ^^ unlike the "c" register group, a reservation is not required for the "i" group, even though "k" is needed on it. + +float4 main() : sv_target +{ + float f = 0; + + for (int i = 0; i < k; ++i) + f += i; + return f; +}
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl_codegen.c | 41 ++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 76a010fb3..5ea6df57c 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -3947,13 +3947,46 @@ static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_ir_functi
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - if (var->is_uniform && var->last_read) + unsigned int reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC]; + + if (!var->is_uniform || !var->last_read || reg_size == 0) + continue; + + if (var->reg_reservation.reg_type == 'c') { - unsigned int reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC]; + unsigned int reg_idx = var->reg_reservation.reg_index; + unsigned int i;
- if (reg_size == 0) - continue; + assert(reg_size % 4 == 0); + for (i = 0; i < reg_size / 4; ++i) + { + if (get_available_writemask(&allocator, 1, UINT_MAX, reg_idx + i) != VKD3DSP_WRITEMASK_ALL) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, + "Overlapping register() reservations on 'c%u'.", reg_idx + i); + } + + record_allocation(ctx, &allocator, reg_idx + i, VKD3DSP_WRITEMASK_ALL, 1, UINT_MAX); + }
+ var->regs[HLSL_REGSET_NUMERIC].id = reg_idx; + var->regs[HLSL_REGSET_NUMERIC].allocation_size = reg_size / 4; + var->regs[HLSL_REGSET_NUMERIC].writemask = VKD3DSP_WRITEMASK_ALL; + var->regs[HLSL_REGSET_NUMERIC].allocated = true; + TRACE("Allocated reserved %s to %s.\n", var->name, + debug_register('c', var->regs[HLSL_REGSET_NUMERIC], var->data_type)); + } + } + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + unsigned int reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC]; + + if (!var->is_uniform || !var->last_read || reg_size == 0) + continue; + + if (!var->regs[HLSL_REGSET_NUMERIC].allocated) + { var->regs[HLSL_REGSET_NUMERIC] = allocate_numeric_registers_for_type(ctx, &allocator, 1, UINT_MAX, var->data_type); TRACE("Allocated %s to %s.\n", var->name,
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl_codegen.c | 96 ++++++++++++------- .../register-reservations-numeric.shader_test | 8 +- 2 files changed, 66 insertions(+), 38 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 5ea6df57c..80b75a88d 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -4124,45 +4124,52 @@ static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, uint3 return NULL; }
-static void calculate_buffer_offset(struct hlsl_ctx *ctx, struct hlsl_ir_var *var) +static void calculate_buffer_offset(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, bool register_reservation) { unsigned int var_reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC]; enum hlsl_type_class var_class = var->data_type->class; struct hlsl_buffer *buffer = var->buffer;
- if (var->reg_reservation.offset_type == 'c') + if (register_reservation) { - if (var->reg_reservation.offset_index % 4) + var->buffer_offset = 4 * var->reg_reservation.reg_index; + } + else + { + if (var->reg_reservation.offset_type == 'c') { - if (var_class == HLSL_CLASS_MATRIX) - { - hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, - "packoffset() reservations with matrix types must be aligned with the beginning of a register."); - } - else if (var_class == HLSL_CLASS_ARRAY) - { - hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, - "packoffset() reservations with array types must be aligned with the beginning of a register."); - } - else if (var_class == HLSL_CLASS_STRUCT) - { - hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, - "packoffset() reservations with struct types must be aligned with the beginning of a register."); - } - else if (var_class == HLSL_CLASS_VECTOR) + if (var->reg_reservation.offset_index % 4) { - unsigned int aligned_offset = hlsl_type_get_sm4_offset(var->data_type, var->reg_reservation.offset_index); - - if (var->reg_reservation.offset_index != aligned_offset) + if (var_class == HLSL_CLASS_MATRIX) + { hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, - "packoffset() reservations with vector types cannot span multiple registers."); + "packoffset() reservations with matrix types must be aligned with the beginning of a register."); + } + else if (var_class == HLSL_CLASS_ARRAY) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, + "packoffset() reservations with array types must be aligned with the beginning of a register."); + } + else if (var_class == HLSL_CLASS_STRUCT) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, + "packoffset() reservations with struct types must be aligned with the beginning of a register."); + } + else if (var_class == HLSL_CLASS_VECTOR) + { + unsigned int aligned_offset = hlsl_type_get_sm4_offset(var->data_type, var->reg_reservation.offset_index); + + if (var->reg_reservation.offset_index != aligned_offset) + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION, + "packoffset() reservations with vector types cannot span multiple registers."); + } } + var->buffer_offset = var->reg_reservation.offset_index; + } + else + { + var->buffer_offset = hlsl_type_get_sm4_offset(var->data_type, buffer->size); } - var->buffer_offset = var->reg_reservation.offset_index; - } - else - { - var->buffer_offset = hlsl_type_get_sm4_offset(var->data_type, buffer->size); }
TRACE("Allocated buffer offset %u to %s.\n", var->buffer_offset, var->name); @@ -4231,6 +4238,11 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx) } }
+static bool var_has_buffer_offset_register_reservation(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var) +{ + return var->reg_reservation.reg_type == 'c' && var->buffer == ctx->globals_buffer; +} + static void allocate_buffers(struct hlsl_ctx *ctx) { struct hlsl_buffer *buffer; @@ -4239,13 +4251,29 @@ static void allocate_buffers(struct hlsl_ctx *ctx)
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - if (var->is_uniform && !hlsl_type_is_resource(var->data_type)) - { - if (var->is_param) - var->buffer = ctx->params_buffer; + if (!var->is_uniform || hlsl_type_is_resource(var->data_type)) + continue;
- calculate_buffer_offset(ctx, var); - } + if (var->is_param) + var->buffer = ctx->params_buffer; + } + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (!var->is_uniform || hlsl_type_is_resource(var->data_type)) + continue; + + if (var_has_buffer_offset_register_reservation(ctx, var)) + calculate_buffer_offset(ctx, var, true); + } + + LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (!var->is_uniform || hlsl_type_is_resource(var->data_type)) + continue; + + if (!var_has_buffer_offset_register_reservation(ctx, var)) + calculate_buffer_offset(ctx, var, false); }
validate_buffer_offsets(ctx); diff --git a/tests/hlsl/register-reservations-numeric.shader_test b/tests/hlsl/register-reservations-numeric.shader_test index 0a8f63d21..f112eae68 100644 --- a/tests/hlsl/register-reservations-numeric.shader_test +++ b/tests/hlsl/register-reservations-numeric.shader_test @@ -1,4 +1,4 @@ -[pixel shader fail(sm<6) todo] +[pixel shader fail(sm<6)] // Overlapping register(cX) reservations are not allowed except on SM6, where they are aliased. float a : register(c0); float b : register(c0); @@ -23,7 +23,7 @@ float4 main() : sv_target uniform 0 float4 0.1 0.2 0.3 0.4 uniform 4 float4 1.1 1.2 1.3 1.4 draw quad -todo(sm<6) probe all rgba (1.1, 1.4, 0.2, 0.3) +probe all rgba (1.1, 1.4, 0.2, 0.3)
[pixel shader] @@ -42,7 +42,7 @@ uniform 8 float4 2.1 2.2 2.3 2.4 uniform 12 float4 3.1 3.2 3.3 3.4 uniform 16 float4 4.1 4.2 4.3 4.4 draw quad -todo(sm<6) probe all rgba (4.1, 4.2, 1.3, 1.4) +probe all rgba (4.1, 4.2, 1.3, 1.4)
[require] @@ -113,7 +113,7 @@ uniform 4 float4 1.1 1.2 1.3 1.4 uniform 8 float4 2.1 2.2 2.3 2.4 uniform 12 float4 3.1 3.2 3.3 3.4 draw quad -todo(sm<6) probe all rgba (2.1, 2.2, 2.3, 0.0) +probe all rgba (2.1, 2.2, 2.3, 0.0)
[pixel shader]
On Tue Nov 14 15:25:01 2023 +0000, Giovanni Mascellani wrote:
I think that by moving this code above `[require]` you don't have to set it again below.
This test and the following one are the same but with different shader models, because they give different results, so I prefer to keep them together with their [require] directives explicit.
I prepended the 2 commits from @giomasce's !474 required to fix the pipeline test failure on Windows when renaming test files.
Okay, now the pipeline is failing because the shader_runner is still running this compilation test for SM1 with ps_4_0:
``` [pixel shader fail(sm<4)] int k : register(i0); // ^^ register(cX) is also required in SM1.
float4 main() : sv_target { return k; } ``` so it is not failing as expected.