-- v2: vkd3d-shader/hlsl: Parse UAV types. vkd3d-shader/hlsl: Parse texture index expressions. vkd3d-shader/hlsl: Cast array indices inside of add_array_load(). tests: Add a basic shader test for typed UAV loads. tests: Add a basic shader test for compute shaders.
From: Zebediah Figura zfigura@codeweavers.com
--- Makefile.am | 1 + tests/compute.shader_test | 21 ++++ tests/d3d12.c | 20 ---- tests/d3d12_test_utils.h | 20 ++++ tests/shader_runner.c | 31 ++++- tests/shader_runner.h | 2 + tests/shader_runner_d3d11.c | 101 +++++++++++++--- tests/shader_runner_d3d12.c | 221 +++++++++++++++++++++++++++-------- tests/shader_runner_vulkan.c | 75 +++++++++++- tests/vulkan_procs.h | 2 + 10 files changed, 401 insertions(+), 93 deletions(-) create mode 100644 tests/compute.shader_test
diff --git a/Makefile.am b/Makefile.am index 110b66f6..3e69c28a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -62,6 +62,7 @@ vkd3d_shader_tests = \ tests/cast-to-half.shader_test \ tests/cast-to-int.shader_test \ tests/cast-to-uint.shader_test \ + tests/compute.shader_test \ tests/conditional.shader_test \ tests/floor.shader_test \ tests/hlsl-array-dimension.shader_test \ diff --git a/tests/compute.shader_test b/tests/compute.shader_test new file mode 100644 index 00000000..900756e6 --- /dev/null +++ b/tests/compute.shader_test @@ -0,0 +1,21 @@ +[require] +shader model >= 5.0 + +[uav 0] +format r32 float +size (1, 1) + +0.1 + +[compute shader] +RWTexture2D<float> u; + + [numthreads(1, 1, 1)] +void main() +{ + u[uint2(0, 0)] = -123.0; +} + +[test] +todo dispatch 1 1 1 +todo probe uav 0 (0, 0) r (-123.0) diff --git a/tests/d3d12.c b/tests/d3d12.c index 89bfab79..483c7888 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -689,26 +689,6 @@ static ID3D12RootSignature *create_texture_root_signature_(unsigned int line, return root_signature; }
-#define create_compute_pipeline_state(a, b, c) create_compute_pipeline_state_(__LINE__, a, b, c) -static ID3D12PipelineState *create_compute_pipeline_state_(unsigned int line, ID3D12Device *device, - ID3D12RootSignature *root_signature, const D3D12_SHADER_BYTECODE cs) -{ - D3D12_COMPUTE_PIPELINE_STATE_DESC pipeline_state_desc; - ID3D12PipelineState *pipeline_state = NULL; - HRESULT hr; - - memset(&pipeline_state_desc, 0, sizeof(pipeline_state_desc)); - pipeline_state_desc.pRootSignature = root_signature; - pipeline_state_desc.CS = cs; - pipeline_state_desc.NodeMask = 0; - pipeline_state_desc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; - hr = ID3D12Device_CreateComputePipelineState(device, &pipeline_state_desc, - &IID_ID3D12PipelineState, (void **)&pipeline_state); - ok_(line)(SUCCEEDED(hr), "Failed to create compute pipeline state, hr %#x.\n", hr); - - return pipeline_state; -} - #define create_command_signature(a, b) create_command_signature_(__LINE__, a, b) static ID3D12CommandSignature *create_command_signature_(unsigned int line, ID3D12Device *device, D3D12_INDIRECT_ARGUMENT_TYPE argument_type) diff --git a/tests/d3d12_test_utils.h b/tests/d3d12_test_utils.h index c25449e6..eebf3206 100644 --- a/tests/d3d12_test_utils.h +++ b/tests/d3d12_test_utils.h @@ -874,6 +874,26 @@ static ID3D12PipelineState *create_pipeline_state_(unsigned int line, ID3D12Devi return SUCCEEDED(hr) ? pipeline_state : NULL; }
+#define create_compute_pipeline_state(a, b, c) create_compute_pipeline_state_(__LINE__, a, b, c) +static inline ID3D12PipelineState *create_compute_pipeline_state_(unsigned int line, ID3D12Device *device, + ID3D12RootSignature *root_signature, const D3D12_SHADER_BYTECODE cs) +{ + D3D12_COMPUTE_PIPELINE_STATE_DESC pipeline_state_desc; + ID3D12PipelineState *pipeline_state = NULL; + HRESULT hr; + + memset(&pipeline_state_desc, 0, sizeof(pipeline_state_desc)); + pipeline_state_desc.pRootSignature = root_signature; + pipeline_state_desc.CS = cs; + pipeline_state_desc.NodeMask = 0; + pipeline_state_desc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + hr = ID3D12Device_CreateComputePipelineState(device, &pipeline_state_desc, + &IID_ID3D12PipelineState, (void **)&pipeline_state); + ok_(line)(SUCCEEDED(hr), "Failed to create compute pipeline state, hr %#x.\n", hr); + + return pipeline_state; +} + struct test_context_desc { unsigned int rt_width, rt_height, rt_array_size; diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 3fb677ce..43db4d98 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -80,6 +80,7 @@ enum parse_state STATE_REQUIRE, STATE_RESOURCE, STATE_SAMPLER, + STATE_SHADER_COMPUTE, STATE_SHADER_INVALID_PIXEL, STATE_SHADER_INVALID_PIXEL_TODO, STATE_SHADER_PIXEL, @@ -371,13 +372,24 @@ static void set_uniforms(struct shader_runner *runner, size_t offset, size_t cou static void parse_test_directive(struct shader_runner *runner, const char *line) { char *rest; + int ret;
runner->is_todo = false;
if (match_string(line, "todo", &line)) runner->is_todo = true;
- if (match_string(line, "draw quad", &line)) + if (match_string(line, "dispatch", &line)) + { + unsigned int x, y, z; + + ret = sscanf(line, "%u %u %u", &x, &y, &z); + if (ret < 3) + fatal_error("Malformed dispatch arguments '%s'.\n", line); + + runner->last_render_failed = !runner->ops->dispatch(runner, x, y, z); + } + else if (match_string(line, "draw quad", &line)) { struct resource_params params; struct input_element *element; @@ -471,8 +483,8 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) unsigned int left, top, right, bottom, ulps, slot; struct resource_readback *rb; struct resource *resource; - int ret, len; RECT rect; + int len;
if (runner->last_render_failed) return; @@ -709,6 +721,14 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const free(current_resource.data); break;
+ case STATE_SHADER_COMPUTE: + free(runner->cs_source); + runner->cs_source = shader_source; + shader_source = NULL; + shader_source_len = 0; + shader_source_size = 0; + break; + case STATE_SHADER_PIXEL: free(runner->ps_source); runner->ps_source = shader_source; @@ -816,7 +836,11 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const { unsigned int index;
- if (!strcmp(line, "[require]\n")) + if (!strcmp(line, "[compute shader]\n")) + { + state = STATE_SHADER_COMPUTE; + } + else if (!strcmp(line, "[require]\n")) { state = STATE_REQUIRE; } @@ -937,6 +961,7 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const
case STATE_PREPROC: case STATE_PREPROC_INVALID: + case STATE_SHADER_COMPUTE: case STATE_SHADER_INVALID_PIXEL: case STATE_SHADER_INVALID_PIXEL_TODO: case STATE_SHADER_PIXEL: diff --git a/tests/shader_runner.h b/tests/shader_runner.h index 19a48ee8..82d7fa18 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -103,6 +103,7 @@ struct shader_runner
char *vs_source; char *ps_source; + char *cs_source; enum shader_model minimum_shader_model;
bool last_render_failed; @@ -128,6 +129,7 @@ struct shader_runner_ops 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); + bool (*dispatch)(struct shader_runner *runner, unsigned int x, unsigned int y, unsigned int z); struct resource_readback *(*get_resource_readback)(struct shader_runner *runner, struct resource *resource); void (*release_readback)(struct shader_runner *runner, struct resource_readback *rb); }; diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index 2314f6d7..d2b4807c 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -424,6 +424,91 @@ static void d3d11_runner_destroy_resource(struct shader_runner *r, struct resour free(resource); }
+static ID3D11SamplerState *create_sampler(ID3D11Device *device, const struct sampler *sampler) +{ + ID3D11SamplerState *d3d11_sampler; + D3D11_SAMPLER_DESC desc = {0}; + HRESULT hr; + + /* Members of D3D11_FILTER are compatible with D3D12_FILTER. */ + desc.Filter = (D3D11_FILTER)sampler->filter; + /* Members of D3D11_TEXTURE_ADDRESS_MODE are compatible with D3D12_TEXTURE_ADDRESS_MODE. */ + desc.AddressU = (D3D11_TEXTURE_ADDRESS_MODE)sampler->u_address; + desc.AddressV = (D3D11_TEXTURE_ADDRESS_MODE)sampler->v_address; + desc.AddressW = (D3D11_TEXTURE_ADDRESS_MODE)sampler->w_address; + desc.ComparisonFunc = D3D11_COMPARISON_NEVER; + desc.MaxLOD = D3D11_FLOAT32_MAX; + + hr = ID3D11Device_CreateSamplerState(device, &desc, &d3d11_sampler); + ok(hr == S_OK, "Failed to create sampler state, hr %#lx.\n", hr); + return d3d11_sampler; +} + +static bool d3d11_runner_dispatch(struct shader_runner *r, unsigned int x, unsigned int y, unsigned int z) +{ + struct d3d11_shader_runner *runner = d3d11_shader_runner(r); + ID3D11DeviceContext *context = runner->immediate_context; + ID3D11Device *device = runner->device; + ID3D11ComputeShader *cs; + ID3D10Blob *cs_code; + HRESULT hr; + size_t i; + + if (!(cs_code = compile_shader(runner->r.cs_source, "cs", runner->r.minimum_shader_model))) + return false; + + hr = ID3D11Device_CreateComputeShader(device, ID3D10Blob_GetBufferPointer(cs_code), + ID3D10Blob_GetBufferSize(cs_code), NULL, &cs); + ok(hr == S_OK, "Failed to create compute shader, hr %#lx.\n", hr); + + if (runner->r.uniform_count) + { + ID3D11Buffer *cb; + + cb = create_buffer(device, D3D11_BIND_CONSTANT_BUFFER, + runner->r.uniform_count * sizeof(*runner->r.uniforms), runner->r.uniforms); + ID3D11DeviceContext_CSSetConstantBuffers(context, 0, 1, &cb); + ID3D11Buffer_Release(cb); + } + + for (i = 0; i < runner->r.resource_count; ++i) + { + struct d3d11_resource *resource = d3d11_resource(runner->r.resources[i]); + + switch (resource->r.type) + { + case RESOURCE_TYPE_TEXTURE: + ID3D11DeviceContext_CSSetShaderResources(context, resource->r.slot, 1, &resource->srv); + break; + + case RESOURCE_TYPE_UAV: + ID3D11DeviceContext_CSSetUnorderedAccessViews(context, resource->r.slot, 1, &resource->uav, NULL); + break; + + case RESOURCE_TYPE_RENDER_TARGET: + case RESOURCE_TYPE_VERTEX_BUFFER: + break; + } + } + + for (i = 0; i < runner->r.sampler_count; ++i) + { + struct sampler *sampler = &runner->r.samplers[i]; + ID3D11SamplerState *d3d11_sampler; + + d3d11_sampler = create_sampler(device, sampler); + ID3D11DeviceContext_CSSetSamplers(context, sampler->slot, 1, &d3d11_sampler); + ID3D11SamplerState_Release(d3d11_sampler); + } + + ID3D11DeviceContext_CSSetShader(context, cs, NULL, 0); + ID3D11DeviceContext_Dispatch(context, x, y, z); + + ID3D11ComputeShader_Release(cs); + + return true; +} + static bool d3d11_runner_draw(struct shader_runner *r, D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count) { @@ -501,19 +586,8 @@ static bool d3d11_runner_draw(struct shader_runner *r, { struct sampler *sampler = &runner->r.samplers[i]; ID3D11SamplerState *d3d11_sampler; - D3D11_SAMPLER_DESC desc = {0}; - - /* Members of D3D11_FILTER are compatible with D3D12_FILTER. */ - desc.Filter = (D3D11_FILTER)sampler->filter; - /* Members of D3D11_TEXTURE_ADDRESS_MODE are compatible with D3D12_TEXTURE_ADDRESS_MODE. */ - desc.AddressU = (D3D11_TEXTURE_ADDRESS_MODE)sampler->u_address; - desc.AddressV = (D3D11_TEXTURE_ADDRESS_MODE)sampler->v_address; - desc.AddressW = (D3D11_TEXTURE_ADDRESS_MODE)sampler->w_address; - desc.ComparisonFunc = D3D11_COMPARISON_NEVER; - desc.MaxLOD = D3D11_FLOAT32_MAX; - - hr = ID3D11Device_CreateSamplerState(device, &desc, &d3d11_sampler); - ok(hr == S_OK, "Failed to create sampler state, hr %#lx.\n", hr); + + d3d11_sampler = create_sampler(device, sampler); ID3D11DeviceContext_PSSetSamplers(context, sampler->slot, 1, &d3d11_sampler); ID3D11SamplerState_Release(d3d11_sampler); } @@ -607,6 +681,7 @@ static const struct shader_runner_ops d3d11_runner_ops = { .create_resource = d3d11_runner_create_resource, .destroy_resource = d3d11_runner_destroy_resource, + .dispatch = d3d11_runner_dispatch, .draw = d3d11_runner_draw, .get_resource_readback = d3d11_runner_get_resource_readback, .release_readback = d3d11_runner_release_readback, diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index 871b5022..27f381ce 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -45,6 +45,10 @@ struct d3d12_shader_runner struct test_context test_context;
ID3D12DescriptorHeap *heap, *rtv_heap; + + ID3D12CommandQueue *compute_queue; + ID3D12CommandAllocator *compute_allocator; + ID3D12GraphicsCommandList *compute_list; };
static struct d3d12_shader_runner *d3d12_shader_runner(struct shader_runner *r) @@ -158,62 +162,27 @@ static void d3d12_runner_destroy_resource(struct shader_runner *r, struct resour free(resource); }
-static bool d3d12_runner_draw(struct shader_runner *r, - D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count) +static ID3D12RootSignature *d3d12_runner_create_root_signature(struct d3d12_shader_runner *runner, + ID3D12CommandQueue *queue, ID3D12CommandAllocator *allocator, + ID3D12GraphicsCommandList *command_list, unsigned int *uniform_index) { - struct d3d12_shader_runner *runner = d3d12_shader_runner(r); - struct test_context *test_context = &runner->test_context; - - D3D12_CPU_DESCRIPTOR_HANDLE rtvs[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; - ID3D12GraphicsCommandList *command_list = test_context->list; D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {0}; - D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = {0}; D3D12_ROOT_PARAMETER root_params[3], *root_param; - ID3D12CommandQueue *queue = test_context->queue; - D3D12_INPUT_ELEMENT_DESC *input_element_descs; D3D12_STATIC_SAMPLER_DESC static_samplers[1]; - ID3D12Device *device = test_context->device; - static const float clear_color[4]; - unsigned int uniform_index = 0; - ID3D10Blob *vs_code, *ps_code; - unsigned int rtv_count = 0; - ID3D12PipelineState *pso; + ID3D12RootSignature *root_signature; HRESULT hr; size_t i;
- ps_code = compile_shader(runner, runner->r.ps_source, "ps"); - vs_code = compile_shader(runner, runner->r.vs_source, "vs"); - todo_if (runner->r.is_todo) ok(ps_code && vs_code, "Failed to compile shaders.\n"); - - if (!ps_code || !vs_code) - { - if (ps_code) - ID3D10Blob_Release(ps_code); - if (vs_code) - ID3D10Blob_Release(vs_code); - return false; - } - root_signature_desc.NumParameters = 0; root_signature_desc.pParameters = root_params; root_signature_desc.NumStaticSamplers = 0; root_signature_desc.pStaticSamplers = static_samplers; root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
- pso_desc.VS.pShaderBytecode = ID3D10Blob_GetBufferPointer(vs_code); - pso_desc.VS.BytecodeLength = ID3D10Blob_GetBufferSize(vs_code); - pso_desc.PS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ps_code); - pso_desc.PS.BytecodeLength = ID3D10Blob_GetBufferSize(ps_code); - pso_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; - pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK; - pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - pso_desc.SampleDesc.Count = 1; - pso_desc.SampleMask = ~(UINT)0; - if (runner->r.uniform_count) { - uniform_index = root_signature_desc.NumParameters++; - root_param = &root_params[uniform_index]; + *uniform_index = root_signature_desc.NumParameters++; + root_param = &root_params[*uniform_index]; root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; root_param->Constants.ShaderRegister = 0; root_param->Constants.RegisterSpace = 0; @@ -250,11 +219,6 @@ static bool d3d12_runner_draw(struct shader_runner *r, break;
case RESOURCE_TYPE_RENDER_TARGET: - pso_desc.RTVFormats[resource->r.slot] = resource->r.format; - pso_desc.NumRenderTargets = max(pso_desc.NumRenderTargets, resource->r.slot + 1); - pso_desc.BlendState.RenderTarget[resource->r.slot].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; - break; - case RESOURCE_TYPE_VERTEX_BUFFER: break; } @@ -277,11 +241,150 @@ static bool d3d12_runner_draw(struct shader_runner *r, sampler_desc->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; }
+ hr = create_root_signature(runner->test_context.device, &root_signature_desc, &root_signature); + ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); + return root_signature; +} + +static void add_pso(struct test_context *test_context, ID3D12PipelineState *pso) +{ + vkd3d_array_reserve((void **)&test_context->pso, &test_context->pso_capacity, + test_context->pso_count + 1, sizeof(*test_context->pso)); + test_context->pso[test_context->pso_count++] = pso; +} + +static bool d3d12_runner_dispatch(struct shader_runner *r, unsigned int x, unsigned int y, unsigned int z) +{ + struct d3d12_shader_runner *runner = d3d12_shader_runner(r); + struct test_context *test_context = &runner->test_context; + + ID3D12GraphicsCommandList *command_list = runner->compute_list; + ID3D12CommandAllocator *allocator = runner->compute_allocator; + ID3D12CommandQueue *queue = runner->compute_queue; + ID3D12Device *device = test_context->device; + ID3D12RootSignature *root_signature; + unsigned int uniform_index; + ID3D12PipelineState *pso; + D3D12_SHADER_BYTECODE cs; + ID3D10Blob *cs_code; + HRESULT hr; + size_t i; + + cs_code = compile_shader(runner, runner->r.cs_source, "cs"); + todo_if (runner->r.is_todo) ok(cs_code, "Failed to compile shader.\n"); + if (!cs_code) + return false; + + root_signature = d3d12_runner_create_root_signature(runner, queue, allocator, command_list, &uniform_index); + + cs.pShaderBytecode = ID3D10Blob_GetBufferPointer(cs_code); + cs.BytecodeLength = ID3D10Blob_GetBufferSize(cs_code); + pso = create_compute_pipeline_state(device, root_signature, cs); + ID3D10Blob_Release(cs_code); + add_pso(test_context, pso); + + ID3D12GraphicsCommandList_SetComputeRootSignature(command_list, root_signature); + if (runner->r.uniform_count) + ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(command_list, uniform_index, + runner->r.uniform_count, runner->r.uniforms, 0); + for (i = 0; i < runner->r.resource_count; ++i) + { + struct d3d12_resource *resource = d3d12_resource(runner->r.resources[i]); + + switch (resource->r.type) + { + case RESOURCE_TYPE_TEXTURE: + ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, resource->root_index, + get_gpu_descriptor_handle(test_context, runner->heap, resource->r.slot)); + break; + + case RESOURCE_TYPE_UAV: + // fixme zf: un-magic + ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, resource->root_index, + get_gpu_descriptor_handle(test_context, runner->heap, resource->r.slot + 32)); + break; + + case RESOURCE_TYPE_RENDER_TARGET: + case RESOURCE_TYPE_VERTEX_BUFFER: + break; + } + } + + ID3D12GraphicsCommandList_SetPipelineState(command_list, pso); + ID3D12GraphicsCommandList_Dispatch(command_list, x, y, z); + ID3D12RootSignature_Release(root_signature); + + /* Finish the command list so that we can destroy objects. + * Also, subsequent UAV probes will use the graphics command list, so make + * sure that the above barriers are actually executed. */ + hr = ID3D12GraphicsCommandList_Close(command_list); + ok(hr == S_OK, "Failed to close command list, hr %#x.\n", hr); + exec_command_list(queue, command_list); + wait_queue_idle(device, queue); + reset_command_list(command_list, allocator); + + return true; +} + +static bool d3d12_runner_draw(struct shader_runner *r, + D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count) +{ + struct d3d12_shader_runner *runner = d3d12_shader_runner(r); + struct test_context *test_context = &runner->test_context; + + D3D12_CPU_DESCRIPTOR_HANDLE rtvs[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; + ID3D12GraphicsCommandList *command_list = test_context->list; + D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = {0}; + ID3D12CommandQueue *queue = test_context->queue; + D3D12_INPUT_ELEMENT_DESC *input_element_descs; + ID3D12Device *device = test_context->device; + static const float clear_color[4]; + ID3D10Blob *vs_code, *ps_code; + unsigned int uniform_index; + unsigned int rtv_count = 0; + ID3D12PipelineState *pso; + HRESULT hr; + size_t i; + + ps_code = compile_shader(runner, runner->r.ps_source, "ps"); + vs_code = compile_shader(runner, runner->r.vs_source, "vs"); + todo_if (runner->r.is_todo) ok(ps_code && vs_code, "Failed to compile shaders.\n"); + + if (!ps_code || !vs_code) + { + if (ps_code) + ID3D10Blob_Release(ps_code); + if (vs_code) + ID3D10Blob_Release(vs_code); + return false; + } + if (test_context->root_signature) ID3D12RootSignature_Release(test_context->root_signature); - hr = create_root_signature(device, &root_signature_desc, &test_context->root_signature); - ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); + test_context->root_signature = d3d12_runner_create_root_signature(runner, + queue, test_context->allocator, command_list, &uniform_index);
+ for (i = 0; i < runner->r.resource_count; ++i) + { + struct d3d12_resource *resource = d3d12_resource(runner->r.resources[i]); + + if (resource->r.type == RESOURCE_TYPE_RENDER_TARGET) + { + pso_desc.RTVFormats[resource->r.slot] = resource->r.format; + pso_desc.NumRenderTargets = max(pso_desc.NumRenderTargets, resource->r.slot + 1); + pso_desc.BlendState.RenderTarget[resource->r.slot].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + } + } + + pso_desc.VS.pShaderBytecode = ID3D10Blob_GetBufferPointer(vs_code); + pso_desc.VS.BytecodeLength = ID3D10Blob_GetBufferSize(vs_code); + pso_desc.PS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ps_code); + pso_desc.PS.BytecodeLength = ID3D10Blob_GetBufferSize(ps_code); + pso_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; + pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK; + pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + pso_desc.SampleDesc.Count = 1; + pso_desc.SampleMask = ~(UINT)0; pso_desc.pRootSignature = test_context->root_signature;
input_element_descs = calloc(runner->r.input_element_count, sizeof(*input_element_descs)); @@ -307,9 +410,7 @@ static bool d3d12_runner_draw(struct shader_runner *r, ID3D10Blob_Release(vs_code); ID3D10Blob_Release(ps_code); free(input_element_descs); - vkd3d_array_reserve((void **)&test_context->pso, &test_context->pso_capacity, - test_context->pso_count + 1, sizeof(*test_context->pso)); - test_context->pso[test_context->pso_count++] = pso; + add_pso(test_context, pso);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, test_context->root_signature); if (runner->r.uniform_count) @@ -403,6 +504,7 @@ static const struct shader_runner_ops d3d12_runner_ops = { .create_resource = d3d12_runner_create_resource, .destroy_resource = d3d12_runner_destroy_resource, + .dispatch = d3d12_runner_dispatch, .draw = d3d12_runner_draw, .get_resource_readback = d3d12_runner_get_resource_readback, .release_readback = d3d12_runner_release_readback, @@ -418,14 +520,31 @@ void run_shader_tests_d3d12(int argc, char **argv) .rt_format = DXGI_FORMAT_R32G32B32A32_FLOAT, }; struct d3d12_shader_runner runner = {0}; + ID3D12Device *device; + HRESULT hr;
parse_args(argc, argv); enable_d3d12_debug_layer(argc, argv); init_adapter_info(); init_test_context(&runner.test_context, &desc); + device = runner.test_context.device; + + runner.compute_queue = create_command_queue(device, + D3D12_COMMAND_LIST_TYPE_COMPUTE, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL); + + hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_COMPUTE, + &IID_ID3D12CommandAllocator, (void **)&runner.compute_allocator); + ok(hr == S_OK, "Failed to create command allocator, hr %#x.\n", hr); + + hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_COMPUTE, + runner.compute_allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)&runner.compute_list); + ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr);
run_shader_tests(&runner.r, argc, argv, &d3d12_runner_ops);
+ ID3D12GraphicsCommandList_Release(runner.compute_list); + ID3D12CommandAllocator_Release(runner.compute_allocator); + ID3D12CommandQueue_Release(runner.compute_queue); if (runner.heap) ID3D12DescriptorHeap_Release(runner.heap); if (runner.rtv_heap) diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index 19044126..39dbd787 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -512,7 +512,7 @@ static VkPipelineLayout create_pipeline_layout(const struct vulkan_shader_runner return pipeline_layout; }
-static VkPipeline create_pipeline(const struct vulkan_shader_runner *runner, VkRenderPass render_pass, +static VkPipeline create_graphics_pipeline(const struct vulkan_shader_runner *runner, VkRenderPass render_pass, VkPipelineLayout pipeline_layout, D3D_PRIMITIVE_TOPOLOGY primitive_topology) { VkPipelineInputAssemblyStateCreateInfo ia_desc = {.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; @@ -644,6 +644,27 @@ static VkPipeline create_pipeline(const struct vulkan_shader_runner *runner, VkR return pipeline; }
+static VkPipeline create_compute_pipeline(const struct vulkan_shader_runner *runner, VkPipelineLayout pipeline_layout) +{ + VkComputePipelineCreateInfo pipeline_desc = {.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; + VkPipeline pipeline; + bool ret; + + ret = create_shader_stage(runner, &pipeline_desc.stage, "cs", + VK_SHADER_STAGE_COMPUTE_BIT, runner->r.cs_source, NULL); + todo_if (runner->r.is_todo) ok(ret, "Failed to compile shader.\n"); + if (!ret) + return VK_NULL_HANDLE; + + pipeline_desc.layout = pipeline_layout; + + VK_CALL(vkCreateComputePipelines(runner->device, VK_NULL_HANDLE, 1, &pipeline_desc, NULL, &pipeline)); + + VK_CALL(vkDestroyShaderModule(runner->device, pipeline_desc.stage.module, NULL)); + + return pipeline; +} + static VkSamplerAddressMode vk_address_mode_from_d3d12(D3D12_TEXTURE_ADDRESS_MODE mode) { switch (mode) @@ -856,6 +877,49 @@ static void create_render_pass_and_framebuffer(struct vulkan_shader_runner *runn VK_CALL(vkCreateFramebuffer(runner->device, &fb_desc, NULL, fb)); }
+static bool vulkan_runner_dispatch(struct shader_runner *r, unsigned int x, unsigned int y, unsigned int z) +{ + struct vulkan_shader_runner *runner = vulkan_shader_runner(r); + + VkCommandBuffer cmd_buffer = runner->cmd_buffer; + VkDescriptorSetLayout set_layout; + VkPipelineLayout pipeline_layout; + VkDevice device = runner->device; + VkPipeline pipeline; + bool ret = false; + unsigned int i; + + /* Create this before compiling shaders, it will assign resource bindings. */ + set_layout = create_descriptor_set_layout(runner); + + pipeline_layout = create_pipeline_layout(runner, set_layout); + if (!(pipeline = create_compute_pipeline(runner, pipeline_layout))) + goto out; + + begin_command_buffer(runner); + + VK_CALL(vkCmdBindPipeline(cmd_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline)); + + bind_resources(runner, VK_PIPELINE_BIND_POINT_COMPUTE, set_layout, pipeline_layout); + + VK_CALL(vkCmdDispatch(cmd_buffer, x, y, z)); + + end_command_buffer(runner); + + VK_CALL(vkDestroyPipeline(device, pipeline, NULL)); + VK_CALL(vkResetDescriptorPool(device, runner->descriptor_pool, 0)); + + ret = true; +out: + for (i = 0; i < runner->r.sampler_count; ++i) + VK_CALL(vkDestroySampler(device, runner->samplers[i].vk_sampler, NULL)); + + VK_CALL(vkDestroyPipelineLayout(device, pipeline_layout, NULL)); + VK_CALL(vkDestroyDescriptorSetLayout(device, set_layout, NULL)); + + return ret; +} + static bool vulkan_runner_draw(struct shader_runner *r, D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count) { @@ -872,7 +936,7 @@ static bool vulkan_runner_draw(struct shader_runner *r, VkClearRect clear_rect; VkPipeline pipeline; VkFramebuffer fb; - bool ret = true; + bool ret = false; unsigned int i;
create_render_pass_and_framebuffer(runner, &render_pass, &fb); @@ -881,11 +945,8 @@ static bool vulkan_runner_draw(struct shader_runner *r, set_layout = create_descriptor_set_layout(runner);
pipeline_layout = create_pipeline_layout(runner, set_layout); - if (!(pipeline = create_pipeline(runner, render_pass, pipeline_layout, primitive_topology))) - { - ret = false; + if (!(pipeline = create_graphics_pipeline(runner, render_pass, pipeline_layout, primitive_topology))) goto out; - }
begin_command_buffer(runner);
@@ -917,6 +978,7 @@ static bool vulkan_runner_draw(struct shader_runner *r, VK_CALL(vkDestroyPipeline(device, pipeline, NULL)); VK_CALL(vkResetDescriptorPool(device, runner->descriptor_pool, 0));
+ ret = true; out: for (i = 0; i < runner->r.sampler_count; ++i) VK_CALL(vkDestroySampler(device, runner->samplers[i].vk_sampler, NULL)); @@ -997,6 +1059,7 @@ static const struct shader_runner_ops vulkan_runner_ops = { .create_resource = vulkan_runner_create_resource, .destroy_resource = vulkan_runner_destroy_resource, + .dispatch = vulkan_runner_dispatch, .draw = vulkan_runner_draw, .get_resource_readback = vulkan_runner_get_resource_readback, .release_readback = vulkan_runner_release_readback, diff --git a/tests/vulkan_procs.h b/tests/vulkan_procs.h index 8e205c1b..9d70b499 100644 --- a/tests/vulkan_procs.h +++ b/tests/vulkan_procs.h @@ -58,6 +58,7 @@ VK_DEVICE_PFN(vkCmdBindVertexBuffers) VK_DEVICE_PFN(vkCmdClearAttachments) VK_DEVICE_PFN(vkCmdCopyBufferToImage) VK_DEVICE_PFN(vkCmdCopyImageToBuffer) +VK_DEVICE_PFN(vkCmdDispatch) VK_DEVICE_PFN(vkCmdDraw) VK_DEVICE_PFN(vkCmdEndRenderPass) VK_DEVICE_PFN(vkCmdFillBuffer) @@ -65,6 +66,7 @@ VK_DEVICE_PFN(vkCmdPipelineBarrier) VK_DEVICE_PFN(vkCmdPushConstants) VK_DEVICE_PFN(vkCreateBuffer) VK_DEVICE_PFN(vkCreateCommandPool) +VK_DEVICE_PFN(vkCreateComputePipelines) VK_DEVICE_PFN(vkCreateDescriptorPool) VK_DEVICE_PFN(vkCreateDescriptorSetLayout) VK_DEVICE_PFN(vkCreateFramebuffer)
From: Zebediah Figura zfigura@codeweavers.com
--- Makefile.am | 1 + tests/uav-load.shader_test | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/uav-load.shader_test
diff --git a/Makefile.am b/Makefile.am index 3e69c28a..b35524c9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -142,6 +142,7 @@ vkd3d_shader_tests = \ tests/texture-load-typed.shader_test \ tests/trigonometry.shader_test \ tests/uav.shader_test \ + tests/uav-load.shader_test \ tests/writemask-assignop-0.shader_test \ tests/writemask-assignop-1.shader_test \ tests/writemask-assignop-2.shader_test \ diff --git a/tests/uav-load.shader_test b/tests/uav-load.shader_test new file mode 100644 index 00000000..2664a99f --- /dev/null +++ b/tests/uav-load.shader_test @@ -0,0 +1,31 @@ +[require] +shader model >= 5.0 + +[uav 0] +format r32 float +size (3, 1) + +0.1 0.1 0.1 + +[uav 1] +format r32 float +size (1, 1) + +0.5 + +[compute shader] +RWTexture2D<float> u, v; + [numthreads(1, 1, 1)] +void main() +{ + uint2 pos = uint2(0, 0); + u[uint2(1, 0)] = (u[uint2(0, 0)] += v[uint2(0, 0)]); + u[uint2(2, 0)] = u[uint2(0, 0)]; +} + +[test] +todo dispatch 1 1 1 +probe uav 0 (0, 0) r (0.6) +probe uav 0 (1, 0) r (0.6) +probe uav 0 (2, 0) r (0.6) +probe uav 1 (0, 0) r (0.5)
From: Zebediah Figura zfigura@codeweavers.com
Mostly in the interest of keeping the yacc code as simple as possible. --- libs/vkd3d-shader/hlsl.y | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 60ca09ce..4daf5e4f 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -748,23 +748,35 @@ static bool add_matrix_index(struct hlsl_ctx *ctx, struct list *instrs, }
static bool add_array_load(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *array, - struct hlsl_ir_node *index, const struct vkd3d_shader_location loc) + struct hlsl_ir_node *index, const struct vkd3d_shader_location *loc) { const struct hlsl_type *expr_type = array->data_type; + struct hlsl_ir_expr *cast; + + if (index->data_type->type != HLSL_CLASS_SCALAR) + { + hlsl_error(ctx, &index->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Array index is not scalar."); + return false; + } + + if (!(cast = hlsl_new_cast(ctx, index, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), &index->loc))) + return false; + list_add_tail(instrs, &cast->node.entry); + index = &cast->node;
if (expr_type->type == HLSL_CLASS_MATRIX) - return add_matrix_index(ctx, instrs, array, index, &loc); + return add_matrix_index(ctx, instrs, array, index, loc);
if (expr_type->type != HLSL_CLASS_ARRAY && expr_type->type != HLSL_CLASS_VECTOR) { if (expr_type->type == HLSL_CLASS_SCALAR) - hlsl_error(ctx, &loc, VKD3D_SHADER_ERROR_HLSL_INVALID_INDEX, "Scalar expressions cannot be array-indexed."); + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_INDEX, "Scalar expressions cannot be array-indexed."); else - hlsl_error(ctx, &loc, VKD3D_SHADER_ERROR_HLSL_INVALID_INDEX, "Expression cannot be array-indexed."); + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_INDEX, "Expression cannot be array-indexed."); return false; }
- if (!add_load_index(ctx, instrs, array, index, &loc)) + if (!add_load_index(ctx, instrs, array, index, loc)) return false;
return true; @@ -4185,26 +4197,11 @@ postfix_expr: | postfix_expr '[' expr ']' { struct hlsl_ir_node *array = node_from_list($1), *index = node_from_list($3); - struct hlsl_ir_expr *cast;
list_move_tail($1, $3); vkd3d_free($3);
- if (index->data_type->type != HLSL_CLASS_SCALAR) - { - hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Array index is not scalar."); - destroy_instr_list($1); - YYABORT; - } - - if (!(cast = hlsl_new_cast(ctx, index, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), &index->loc))) - { - destroy_instr_list($1); - YYABORT; - } - list_add_tail($1, &cast->node.entry); - - if (!add_array_load(ctx, $1, array, &cast->node, @2)) + if (!add_array_load(ctx, $1, array, index, &@2)) { destroy_instr_list($1); YYABORT;
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/hlsl.y | 74 +++++++++++++++++++++++++++++++++- tests/texture-load.shader_test | 15 +++++++ 2 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 4daf5e4f..986738e0 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -747,13 +747,83 @@ static bool add_matrix_index(struct hlsl_ctx *ctx, struct list *instrs, return true; }
+static struct hlsl_ir_node *add_zero_mipmap_level(struct hlsl_ctx *ctx, struct list *instrs, + struct hlsl_ir_node *index, unsigned int dim_count, const struct vkd3d_shader_location *loc) +{ + struct hlsl_ir_load *coords_load; + struct hlsl_deref coords_deref; + struct hlsl_ir_constant *zero; + struct hlsl_ir_store *store; + struct hlsl_ir_var *coords; + + if (!(coords = hlsl_new_synthetic_var(ctx, "coords", + hlsl_get_vector_type(ctx, HLSL_TYPE_UINT, dim_count + 1), loc))) + return NULL; + + hlsl_init_simple_deref_from_var(&coords_deref, coords); + if (!(store = hlsl_new_store_index(ctx, &coords_deref, NULL, index, (1u << dim_count) - 1, loc))) + return NULL; + list_add_tail(instrs, &store->node.entry); + + if (!(zero = hlsl_new_uint_constant(ctx, 0, loc))) + return NULL; + list_add_tail(instrs, &zero->node.entry); + + if (!(store = hlsl_new_store_index(ctx, &coords_deref, NULL, &zero->node, 1u << dim_count, loc))) + return NULL; + list_add_tail(instrs, &store->node.entry); + + if (!(coords_load = hlsl_new_var_load(ctx, coords, *loc))) + return NULL; + list_add_tail(instrs, &coords_load->node.entry); + + return &coords_load->node; +} + static bool add_array_load(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *array, struct hlsl_ir_node *index, const struct vkd3d_shader_location *loc) { - const struct hlsl_type *expr_type = array->data_type; + const struct hlsl_type *expr_type = array->data_type, *index_type = index->data_type; struct hlsl_ir_expr *cast;
- if (index->data_type->type != HLSL_CLASS_SCALAR) + if (expr_type->type == HLSL_CLASS_OBJECT && expr_type->base_type == HLSL_TYPE_TEXTURE + && expr_type->sampler_dim != HLSL_SAMPLER_DIM_GENERIC) + { + struct hlsl_resource_load_params load_params = {.type = HLSL_RESOURCE_LOAD}; + unsigned int dim_count = hlsl_sampler_dim_count(expr_type->sampler_dim); + /* Only HLSL_IR_LOAD can return an object. */ + struct hlsl_ir_load *object_load = hlsl_ir_load(array); + struct hlsl_ir_resource_load *resource_load; + + if (index_type->type > HLSL_CLASS_VECTOR || index_type->dimx != dim_count) + { + struct vkd3d_string_buffer *string; + + if ((string = hlsl_type_to_string(ctx, expr_type))) + hlsl_error(ctx, &index->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "Array index of type '%s' must be of type 'uint%u'.", string->buffer, dim_count); + hlsl_release_string_buffer(ctx, string); + return false; + } + + if (!(index = add_implicit_conversion(ctx, instrs, index, + hlsl_get_vector_type(ctx, HLSL_TYPE_UINT, dim_count), &index->loc))) + return false; + + if (!(index = add_zero_mipmap_level(ctx, instrs, index, dim_count, loc))) + return false; + + load_params.format = expr_type->e.resource_format; + load_params.resource = object_load->src; + load_params.coords = index; + + if (!(resource_load = hlsl_new_resource_load(ctx, &load_params, loc))) + return false; + list_add_tail(instrs, &resource_load->node.entry); + return true; + } + + if (index_type->type != HLSL_CLASS_SCALAR) { hlsl_error(ctx, &index->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, "Array index is not scalar."); return false; diff --git a/tests/texture-load.shader_test b/tests/texture-load.shader_test index 81d06305..7d39fb65 100644 --- a/tests/texture-load.shader_test +++ b/tests/texture-load.shader_test @@ -20,3 +20,18 @@ probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4) probe (1, 0) rgba (0.5, 0.7, 0.6, 0.8) probe (0, 1) rgba (0.6, 0.5, 0.2, 0.1) probe (1, 1) rgba (0.8, 0.0, 0.7, 1.0) + +[pixel shader] +Texture2D t; + +float4 main(float4 pos : sv_position) : sv_target +{ + return t[pos.yx]; +} + +[test] +draw quad +probe (0, 0) rgba (0.1, 0.2, 0.3, 0.4) +probe (1, 0) rgba (0.6, 0.5, 0.2, 0.1) +probe (0, 1) rgba (0.5, 0.7, 0.6, 0.8) +probe (1, 1) rgba (0.8, 0.0, 0.7, 1.0)
From: Zebediah Figura zfigura@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 25 ++++++++++++++++++++++++- libs/vkd3d-shader/hlsl.h | 2 ++ libs/vkd3d-shader/hlsl.l | 3 +++ libs/vkd3d-shader/hlsl.y | 33 ++++++++++++++++++++++++++++++++- libs/vkd3d-shader/hlsl_sm4.c | 2 ++ 5 files changed, 63 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 3edbb978..8591fe31 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -525,6 +525,23 @@ struct hlsl_type *hlsl_new_texture_type(struct hlsl_ctx *ctx, enum hlsl_sampler_ return type; }
+struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format) +{ + struct hlsl_type *type; + + if (!(type = vkd3d_calloc(1, sizeof(*type)))) + return NULL; + type->type = HLSL_CLASS_OBJECT; + type->base_type = HLSL_TYPE_UAV; + type->dimx = format->dimx; + type->dimy = 1; + type->sampler_dim = dim; + type->e.resource_format = format; + hlsl_type_calculate_reg_size(ctx, type); + list_add_tail(&ctx->types, &type->entry); + return type; +} + struct hlsl_type *hlsl_get_type(struct hlsl_scope *scope, const char *name, bool recursive) { struct rb_entry *entry = rb_get(&scope->types, name); @@ -596,7 +613,8 @@ bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2 return false; if (t1->base_type != t2->base_type) return false; - if (t1->base_type == HLSL_TYPE_SAMPLER || t1->base_type == HLSL_TYPE_TEXTURE) + if (t1->base_type == HLSL_TYPE_SAMPLER || t1->base_type == HLSL_TYPE_TEXTURE + || t1->base_type == HLSL_TYPE_UAV) { if (t1->sampler_dim != t2->sampler_dim) return false; @@ -1411,6 +1429,11 @@ struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const stru base_types[type->e.resource_format->base_type], type->e.resource_format->dimx); return string;
+ case HLSL_TYPE_UAV: + vkd3d_string_buffer_printf(string, "RWTexture%s<%s%u>", dimensions[type->sampler_dim], + base_types[type->e.resource_format->base_type], type->e.resource_format->dimx); + return string; + default: vkd3d_string_buffer_printf(string, "<unexpected type>"); return string; diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index e8f01f2b..f237d6c4 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -85,6 +85,7 @@ enum hlsl_base_type HLSL_TYPE_LAST_SCALAR = HLSL_TYPE_BOOL, HLSL_TYPE_SAMPLER, HLSL_TYPE_TEXTURE, + HLSL_TYPE_UAV, HLSL_TYPE_PIXELSHADER, HLSL_TYPE_VERTEXSHADER, HLSL_TYPE_STRING, @@ -787,6 +788,7 @@ struct hlsl_ir_swizzle *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *template, struct hlsl_type *type, const struct vkd3d_shader_location *loc); struct hlsl_type *hlsl_new_texture_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format); +struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format); struct hlsl_ir_constant *hlsl_new_uint_constant(struct hlsl_ctx *ctx, unsigned int n, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *hlsl_new_unary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg, diff --git a/libs/vkd3d-shader/hlsl.l b/libs/vkd3d-shader/hlsl.l index ff7b712f..69ed9d9d 100644 --- a/libs/vkd3d-shader/hlsl.l +++ b/libs/vkd3d-shader/hlsl.l @@ -102,6 +102,9 @@ RasterizerState {return KW_RASTERIZERSTATE; } RenderTargetView {return KW_RENDERTARGETVIEW; } return {return KW_RETURN; } register {return KW_REGISTER; } +RWTexture1D {return KW_RWTEXTURE1D; } +RWTexture2D {return KW_RWTEXTURE2D; } +RWTexture3D {return KW_RWTEXTURE3D; } sampler {return KW_SAMPLER; } sampler1D {return KW_SAMPLER1D; } sampler2D {return KW_SAMPLER2D; } diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 986738e0..1082837c 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -3007,6 +3007,9 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl %token KW_RETURN %token KW_REGISTER %token KW_ROW_MAJOR +%token KW_RWTEXTURE1D +%token KW_RWTEXTURE2D +%token KW_RWTEXTURE3D %token KW_SAMPLER %token KW_SAMPLER1D %token KW_SAMPLER2D @@ -3144,7 +3147,7 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl
%type <reg_reservation> register_opt
-%type <sampler_dim> texture_type +%type <sampler_dim> texture_type uav_type
%type <semantic> semantic
@@ -3568,6 +3571,20 @@ texture_type: $$ = HLSL_SAMPLER_DIM_CUBEARRAY; }
+uav_type: + KW_RWTEXTURE1D + { + $$ = HLSL_SAMPLER_DIM_1D; + } + | KW_RWTEXTURE2D + { + $$ = HLSL_SAMPLER_DIM_2D; + } + | KW_RWTEXTURE3D + { + $$ = HLSL_SAMPLER_DIM_3D; + } + type: KW_VECTOR '<' type ',' C_INTEGER '>' { @@ -3673,6 +3690,20 @@ type: } $$ = hlsl_new_texture_type(ctx, $1, $3); } + | uav_type '<' type '>' + { + if ($3->type > HLSL_CLASS_VECTOR) + { + struct vkd3d_string_buffer *string; + + string = hlsl_type_to_string(ctx, $3); + if (string) + hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "UAV data type %s is not scalar or vector.", string->buffer); + hlsl_release_string_buffer(ctx, string); + } + $$ = hlsl_new_uav_type(ctx, $1, $3); + } | TYPE_IDENTIFIER { $$ = hlsl_get_type(ctx->cur_scope, $1, true); diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c index b6d5e92c..b10c537a 100644 --- a/libs/vkd3d-shader/hlsl_sm4.c +++ b/libs/vkd3d-shader/hlsl_sm4.c @@ -410,6 +410,8 @@ static D3D_SHADER_INPUT_TYPE sm4_resource_type(const struct hlsl_type *type) return D3D_SIT_SAMPLER; case HLSL_TYPE_TEXTURE: return D3D_SIT_TEXTURE; + case HLSL_TYPE_UAV: + return D3D_SIT_UAV_RWTYPED; default: vkd3d_unreachable(); }
Giovanni Mascellani (@giomasce) commented about tests/shader_runner.c:
runner->is_todo = false; if (match_string(line, "todo", &line)) runner->is_todo = true;
- if (match_string(line, "draw quad", &line))
- if (match_string(line, "dispatch", &line))
- {
unsigned int x, y, z;
ret = sscanf(line, "%u %u %u", &x, &y, &z);
if (ret < 3)
fatal_error("Malformed dispatch arguments '%s'.\n", line);
runner->last_render_failed = !runner->ops->dispatch(runner, x, y, z);
This segfaults if somebody tries to run a compute shader on D3D9. Maybe we would like to error out properly instead?
Giovanni Mascellani (@giomasce) commented about tests/shader_runner_d3d12.c:
runner->r.uniform_count, runner->r.uniforms, 0);
- for (i = 0; i < runner->r.resource_count; ++i)
- {
struct d3d12_resource *resource = d3d12_resource(runner->r.resources[i]);
switch (resource->r.type)
{
case RESOURCE_TYPE_TEXTURE:
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, resource->root_index,
get_gpu_descriptor_handle(test_context, runner->heap, resource->r.slot));
break;
case RESOURCE_TYPE_UAV:
// fixme zf: un-magic
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, resource->root_index,
get_gpu_descriptor_handle(test_context, runner->heap, resource->r.slot + 32));
Your magic is indeed powerful, but please use `MAX_RESOURCES`.
Giovanni Mascellani (@giomasce) commented about tests/uav-load.shader_test:
+size (3, 1)
+0.1 0.1 0.1
+[uav 1] +format r32 float +size (1, 1)
+0.5
+[compute shader] +RWTexture2D<float> u, v;
- [numthreads(1, 1, 1)]
+void main() +{
- uint2 pos = uint2(0, 0);
I guess this line is useless?
Giovanni Mascellani (@giomasce) commented about tests/uav-load.shader_test:
+[require] +shader model >= 5.0
+[uav 0] +format r32 float +size (3, 1)
+0.1 0.1 0.1
Not a big deal, but usually I try to make tests with inputs and outputs that are as diverse as possible. For example, here I would have written something like `0.1 0.2 0.3`, so that if for some bug loads to (0, 0) actually read from (2, 0) the bug is more likely to get caught.
On Mon Oct 17 10:54:02 2022 +0000, Giovanni Mascellani wrote:
This segfaults if somebody tries to run a compute shader on D3D9. Maybe we would like to error out properly instead?
I haven't necessarily been putting too much effort into error handling in the shader runners, but sure.
On Mon Oct 17 13:10:35 2022 +0000, Giovanni Mascellani wrote:
I guess this line is useless?
Yes.
On Mon Oct 17 13:10:36 2022 +0000, Giovanni Mascellani wrote:
Not a big deal, but usually I try to make tests with inputs and outputs that are as diverse as possible. For example, here I would have written something like `0.1 0.2 0.3`, so that if for some bug loads to (0, 0) actually read from (2, 0) the bug is more likely to get caught.
Sure.
On Mon Oct 17 10:58:54 2022 +0000, Giovanni Mascellani wrote:
Your magic is indeed powerful, but please use `MAX_RESOURCES`.
So much for those comments, clearly they don't work...