From 00b0b8d65cc61eee4ba51c3ec479e267ad65b92c Mon Sep 17 00:00:00 2001 From: Conor McCarthy Date: Fri, 19 Apr 2024 12:33:56 +1000 Subject: [PATCH] tests/hlsl: Add a geometry shader test. --- Makefile.am | 1 + tests/hlsl/geometry.shader_test | 67 +++++++++++++++++++++++++++++++++ tests/shader_runner.c | 32 ++++++++++++++++ tests/shader_runner.h | 2 + tests/shader_runner_d3d11.c | 24 +++++++++++- tests/shader_runner_d3d12.c | 43 +++++++++++++++++++-- tests/shader_runner_gl.c | 11 +++++- tests/shader_runner_vulkan.c | 7 +++- 8 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 tests/hlsl/geometry.shader_test diff --git a/Makefile.am b/Makefile.am index d4b1619e..558938c5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -117,6 +117,7 @@ vkd3d_shader_tests = \ tests/hlsl/fxgroup-syntax.shader_test \ tests/hlsl/gather-offset.shader_test \ tests/hlsl/gather.shader_test \ + tests/hlsl/geometry.shader_test \ tests/hlsl/get-sample-pos.shader_test \ tests/hlsl/getdimensions.shader_test \ tests/hlsl/half.shader_test \ diff --git a/tests/hlsl/geometry.shader_test b/tests/hlsl/geometry.shader_test new file mode 100644 index 00000000..a5c21e78 --- /dev/null +++ b/tests/hlsl/geometry.shader_test @@ -0,0 +1,67 @@ +[require] +shader model >= 4.0 + +[input layout] +0 r32g32b32a32 float SV_POSITION +0 r32g32b32a32 float COLOR + +[vb 0] +0.0 0.0 1.0 1.0 0.0 1.0 1.0 1.0 + +[vertex shader] +struct vs_data +{ + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +void main(in struct vs_data vs_input, out struct vs_data vs_output) +{ + vs_output.pos = vs_input.pos; + vs_output.color = vs_input.color; +} + +[geometry shader todo] +struct gs_data +{ + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + + [maxvertexcount(4)] +void main(point struct gs_data vin[1], inout TriangleStream vout) +{ + float offset = 0.2 * vin[0].pos.w; + gs_data v; + + v.color = vin[0].color; + + v.pos = float4(vin[0].pos.x - offset, vin[0].pos.y - offset, vin[0].pos.z, 1.0); + vout.Append(v); + v.pos = float4(vin[0].pos.x - offset, vin[0].pos.y + offset, vin[0].pos.z, 1.0); + vout.Append(v); + v.pos = float4(vin[0].pos.x + offset, vin[0].pos.y - offset, vin[0].pos.z, 1.0); + vout.Append(v); + v.pos = float4(vin[0].pos.x + offset, vin[0].pos.y + offset, vin[0].pos.z, 1.0); + vout.Append(v); +} + +[pixel shader] +struct ps_data +{ + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +float4 main(struct ps_data ps_input) : SV_Target +{ + return ps_input.color; +} + +[test] +todo draw point list 1 +probe rtv 0 (320, 190) rgba (0.0, 0.0, 0.0, 0.0) +probe rtv 0 (255, 240) rgba (0.0, 0.0, 0.0, 0.0) +probe rtv 0 (320, 240) rgba (0.0, 1.0, 1.0, 1.0) +probe rtv 0 (385, 240) rgba (0.0, 0.0, 0.0, 0.0) +probe rtv 0 (320, 290) rgba (0.0, 0.0, 0.0, 0.0) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 97047457..e91db918 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -113,6 +113,8 @@ enum parse_state STATE_SHADER_HULL_TODO, STATE_SHADER_DOMAIN, STATE_SHADER_DOMAIN_TODO, + STATE_SHADER_GEOMETRY, + STATE_SHADER_GEOMETRY_TODO, STATE_TEST, }; @@ -965,6 +967,8 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; else if (match_string(line, "triangle strip", &line)) topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + else if (match_string(line, "point list", &line)) + topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; else if (match_string(line, "1 control point patch list", &line)) topology = D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST; else if (match_string(line, "2 control point patch list", &line)) @@ -1306,6 +1310,7 @@ const char *shader_type_string(enum shader_type type) [SHADER_TYPE_VS] = "vs", [SHADER_TYPE_HS] = "hs", [SHADER_TYPE_DS] = "ds", + [SHADER_TYPE_GS] = "gs", [SHADER_TYPE_FX] = "fx", }; assert(type < ARRAY_SIZE(shader_types)); @@ -1369,6 +1374,7 @@ HRESULT dxc_compiler_compile_shader(void *dxc_compiler, enum shader_type type, u [SHADER_TYPE_VS] = L"vs_6_0", [SHADER_TYPE_HS] = L"hs_6_0", [SHADER_TYPE_DS] = L"ds_6_0", + [SHADER_TYPE_GS] = L"gs_6_0", }; const WCHAR *args[] = { @@ -1500,6 +1506,8 @@ static enum parse_state get_parse_state_todo(enum parse_state state) return STATE_SHADER_HULL_TODO; else if (state == STATE_SHADER_DOMAIN) return STATE_SHADER_DOMAIN_TODO; + else if (state == STATE_SHADER_GEOMETRY) + return STATE_SHADER_GEOMETRY_TODO; else return STATE_SHADER_EFFECT_TODO; } @@ -1760,6 +1768,21 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c shader_source_size = 0; break; + case STATE_SHADER_GEOMETRY: + case STATE_SHADER_GEOMETRY_TODO: + if (!skip_tests) + { + todo_if (state == STATE_SHADER_GEOMETRY_TODO) + compile_shader(runner, dxc_compiler, shader_source, shader_source_len, SHADER_TYPE_GS, + expect_hr); + } + free(runner->gs_source); + runner->gs_source = shader_source; + shader_source = NULL; + shader_source_len = 0; + shader_source_size = 0; + break; + case STATE_PREPROC_INVALID: { ID3D10Blob *blob = NULL, *errors = NULL; @@ -1972,6 +1995,12 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c expect_hr = S_OK; state = read_shader_directive(runner, state, line_buffer, line, &expect_hr); } + else if (match_directive_substring(line, "[geometry shader", &line)) + { + state = STATE_SHADER_GEOMETRY; + expect_hr = S_OK; + state = read_shader_directive(runner, state, line_buffer, line, &expect_hr); + } else if (!strcmp(line, "[input layout]\n")) { state = STATE_INPUT_LAYOUT; @@ -2009,6 +2038,8 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c case STATE_SHADER_HULL_TODO: case STATE_SHADER_DOMAIN: case STATE_SHADER_DOMAIN_TODO: + case STATE_SHADER_GEOMETRY: + case STATE_SHADER_GEOMETRY_TODO: { size_t len = strlen(line); @@ -2051,6 +2082,7 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c free(runner->cs_source); free(runner->hs_source); free(runner->ds_source); + free(runner->gs_source); free(runner->fx_source); free(runner->uniforms); for (i = 0; i < runner->resource_count; ++i) diff --git a/tests/shader_runner.h b/tests/shader_runner.h index 4d7e7b67..60dc9ff3 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -47,6 +47,7 @@ enum shader_type SHADER_TYPE_VS, SHADER_TYPE_HS, SHADER_TYPE_DS, + SHADER_TYPE_GS, SHADER_TYPE_FX, }; @@ -165,6 +166,7 @@ struct shader_runner char *fx_source; char *hs_source; char *ds_source; + char *gs_source; enum shader_model minimum_shader_model; enum shader_model maximum_shader_model; bool require_float64; diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index e937040f..a21f2ea4 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -636,9 +636,9 @@ static void d3d11_runner_clear(struct shader_runner *r, struct resource *res, co static bool d3d11_runner_draw(struct shader_runner *r, D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count, unsigned int instance_count) { + ID3D10Blob *vs_code, *ps_code, *hs_code = NULL, *ds_code = NULL, *gs_code = NULL; ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = {0}; ID3D11RenderTargetView *rtvs[D3D11_PS_CS_UAV_REGISTER_COUNT] = {0}; - ID3D10Blob *vs_code, *ps_code, *hs_code = NULL, *ds_code = NULL; struct d3d11_shader_runner *runner = d3d11_shader_runner(r); ID3D11DeviceContext *context = runner->immediate_context; unsigned int min_uav_slot = ARRAY_SIZE(uavs); @@ -647,6 +647,7 @@ static bool d3d11_runner_draw(struct shader_runner *r, ID3D11Device *device = runner->device; ID3D11DepthStencilView *dsv = NULL; unsigned int rtv_count = 0; + ID3D11GeometryShader *gs; ID3D11Buffer *cb = NULL; ID3D11VertexShader *vs; ID3D11DomainShader *ds; @@ -670,6 +671,11 @@ static bool d3d11_runner_draw(struct shader_runner *r, ds_code = compile_shader(runner, runner->r.ds_source, "ds"); succeeded = succeeded && ds_code; } + if (runner->r.gs_source) + { + gs_code = compile_shader(runner, runner->r.gs_source, "gs"); + succeeded = succeeded && gs_code; + } if (!succeeded) { @@ -681,6 +687,8 @@ static bool d3d11_runner_draw(struct shader_runner *r, ID3D10Blob_Release(hs_code); if (ds_code) ID3D10Blob_Release(ds_code); + if (gs_code) + ID3D10Blob_Release(gs_code); return false; } @@ -704,12 +712,20 @@ static bool d3d11_runner_draw(struct shader_runner *r, ID3D10Blob_GetBufferSize(ds_code), NULL, &ds); ok(hr == S_OK, "Failed to create domain shader, hr %#lx.\n", hr); } + if (gs_code) + { + hr = ID3D11Device_CreateGeometryShader(device, ID3D10Blob_GetBufferPointer(gs_code), + ID3D10Blob_GetBufferSize(gs_code), NULL, &gs); + ok(hr == S_OK, "Failed to create geometry shader, hr %#lx.\n", hr); + } ID3D10Blob_Release(ps_code); if (hs_code) ID3D10Blob_Release(hs_code); if (ds_code) ID3D10Blob_Release(ds_code); + if (gs_code) + ID3D10Blob_Release(gs_code); if (runner->r.uniform_count) { @@ -721,6 +737,8 @@ static bool d3d11_runner_draw(struct shader_runner *r, ID3D11DeviceContext_HSSetConstantBuffers(context, 0, 1, &cb); if (ds_code) ID3D11DeviceContext_DSSetConstantBuffers(context, 0, 1, &cb); + if (gs_code) + ID3D11DeviceContext_GSSetConstantBuffers(context, 0, 1, &cb); } for (i = 0; i < runner->r.resource_count; ++i) @@ -812,6 +830,8 @@ static bool d3d11_runner_draw(struct shader_runner *r, ID3D11DeviceContext_HSSetShader(context, hs, NULL, 0); if (ds_code) ID3D11DeviceContext_DSSetShader(context, ds, NULL, 0); + if (gs_code) + ID3D11DeviceContext_GSSetShader(context, gs, NULL, 0); ID3D11DeviceContext_RSSetState(context, runner->rasterizer_state); ID3D11DeviceContext_DrawInstanced(context, vertex_count, instance_count, 0, 0); @@ -822,6 +842,8 @@ static bool d3d11_runner_draw(struct shader_runner *r, ID3D11HullShader_Release(hs); if (ds_code) ID3D11DomainShader_Release(ds); + if (gs_code) + ID3D11GeometryShader_Release(gs); if (cb) ID3D11Buffer_Release(cb); if (ds_state) diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index d566261f..a9b4f244 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -493,14 +493,39 @@ static void d3d12_runner_clear(struct shader_runner *r, struct resource *resourc reset_command_list(command_list, test_context->allocator); } +static D3D12_PRIMITIVE_TOPOLOGY_TYPE d3d12_primitive_topology_type_from_primitive_topology( + D3D_PRIMITIVE_TOPOLOGY primitive_topology) +{ + switch (primitive_topology) + { + case D3D_PRIMITIVE_TOPOLOGY_POINTLIST: + return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; + case D3D_PRIMITIVE_TOPOLOGY_LINELIST: + case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP: + case D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ: + case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ: + return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST: + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP: + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ: + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ: + return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + default: + if (primitive_topology >= D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + && primitive_topology <= D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST) + return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH; + fatal_error("Unhandled primitive topology %u.\n", primitive_topology); + } +} + static bool d3d12_runner_draw(struct shader_runner *r, D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count, unsigned int instance_count) { struct d3d12_shader_runner *runner = d3d12_shader_runner(r); struct test_context *test_context = &runner->test_context; + ID3D10Blob *vs_code, *ps_code, *hs_code = NULL, *ds_code = NULL, *gs_code = NULL; D3D12_CPU_DESCRIPTOR_HANDLE rtvs[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; - ID3D10Blob *vs_code, *ps_code, *hs_code = NULL, *ds_code = NULL; ID3D12GraphicsCommandList *command_list = test_context->list; unsigned int uniform_index, sample_count, rtv_count = 0; D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = {0}; @@ -527,6 +552,11 @@ static bool d3d12_runner_draw(struct shader_runner *r, ds_code = compile_shader(runner, runner->r.ds_source, SHADER_TYPE_DS); succeeded = succeeded && ds_code; } + if (runner->r.gs_source) + { + gs_code = compile_shader(runner, runner->r.gs_source, SHADER_TYPE_GS); + succeeded = succeeded && gs_code; + } todo_if(runner->r.is_todo && runner->r.minimum_shader_model < SHADER_MODEL_6_0) ok(succeeded, "Failed to compile shaders.\n"); @@ -541,6 +571,8 @@ static bool d3d12_runner_draw(struct shader_runner *r, ID3D10Blob_Release(hs_code); if (ds_code) ID3D10Blob_Release(ds_code); + if (gs_code) + ID3D10Blob_Release(gs_code); return false; } @@ -581,12 +613,13 @@ static bool d3d12_runner_draw(struct shader_runner *r, pso_desc.HS.BytecodeLength = ID3D10Blob_GetBufferSize(hs_code); pso_desc.DS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ds_code); pso_desc.DS.BytecodeLength = ID3D10Blob_GetBufferSize(ds_code); - pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH; } - else + if (gs_code) { - pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + pso_desc.GS.pShaderBytecode = ID3D10Blob_GetBufferPointer(gs_code); + pso_desc.GS.BytecodeLength = ID3D10Blob_GetBufferSize(gs_code); } + pso_desc.PrimitiveTopologyType = d3d12_primitive_topology_type_from_primitive_topology(primitive_topology); pso_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; pso_desc.SampleDesc.Count = sample_count; @@ -619,6 +652,8 @@ static bool d3d12_runner_draw(struct shader_runner *r, ID3D10Blob_Release(hs_code); if (ds_code) ID3D10Blob_Release(ds_code); + if (gs_code) + ID3D10Blob_Release(gs_code); free(input_element_descs); if (FAILED(hr)) diff --git a/tests/shader_runner_gl.c b/tests/shader_runner_gl.c index 601307ff..23879437 100644 --- a/tests/shader_runner_gl.c +++ b/tests/shader_runner_gl.c @@ -827,7 +827,7 @@ static GLenum get_compare_op_gl(D3D12_COMPARISON_FUNC op) static GLuint compile_graphics_shader_program(struct gl_runner *runner, ID3D10Blob **vs_blob) { - ID3D10Blob *fs_blob, *hs_blob = NULL, *ds_blob = NULL; + ID3D10Blob *fs_blob, *hs_blob = NULL, *ds_blob = NULL, *gs_blob = NULL; struct vkd3d_shader_code vs_code, fs_code; GLuint program_id, vs_id, fs_id; const GLchar *source; @@ -850,6 +850,11 @@ static GLuint compile_graphics_shader_program(struct gl_runner *runner, ID3D10Bl ds_blob = compile_hlsl(&runner->r, runner->r.ds_source, "ds"); succeeded = succeeded && ds_blob; } + if (runner->r.gs_source) + { + gs_blob = compile_hlsl(&runner->r, runner->r.gs_source, "gs"); + succeeded = succeeded && gs_blob; + } if (!succeeded) { @@ -861,6 +866,8 @@ static GLuint compile_graphics_shader_program(struct gl_runner *runner, ID3D10Bl ID3D10Blob_Release(hs_blob); if (ds_blob) ID3D10Blob_Release(ds_blob); + if (gs_blob) + ID3D10Blob_Release(gs_blob); return false; } @@ -880,7 +887,7 @@ static GLuint compile_graphics_shader_program(struct gl_runner *runner, ID3D10Bl } ID3D10Blob_Release(fs_blob); - /* TODO: compile and use the hs and ds blobs too, but currently this + /* TODO: compile and use the hs, ds and/or gs blobs too, but currently this * point is not reached because compile_hlsl() fails on these. */ if (hs_blob) ID3D10Blob_Release(hs_blob); diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index 3d02639f..7f008bdb 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -728,7 +728,7 @@ static VkPipeline create_graphics_pipeline(struct vulkan_shader_runner *runner, VkVertexInputAttributeDescription input_attributes[32]; VkPipelineDepthStencilStateCreateInfo ds_desc = {0}; VkVertexInputBindingDescription input_bindings[32]; - VkPipelineShaderStageCreateInfo stage_desc[4]; + VkPipelineShaderStageCreateInfo stage_desc[5]; struct vkd3d_shader_code vs_dxbc; VkDevice device = runner->device; unsigned int stage_count = 0; @@ -750,6 +750,11 @@ static VkPipeline create_graphics_pipeline(struct vulkan_shader_runner *runner, ret &= create_shader_stage(runner, &stage_desc[stage_count++], "ds", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, runner->r.ds_source, NULL); } + + if (runner->r.gs_source) + ret &= create_shader_stage(runner, &stage_desc[stage_count++], "gs", + VK_SHADER_STAGE_GEOMETRY_BIT, runner->r.gs_source, NULL); + todo_if (runner->r.is_todo) ok(ret, "Failed to compile shaders.\n"); if (!ret) {