diff --git a/Makefile.am b/Makefile.am index 5a5a01c4..66a93ab4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,6 +65,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 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..bb4d9c5a 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,149 @@ 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: + ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, resource->root_index, + get_gpu_descriptor_handle(test_context, runner->heap, resource->r.slot + MAX_RESOURCES)); + 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 +409,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 +503,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 +519,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_d3d9.c b/tests/shader_runner_d3d9.c index a56f39be..e425da1b 100644 --- a/tests/shader_runner_d3d9.c +++ b/tests/shader_runner_d3d9.c @@ -304,6 +304,11 @@ static D3DDECLUSAGE vertex_decl_usage_from_name(const char *name) fatal_error("Cannot translate usage \"%s\" to a d3d9 usage.\n", name); } +static bool d3d9_runner_dispatch(struct shader_runner *r, unsigned int x, unsigned int y, unsigned int z) +{ + fatal_error("Compute shaders are not supported.\n"); +} + static bool d3d9_runner_draw(struct shader_runner *r, D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count) { @@ -504,6 +509,7 @@ static const struct shader_runner_ops d3d9_runner_ops = .check_requirements = d3d9_runner_check_requirements, .create_resource = d3d9_runner_create_resource, .destroy_resource = d3d9_runner_destroy_resource, + .dispatch = d3d9_runner_dispatch, .draw = d3d9_runner_draw, .get_resource_readback = d3d9_runner_get_resource_readback, .release_readback = d3d9_runner_release_readback, 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)