Goes atop !767. The last five commits belong here.
-- v4: vkd3d-shader/dxil: Implement DX intrinsic OutputControlPointID. vkd3d-shader/dxil: Implement DX intrinsic DomainLocation. vkd3d-shader/dxil: Implement DX intrinsic StorePatchConstant. vkd3d-shader/dxil: Implement DX intrinsics LoadOutputControlPoint and LoadPatchConstant. vkd3d-shader/dxil: Support patch constant functions and signatures. vkd3d-shader/ir: Validate tessellation declarations. vkd3d-shader/dxil: Implement DX intrinsic PrimitiveID. vkd3d-shader/dxil: Load hull shader properties. vkd3d-shader/dxil: Load domain shader properties. tests/hlsl: Add a tessellation test.
From: Conor McCarthy cmccarthy@codeweavers.com
--- Makefile.am | 1 + tests/hlsl/tessellation.shader_test | 98 +++++++++++++++++++++++++++++ tests/shader_runner.c | 72 +++++++++++++++++++++ tests/shader_runner.h | 4 ++ tests/shader_runner_d3d11.c | 65 +++++++++++++++++-- tests/shader_runner_d3d12.c | 41 ++++++++++-- tests/shader_runner_gl.c | 37 +++++++++-- tests/shader_runner_vulkan.c | 27 ++++++-- 8 files changed, 326 insertions(+), 19 deletions(-) create mode 100644 tests/hlsl/tessellation.shader_test
diff --git a/Makefile.am b/Makefile.am index 68e8642e0..9380af450 100644 --- a/Makefile.am +++ b/Makefile.am @@ -197,6 +197,7 @@ vkd3d_shader_tests = \ tests/hlsl/swizzle-matrix.shader_test \ tests/hlsl/swizzles.shader_test \ tests/hlsl/ternary.shader_test \ + tests/hlsl/tessellation.shader_test \ tests/hlsl/texture-load-offset.shader_test \ tests/hlsl/texture-load-typed.shader_test \ tests/hlsl/texture-load.shader_test \ diff --git a/tests/hlsl/tessellation.shader_test b/tests/hlsl/tessellation.shader_test new file mode 100644 index 000000000..d8b263473 --- /dev/null +++ b/tests/hlsl/tessellation.shader_test @@ -0,0 +1,98 @@ +[require] +shader model >= 5.0 + +[vertex shader] +struct data +{ + float4 position : SV_Position; + float r : RED; + float g : GREEN; + float b : BLUE; +}; + +void main(uint id : SV_VertexID, out data output) +{ + float2 coords = float2((id << 1) & 2, id & 2); + output.position = float4(coords * float2(2, -2) + float2(-1, 1), 0, 1); + output.r = 0.0; + output.g = 1.0; + output.b = 0.0; +} + +[hull shader todo] +struct data +{ + float4 position : SV_Position; + float r : RED; + float g : GREEN; + float b : BLUE; +}; + +struct patch_constant_data +{ + float edges[3] : SV_TessFactor; + float inside : SV_InsideTessFactor; +}; + +void patch_constant(InputPatch<data, 3> input, out patch_constant_data output) +{ + output.edges[0] = output.edges[1] = output.edges[2] = 1.0f; + output.inside = 1.0f; +} + + [domain("tri")] + [outputcontrolpoints(3)] + [partitioning("integer")] + [outputtopology("triangle_cw")] + [patchconstantfunc("patch_constant")] +data main(InputPatch<data, 3> input, uint i : SV_OutputControlPointID) +{ + return input[i]; +} + +[domain shader todo] +struct data +{ + float4 position : SV_Position; + float r : RED; + float g : GREEN; + float b : BLUE; +}; + +struct patch_constant_data +{ + float edges[3] : SV_TessFactor; + float inside : SV_InsideTessFactor; +}; + + [domain("tri")] +void main(patch_constant_data input, + float3 tess_coord : SV_DomainLocation, + const OutputPatch<data, 3> patch, + out data output) +{ + output.position = tess_coord.x * patch[0].position + + tess_coord.y * patch[1].position + + tess_coord.z * patch[2].position; + output.r = tess_coord.x * patch[0].r + tess_coord.y * patch[1].r + tess_coord.z * patch[2].r; + output.g = tess_coord.x * patch[0].g + tess_coord.y * patch[1].g + tess_coord.z * patch[2].g; + output.b = tess_coord.x * patch[0].b + tess_coord.y * patch[1].b + tess_coord.z * patch[2].b; +} + +[pixel shader] +struct data +{ + float4 position : SV_Position; + float r : RED; + float g : GREEN; + float b : BLUE; +}; + +float4 main(data input) : sv_target +{ + return float4(input.r, input.g, input.b, 1.0); +} + +[test] +todo draw 3 control point patch list 3 +probe all rgba (0.0, 1.0, 0.0, 1.0) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 5eafbcbe4..427cbec00 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -107,6 +107,10 @@ enum parse_state STATE_SHADER_VERTEX_TODO, STATE_SHADER_EFFECT, STATE_SHADER_EFFECT_TODO, + STATE_SHADER_HULL, + STATE_SHADER_HULL_TODO, + STATE_SHADER_DOMAIN, + STATE_SHADER_DOMAIN_TODO, STATE_TEST, };
@@ -817,6 +821,9 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) " return pos;\n" "}";
+ if (!runner->hs_source != !runner->ds_source) + fatal_error("Have a domain or hull shader but not both.\n"); + if (!shader_runner_get_resource(runner, RESOURCE_TYPE_RENDER_TARGET, 0)) { memset(¶ms, 0, sizeof(params)); @@ -867,6 +874,9 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) struct resource_params params; unsigned int vertex_count;
+ if (!runner->hs_source != !runner->ds_source) + fatal_error("Have a domain or hull shader but not both.\n"); + if (!shader_runner_get_resource(runner, RESOURCE_TYPE_RENDER_TARGET, 0)) { memset(¶ms, 0, sizeof(params)); @@ -887,6 +897,14 @@ 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, "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)) + topology = D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST; + else if (match_string(line, "3 control point patch list", &line)) + topology = D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST; + else if (match_string(line, "4 control point patch list", &line)) + topology = D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST; else fatal_error("Unknown primitive topology '%s'.\n", line);
@@ -1204,6 +1222,8 @@ const char *shader_type_string(enum shader_type type) [SHADER_TYPE_CS] = "cs", [SHADER_TYPE_PS] = "ps", [SHADER_TYPE_VS] = "vs", + [SHADER_TYPE_HS] = "hs", + [SHADER_TYPE_DS] = "ds", [SHADER_TYPE_FX] = "fx", }; assert(type < ARRAY_SIZE(shader_types)); @@ -1265,6 +1285,8 @@ HRESULT dxc_compiler_compile_shader(void *dxc_compiler, enum shader_type type, u [SHADER_TYPE_CS] = L"cs_6_0", [SHADER_TYPE_PS] = L"ps_6_0", [SHADER_TYPE_VS] = L"vs_6_0", + [SHADER_TYPE_HS] = L"hs_6_0", + [SHADER_TYPE_DS] = L"ds_6_0", }; const WCHAR *args[] = { @@ -1392,6 +1414,10 @@ static enum parse_state get_parse_state_todo(enum parse_state state) return STATE_SHADER_PIXEL_TODO; else if (state == STATE_SHADER_VERTEX) return STATE_SHADER_VERTEX_TODO; + else if (state == STATE_SHADER_HULL) + return STATE_SHADER_HULL_TODO; + else if (state == STATE_SHADER_DOMAIN) + return STATE_SHADER_DOMAIN_TODO; else return STATE_SHADER_EFFECT_TODO; } @@ -1612,6 +1638,36 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c shader_source_size = 0; break;
+ case STATE_SHADER_HULL: + case STATE_SHADER_HULL_TODO: + if (!skip_tests) + { + todo_if (state == STATE_SHADER_HULL_TODO) + compile_shader(runner, dxc_compiler, shader_source, shader_source_len, SHADER_TYPE_HS, + expect_hr); + } + free(runner->hs_source); + runner->hs_source = shader_source; + shader_source = NULL; + shader_source_len = 0; + shader_source_size = 0; + break; + + case STATE_SHADER_DOMAIN: + case STATE_SHADER_DOMAIN_TODO: + if (!skip_tests) + { + todo_if (state == STATE_SHADER_DOMAIN_TODO) + compile_shader(runner, dxc_compiler, shader_source, shader_source_len, SHADER_TYPE_DS, + expect_hr); + } + free(runner->ds_source); + runner->ds_source = shader_source; + shader_source = NULL; + shader_source_len = 0; + shader_source_size = 0; + break; + case STATE_PREPROC_INVALID: { ID3D10Blob *blob = NULL, *errors = NULL; @@ -1794,6 +1850,18 @@ 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, "[hull shader", &line)) + { + state = STATE_SHADER_HULL; + expect_hr = S_OK; + state = read_shader_directive(runner, state, line_buffer, line, &expect_hr); + } + else if (match_directive_substring(line, "[domain shader", &line)) + { + state = STATE_SHADER_DOMAIN; + 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; @@ -1825,6 +1893,10 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c case STATE_SHADER_VERTEX_TODO: case STATE_SHADER_EFFECT: case STATE_SHADER_EFFECT_TODO: + case STATE_SHADER_HULL: + case STATE_SHADER_HULL_TODO: + case STATE_SHADER_DOMAIN: + case STATE_SHADER_DOMAIN_TODO: { size_t len = strlen(line);
diff --git a/tests/shader_runner.h b/tests/shader_runner.h index 2f7e8fb25..dd92048f5 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -45,6 +45,8 @@ enum shader_type SHADER_TYPE_CS, SHADER_TYPE_PS, SHADER_TYPE_VS, + SHADER_TYPE_HS, + SHADER_TYPE_DS, SHADER_TYPE_FX, };
@@ -157,6 +159,8 @@ struct shader_runner char *ps_source; char *cs_source; char *fx_source; + char *hs_source; + char *ds_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 1285ca41f..585a23000 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -589,24 +589,46 @@ static bool d3d11_runner_draw(struct shader_runner *r, { 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); ID3D11Device *device = runner->device; - ID3D10Blob *vs_code, *ps_code; unsigned int rtv_count = 0; ID3D11Buffer *cb = NULL; ID3D11VertexShader *vs; + ID3D11DomainShader *ds; ID3D11PixelShader *ps; + ID3D11HullShader *hs; + bool succeeded; unsigned int i; HRESULT hr;
- if (!(vs_code = compile_shader(runner, runner->r.vs_source, "vs"))) - return false; + vs_code = compile_shader(runner, runner->r.vs_source, "vs"); + ps_code = compile_shader(runner, runner->r.ps_source, "ps"); + succeeded = vs_code && ps_code;
- if (!(ps_code = compile_shader(runner, runner->r.ps_source, "ps"))) + if (runner->r.hs_source) + { + hs_code = compile_shader(runner, runner->r.hs_source, "hs"); + succeeded = succeeded && hs_code; + } + if (runner->r.ds_source) { - ID3D10Blob_Release(vs_code); + ds_code = compile_shader(runner, runner->r.ds_source, "ds"); + succeeded = succeeded && ds_code; + } + + if (!succeeded) + { + if (ps_code) + ID3D10Blob_Release(ps_code); + if (vs_code) + ID3D10Blob_Release(vs_code); + if (hs_code) + ID3D10Blob_Release(hs_code); + if (ds_code) + ID3D10Blob_Release(ds_code); return false; }
@@ -618,12 +640,35 @@ static bool d3d11_runner_draw(struct shader_runner *r, ID3D10Blob_GetBufferSize(ps_code), NULL, &ps); ok(hr == S_OK, "Failed to create pixel shader, hr %#lx.\n", hr);
+ if (hs_code) + { + hr = ID3D11Device_CreateHullShader(device, ID3D10Blob_GetBufferPointer(hs_code), + ID3D10Blob_GetBufferSize(hs_code), NULL, &hs); + ok(hr == S_OK, "Failed to create hull shader, hr %#lx.\n", hr); + } + if (ds_code) + { + hr = ID3D11Device_CreateDomainShader(device, ID3D10Blob_GetBufferPointer(ds_code), + ID3D10Blob_GetBufferSize(ds_code), NULL, &ds); + ok(hr == S_OK, "Failed to create domain shader, hr %#lx.\n", hr); + } + + ID3D10Blob_Release(ps_code); + if (hs_code) + ID3D10Blob_Release(hs_code); + if (ds_code) + ID3D10Blob_Release(ds_code); + if (runner->r.uniform_count) { cb = create_buffer(device, D3D11_BIND_CONSTANT_BUFFER, runner->r.uniform_count * sizeof(*runner->r.uniforms), 0, runner->r.uniforms); ID3D11DeviceContext_VSSetConstantBuffers(context, 0, 1, &cb); ID3D11DeviceContext_PSSetConstantBuffers(context, 0, 1, &cb); + if (hs_code) + ID3D11DeviceContext_HSSetConstantBuffers(context, 0, 1, &cb); + if (ds_code) + ID3D11DeviceContext_DSSetConstantBuffers(context, 0, 1, &cb); }
for (i = 0; i < runner->r.resource_count; ++i) @@ -694,15 +739,25 @@ static bool d3d11_runner_draw(struct shader_runner *r, ID3D11InputLayout_Release(input_layout); }
+ ID3D10Blob_Release(vs_code); + ID3D11DeviceContext_IASetPrimitiveTopology(context, primitive_topology); ID3D11DeviceContext_VSSetShader(context, vs, NULL, 0); ID3D11DeviceContext_PSSetShader(context, ps, NULL, 0); + if (hs_code) + ID3D11DeviceContext_HSSetShader(context, hs, NULL, 0); + if (ds_code) + ID3D11DeviceContext_DSSetShader(context, ds, NULL, 0); ID3D11DeviceContext_RSSetState(context, runner->rasterizer_state);
ID3D11DeviceContext_Draw(context, vertex_count, 0);
ID3D11PixelShader_Release(ps); ID3D11VertexShader_Release(vs); + if (hs_code) + ID3D11HullShader_Release(hs); + if (ds_code) + ID3D11DomainShader_Release(ds); if (cb) ID3D11Buffer_Release(cb);
diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index 9bf7bb248..310e8e6f9 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -434,29 +434,47 @@ static bool d3d12_runner_draw(struct shader_runner *r, struct test_context *test_context = &runner->test_context;
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; 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; - ID3D10Blob *vs_code, *ps_code; unsigned int uniform_index; unsigned int rtv_count = 0; ID3D12PipelineState *pso; + bool succeeded; HRESULT hr; size_t i;
ps_code = compile_shader(runner, runner->r.ps_source, SHADER_TYPE_PS); vs_code = compile_shader(runner, runner->r.vs_source, SHADER_TYPE_VS); + succeeded = ps_code && vs_code; + + if (runner->r.hs_source) + { + hs_code = compile_shader(runner, runner->r.hs_source, SHADER_TYPE_HS); + succeeded = succeeded && hs_code; + } + if (runner->r.ds_source) + { + ds_code = compile_shader(runner, runner->r.ds_source, SHADER_TYPE_DS); + succeeded = succeeded && ds_code; + } + todo_if(runner->r.is_todo && runner->r.minimum_shader_model < SHADER_MODEL_6_0) - ok(ps_code && vs_code, "Failed to compile shaders.\n"); + ok(succeeded, "Failed to compile shaders.\n");
- if (!ps_code || !vs_code) + if (!succeeded) { if (ps_code) ID3D10Blob_Release(ps_code); if (vs_code) ID3D10Blob_Release(vs_code); + if (hs_code) + ID3D10Blob_Release(hs_code); + if (ds_code) + ID3D10Blob_Release(ds_code); return false; }
@@ -481,9 +499,20 @@ static bool d3d12_runner_draw(struct shader_runner *r, pso_desc.VS.BytecodeLength = ID3D10Blob_GetBufferSize(vs_code); pso_desc.PS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ps_code); pso_desc.PS.BytecodeLength = ID3D10Blob_GetBufferSize(ps_code); + if (hs_code) + { + pso_desc.HS.pShaderBytecode = ID3D10Blob_GetBufferPointer(hs_code); + 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 + { + pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + } pso_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; - 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; @@ -510,6 +539,10 @@ static bool d3d12_runner_draw(struct shader_runner *r, todo_if(runner->r.is_todo) ok(hr == S_OK, "Failed to create state, hr %#x.\n", hr); ID3D10Blob_Release(vs_code); ID3D10Blob_Release(ps_code); + if (hs_code) + ID3D10Blob_Release(hs_code); + if (ds_code) + ID3D10Blob_Release(ds_code); free(input_element_descs);
if (FAILED(hr)) diff --git a/tests/shader_runner_gl.c b/tests/shader_runner_gl.c index e56eccab0..f7fc487dd 100644 --- a/tests/shader_runner_gl.c +++ b/tests/shader_runner_gl.c @@ -804,20 +804,40 @@ 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; struct vkd3d_shader_code vs_code, fs_code; GLuint program_id, vs_id, fs_id; const GLchar *source; - ID3D10Blob *fs_blob; GLint status, size; + bool succeeded;
reset_combined_samplers(runner);
- if (!(*vs_blob = compile_hlsl(&runner->r, runner->r.vs_source, "vs"))) - return false; + *vs_blob = compile_hlsl(&runner->r, runner->r.vs_source, "vs"); + fs_blob = compile_hlsl(&runner->r, runner->r.ps_source, "ps"); + succeeded = *vs_blob && fs_blob;
- if (!(fs_blob = compile_hlsl(&runner->r, runner->r.ps_source, "ps"))) + if (runner->r.hs_source) { - ID3D10Blob_Release(*vs_blob); + hs_blob = compile_hlsl(&runner->r, runner->r.hs_source, "hs"); + succeeded = succeeded && hs_blob; + } + if (runner->r.ds_source) + { + ds_blob = compile_hlsl(&runner->r, runner->r.ds_source, "ds"); + succeeded = succeeded && ds_blob; + } + + if (!succeeded) + { + if (*vs_blob) + ID3D10Blob_Release(*vs_blob); + if (fs_blob) + ID3D10Blob_Release(fs_blob); + if (hs_blob) + ID3D10Blob_Release(hs_blob); + if (ds_blob) + ID3D10Blob_Release(ds_blob); return false; }
@@ -837,6 +857,13 @@ 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 + * point is not reached because compile_hlsl() fails on these. */ + if (hs_blob) + ID3D10Blob_Release(hs_blob); + if (ds_blob) + ID3D10Blob_Release(ds_blob); + vs_id = glCreateShader(GL_VERTEX_SHADER); if (runner->language == SPIR_V) { diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index a3bbf170c..c903c8941 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -683,9 +683,10 @@ static VkPipeline create_graphics_pipeline(struct vulkan_shader_runner *runner, static const VkRect2D rt_rect = {.extent.width = RENDER_TARGET_WIDTH, .extent.height = RENDER_TARGET_HEIGHT}; VkGraphicsPipelineCreateInfo pipeline_desc = {.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; VkPipelineColorBlendAttachmentState attachment_desc[MAX_RESOURCES] = {0}; + VkPipelineTessellationStateCreateInfo tessellation_info; VkVertexInputAttributeDescription input_attributes[32]; VkVertexInputBindingDescription input_bindings[32]; - VkPipelineShaderStageCreateInfo stage_desc[2]; + VkPipelineShaderStageCreateInfo stage_desc[4]; struct vkd3d_shader_code vs_dxbc; VkDevice device = runner->device; VkPipeline pipeline; @@ -696,11 +697,17 @@ static VkPipeline create_graphics_pipeline(struct vulkan_shader_runner *runner, memset(stage_desc, 0, sizeof(stage_desc)); ret = create_shader_stage(runner, &stage_desc[0], "vs", VK_SHADER_STAGE_VERTEX_BIT, runner->r.vs_source, &vs_dxbc) && create_shader_stage(runner, &stage_desc[1], "ps", VK_SHADER_STAGE_FRAGMENT_BIT, runner->r.ps_source, NULL); + + if (runner->r.hs_source) + { + ret &= create_shader_stage(runner, &stage_desc[1], "hs", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, runner->r.hs_source, NULL); + ret &= create_shader_stage(runner, &stage_desc[2], "ds", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, runner->r.ds_source, NULL); + } todo_if (runner->r.is_todo) ok(ret, "Failed to compile shaders.\n"); if (!ret) { - VK_CALL(vkDestroyShaderModule(device, stage_desc[0].module, NULL)); - VK_CALL(vkDestroyShaderModule(device, stage_desc[1].module, NULL)); + for (i = 0; i < ARRAY_SIZE(stage_desc); ++i) + VK_CALL(vkDestroyShaderModule(device, stage_desc[i].module, NULL)); return VK_NULL_HANDLE; }
@@ -791,11 +798,21 @@ static VkPipeline create_graphics_pipeline(struct vulkan_shader_runner *runner, pipeline_desc.renderPass = render_pass; pipeline_desc.subpass = 0;
+ if (runner->r.hs_source) + { + tessellation_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + tessellation_info.pNext = NULL; + tessellation_info.flags = 0; + tessellation_info.patchControlPoints + = max(primitive_topology - D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + 1, 1); + pipeline_desc.pTessellationState = &tessellation_info; + } + vr = VK_CALL(vkCreateGraphicsPipelines(runner->device, VK_NULL_HANDLE, 1, &pipeline_desc, NULL, &pipeline)); ok(vr == VK_SUCCESS, "Failed to create graphics pipeline, vr %d.\n", vr);
- VK_CALL(vkDestroyShaderModule(device, stage_desc[0].module, NULL)); - VK_CALL(vkDestroyShaderModule(device, stage_desc[1].module, NULL)); + for (i = 0; i < ARRAY_SIZE(stage_desc); ++i) + VK_CALL(vkDestroyShaderModule(device, stage_desc[i].module, NULL)); vkd3d_shader_free_scan_signature_info(&runner->vs_signatures); vkd3d_shader_free_shader_code(&vs_dxbc);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 136 ++++++++++++++++++++--- libs/vkd3d-shader/vkd3d_shader_private.h | 4 + 2 files changed, 127 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index b5a61d99d..9fe0153f5 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -7527,9 +7527,40 @@ static const enum vkd3d_shader_sysval_semantic sysval_semantic_table[] = [SEMANTIC_KIND_TARGET] = VKD3D_SHADER_SV_TARGET, };
-static enum vkd3d_shader_sysval_semantic sysval_semantic_from_dxil_semantic_kind(enum dxil_semantic_kind kind) +static enum vkd3d_shader_sysval_semantic sysval_semantic_from_dxil_semantic_kind(enum dxil_semantic_kind kind, + enum vkd3d_tessellator_domain domain) { - if (kind < ARRAY_SIZE(sysval_semantic_table)) + if (kind == SEMANTIC_KIND_TESSFACTOR) + { + switch (domain) + { + case VKD3D_TESSELLATOR_DOMAIN_LINE: + return VKD3D_SHADER_SV_TESS_FACTOR_LINEDET; + case VKD3D_TESSELLATOR_DOMAIN_TRIANGLE: + return VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE; + case VKD3D_TESSELLATOR_DOMAIN_QUAD: + return VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE; + default: + /* Error is handled during parsing. */ + return VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE; + } + } + else if (kind == SEMANTIC_KIND_INSIDETESSFACTOR) + { + switch (domain) + { + case VKD3D_TESSELLATOR_DOMAIN_LINE: + return VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN; + case VKD3D_TESSELLATOR_DOMAIN_TRIANGLE: + return VKD3D_SHADER_SV_TESS_FACTOR_TRIINT; + case VKD3D_TESSELLATOR_DOMAIN_QUAD: + return VKD3D_SHADER_SV_TESS_FACTOR_QUADINT; + default: + /* Error is handled during parsing. */ + return VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE; + } + } + else if (kind < ARRAY_SIZE(sysval_semantic_table)) { return sysval_semantic_table[kind]; } @@ -8285,7 +8316,7 @@ static void signature_element_read_additional_element_values(struct signature_el }
static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const struct sm6_metadata_value *m, - struct shader_signature *s) + struct shader_signature *s, enum vkd3d_tessellator_domain tessellator_domain) { unsigned int i, j, column_count, operand_count, index; const struct sm6_metadata_node *node, *element_node; @@ -8378,7 +8409,7 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const e->min_precision = minimum_precision_from_dxil_component_type(values[2]);
j = values[3]; - e->sysval_semantic = sysval_semantic_from_dxil_semantic_kind(j); + e->sysval_semantic = sysval_semantic_from_dxil_semantic_kind(j, tessellator_domain); if (j != SEMANTIC_KIND_ARBITRARY && j != SEMANTIC_KIND_TARGET && e->sysval_semantic == VKD3D_SHADER_SV_NONE) { WARN("Unhandled semantic kind %u.\n", j); @@ -8461,7 +8492,8 @@ static enum vkd3d_result sm6_parser_read_signature(struct sm6_parser *sm6, const return VKD3D_OK; }
-static enum vkd3d_result sm6_parser_signatures_init(struct sm6_parser *sm6, const struct sm6_metadata_value *m) +static enum vkd3d_result sm6_parser_signatures_init(struct sm6_parser *sm6, const struct sm6_metadata_value *m, + enum vkd3d_tessellator_domain tessellator_domain) { enum vkd3d_result ret;
@@ -8474,12 +8506,12 @@ static enum vkd3d_result sm6_parser_signatures_init(struct sm6_parser *sm6, cons }
if (m->u.node->operand_count && (ret = sm6_parser_read_signature(sm6, m->u.node->operands[0], - &sm6->p.program.input_signature)) < 0) + &sm6->p.program.input_signature, tessellator_domain)) < 0) { return ret; } if (m->u.node->operand_count > 1 && (ret = sm6_parser_read_signature(sm6, m->u.node->operands[1], - &sm6->p.program.output_signature)) < 0) + &sm6->p.program.output_signature, tessellator_domain)) < 0) { return ret; } @@ -8572,10 +8604,85 @@ static enum vkd3d_result sm6_parser_emit_thread_group(struct sm6_parser *sm6, co return VKD3D_OK; }
+static void sm6_parser_emit_dcl_tessellator_domain(struct sm6_parser *sm6, + enum vkd3d_tessellator_domain tessellator_domain) +{ + struct vkd3d_shader_instruction *ins; + + if (tessellator_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID || tessellator_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT) + { + WARN("Unhandled domain %u.\n", tessellator_domain); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "Domain shader tessellator domain %u is unhandled.", tessellator_domain); + } + + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_TESSELLATOR_DOMAIN); + ins->declaration.tessellator_domain = tessellator_domain; +} + +static void sm6_parser_validate_control_point_count(struct sm6_parser *sm6, unsigned int count) +{ + if (!count || count > 32) + { + WARN("Invalid control point count %u.\n", count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "Domain shader input control point count %u is invalid.", count); + } +} + +static enum vkd3d_tessellator_domain sm6_parser_ds_properties_init(struct sm6_parser *sm6, + const struct sm6_metadata_value *m) +{ + const struct sm6_metadata_node *node; + unsigned int operands[2] = {0}; + unsigned int i; + + if (!m || !sm6_metadata_value_is_node(m)) + { + WARN("Missing or invalid DS properties.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "Domain shader properties node is missing or invalid."); + return 0; + } + + node = m->u.node; + if (node->operand_count < ARRAY_SIZE(operands)) + { + WARN("Invalid operand count %u.\n", node->operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + "Domain shader properties operand count %u is invalid.", node->operand_count); + return 0; + } + if (node->operand_count > ARRAY_SIZE(operands)) + { + WARN("Ignoring %zu extra operands.\n", node->operand_count - ARRAY_SIZE(operands)); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring %zu extra operands for domain shader properties.", + node->operand_count - ARRAY_SIZE(operands)); + } + + for (i = 0; i < node->operand_count; ++i) + { + if (!sm6_metadata_get_uint_value(sm6, node->operands[i], &operands[i])) + { + WARN("DS property at index %u is not a uint value.\n", i); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "Domain shader properties operand at index %u is not an integer.", i); + } + } + + sm6_parser_emit_dcl_tessellator_domain(sm6, operands[0]); + sm6_parser_validate_control_point_count(sm6, operands[1]); + sm6->p.program.input_control_point_count = operands[1]; + + return operands[0]; +} + static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6) { const struct sm6_metadata_value *m = sm6_parser_find_named_metadata(sm6, "dx.entryPoints"); const struct sm6_metadata_node *node, *entry_node = m ? m->u.node : NULL; + enum vkd3d_tessellator_domain tessellator_domain = 0; unsigned int i, operand_count, tag; const struct sm6_value *value; enum vkd3d_result ret; @@ -8614,12 +8721,6 @@ static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6) "Entry point function name %s does not match the name in metadata.", sm6->entry_point); }
- if (entry_node->operand_count >= 3 && (m = entry_node->operands[2]) - && (ret = sm6_parser_signatures_init(sm6, m)) < 0) - { - return ret; - } - if (entry_node->operand_count >= 5 && (m = entry_node->operands[4])) { if (!sm6_metadata_value_is_node(m)) @@ -8654,6 +8755,9 @@ static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6) case SHADER_PROPERTIES_FLAGS: sm6_parser_emit_global_flags(sm6, node->operands[i + 1]); break; + case SHADER_PROPERTIES_DOMAIN: + tessellator_domain = sm6_parser_ds_properties_init(sm6, node->operands[i + 1]); + break; case SHADER_PROPERTIES_COMPUTE: if ((ret = sm6_parser_emit_thread_group(sm6, node->operands[i + 1])) < 0) return ret; @@ -8667,6 +8771,12 @@ static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6) } }
+ if (entry_node->operand_count >= 3 && (m = entry_node->operands[2]) + && (ret = sm6_parser_signatures_init(sm6, m, tessellator_domain)) < 0) + { + return ret; + } + return VKD3D_OK; }
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index b07a7bff7..6eda2039f 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -763,9 +763,13 @@ enum vkd3d_shader_atomic_rmw_flags
enum vkd3d_tessellator_domain { + VKD3D_TESSELLATOR_DOMAIN_INVALID = 0, + VKD3D_TESSELLATOR_DOMAIN_LINE = 1, VKD3D_TESSELLATOR_DOMAIN_TRIANGLE = 2, VKD3D_TESSELLATOR_DOMAIN_QUAD = 3, + + VKD3D_TESSELLATOR_DOMAIN_COUNT = 4, };
#define VKD3DSI_NONE 0x0
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 183 ++++++++++++++++++++++- libs/vkd3d-shader/spirv.c | 5 - libs/vkd3d-shader/vkd3d_shader_private.h | 5 + 3 files changed, 182 insertions(+), 11 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 9fe0153f5..1333c55b8 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -790,6 +790,7 @@ struct sm6_parser size_t global_symbol_count;
const char *entry_point; + const char *patch_constant_function;
struct vkd3d_shader_dst_param *output_params; struct vkd3d_shader_dst_param *input_params; @@ -2789,7 +2790,7 @@ static inline uint64_t decode_rotated_signed_value(uint64_t value) return value << 63; }
-static inline float bitcast_uint64_to_float(uint64_t value) +static float bitcast_uint_to_float(unsigned int value) { union { @@ -2813,6 +2814,23 @@ static inline double bitcast_uint64_to_double(uint64_t value) return u.double_value; }
+static float register_get_float_value(const struct vkd3d_shader_register *reg) +{ + if (!register_is_constant(reg) || !data_type_is_floating_point(reg->data_type)) + return 0.0; + + if (reg->dimension == VSIR_DIMENSION_VEC4) + WARN("Returning vec4.x.\n"); + + if (reg->type == VKD3DSPR_IMMCONST64) + { + WARN("Truncating double to float.\n"); + return bitcast_uint64_to_double(reg->u.immconst_u64[0]); + } + + return bitcast_uint_to_float(reg->u.immconst_u32[0]); +} + static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, const struct sm6_type *type, const uint64_t *operands, struct sm6_parser *sm6) { @@ -2981,7 +2999,7 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const if (type->u.width == 16) dst->u.reg.u.immconst_u32[0] = record->operands[0]; else if (type->u.width == 32) - dst->u.reg.u.immconst_f32[0] = bitcast_uint64_to_float(record->operands[0]); + dst->u.reg.u.immconst_f32[0] = bitcast_uint_to_float(record->operands[0]); else if (type->u.width == 64) dst->u.reg.u.immconst_f64[0] = bitcast_uint64_to_double(record->operands[0]); else @@ -6570,6 +6588,25 @@ static bool sm6_metadata_get_uint64_value(const struct sm6_parser *sm6, return true; }
+static bool sm6_metadata_get_float_value(const struct sm6_parser *sm6, + const struct sm6_metadata_value *m, float *f) +{ + const struct sm6_value *value; + + if (!m || m->type != VKD3D_METADATA_VALUE) + return false; + + value = m->u.value; + if (!sm6_value_is_constant(value)) + return false; + if (!sm6_type_is_floating_point(value->type)) + return false; + + *f = register_get_float_value(&value->u.reg); + + return true; +} + static void sm6_parser_metadata_attachment_block_init(struct sm6_parser *sm6, const struct dxil_block *target_block, const struct dxil_block *block) { @@ -8604,6 +8641,14 @@ static enum vkd3d_result sm6_parser_emit_thread_group(struct sm6_parser *sm6, co return VKD3D_OK; }
+static void sm6_parser_emit_dcl_count(struct sm6_parser *sm6, enum vkd3d_shader_opcode handler_idx, unsigned int count) +{ + struct vkd3d_shader_instruction *ins; + + ins = sm6_parser_add_instruction(sm6, handler_idx); + ins->declaration.count = count; +} + static void sm6_parser_emit_dcl_tessellator_domain(struct sm6_parser *sm6, enum vkd3d_tessellator_domain tessellator_domain) { @@ -8620,14 +8665,72 @@ static void sm6_parser_emit_dcl_tessellator_domain(struct sm6_parser *sm6, ins->declaration.tessellator_domain = tessellator_domain; }
-static void sm6_parser_validate_control_point_count(struct sm6_parser *sm6, unsigned int count) +static void sm6_parser_validate_control_point_count(struct sm6_parser *sm6, unsigned int count, + const char *type) { if (!count || count > 32) { - WARN("Invalid control point count %u.\n", count); + WARN("%s control point count %u invalid.\n", type, count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "%s control point count %u is invalid.", type, count); + } +} + +static void sm6_parser_emit_dcl_tessellator_partitioning(struct sm6_parser *sm6, + enum vkd3d_shader_tessellator_partitioning tessellator_partitioning) +{ + struct vkd3d_shader_instruction *ins; + + if (!tessellator_partitioning || tessellator_partitioning > VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN) + { + WARN("Unhandled partitioning %u.\n", tessellator_partitioning); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "Hull shader tessellator partitioning %u is unhandled.", tessellator_partitioning); + } + + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_TESSELLATOR_PARTITIONING); + ins->declaration.tessellator_partitioning = tessellator_partitioning; +} + +static void sm6_parser_emit_dcl_tessellator_output_primitive(struct sm6_parser *sm6, + enum vkd3d_shader_tessellator_output_primitive primitive) +{ + struct vkd3d_shader_instruction *ins; + + if (!primitive || primitive > VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW) + { + WARN("Unhandled output primitive %u.\n", primitive); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, - "Domain shader input control point count %u is invalid.", count); + "Hull shader tessellator output primitive %u is unhandled.", primitive); } + + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE); + ins->declaration.tessellator_output_primitive = primitive; +} + +static void sm6_parser_emit_dcl_max_tessellation_factor(struct sm6_parser *sm6, struct sm6_metadata_value *m) +{ + struct vkd3d_shader_instruction *ins; + float max_tessellation_factor; + + if (!sm6_metadata_get_float_value(sm6, m, &max_tessellation_factor)) + { + WARN("Max tess factor property is not a float value.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "Hull shader max tessellation factor property operand is not a float."); + return; + } + + /* Exclude non-finite values. */ + if (!(max_tessellation_factor >= 1.0f && max_tessellation_factor <= 64.0f)) + { + WARN("Invalid max tess factor %f.\n", max_tessellation_factor); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "Hull shader max tessellation factor %f is invalid.", max_tessellation_factor); + } + + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_HS_MAX_TESSFACTOR); + ins->declaration.max_tessellation_factor = max_tessellation_factor; }
static enum vkd3d_tessellator_domain sm6_parser_ds_properties_init(struct sm6_parser *sm6, @@ -8672,12 +8775,77 @@ static enum vkd3d_tessellator_domain sm6_parser_ds_properties_init(struct sm6_pa }
sm6_parser_emit_dcl_tessellator_domain(sm6, operands[0]); - sm6_parser_validate_control_point_count(sm6, operands[1]); + sm6_parser_validate_control_point_count(sm6, operands[1], "Domain shader input"); sm6->p.program.input_control_point_count = operands[1];
return operands[0]; }
+static enum vkd3d_tessellator_domain sm6_parser_hs_properties_init(struct sm6_parser *sm6, + const struct sm6_metadata_value *m) +{ + const struct sm6_metadata_node *node; + unsigned int operands[6] = {0}; + unsigned int i; + + if (!m || !sm6_metadata_value_is_node(m)) + { + WARN("Missing or invalid HS properties.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "Hull shader properties node is missing or invalid."); + return 0; + } + + node = m->u.node; + if (node->operand_count < 7) + { + WARN("Invalid operand count %u.\n", node->operand_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + "Hull shader properties operand count %u is invalid.", node->operand_count); + return 0; + } + if (node->operand_count > 7) + { + WARN("Ignoring %u extra operands.\n", node->operand_count - 7); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring %u extra operands for hull shader properties.", node->operand_count - 7); + } + + m = node->operands[0]; + if (!sm6_metadata_value_is_value(m) || !sm6_value_is_function_dcl(m->u.value)) + { + WARN("Patch constant function node is not a function value.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "Hull shader patch constant function node is not a function value."); + } + else + { + sm6->patch_constant_function = m->u.value->u.function.name; + } + + for (i = 1; i < min(node->operand_count, ARRAY_SIZE(operands)); ++i) + { + if (!sm6_metadata_get_uint_value(sm6, node->operands[i], &operands[i])) + { + WARN("HS property at index %u is not a uint value.\n", i); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES, + "Hull shader properties operand at index %u is not an integer.", i); + } + } + + sm6_parser_validate_control_point_count(sm6, operands[1], "Hull shader input"); + sm6->p.program.input_control_point_count = operands[1]; + sm6_parser_validate_control_point_count(sm6, operands[2], "Hull shader output"); + sm6_parser_emit_dcl_count(sm6, VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT, operands[2]); + sm6->p.program.output_control_point_count = operands[2]; + sm6_parser_emit_dcl_tessellator_domain(sm6, operands[3]); + sm6_parser_emit_dcl_tessellator_partitioning(sm6, operands[4]); + sm6_parser_emit_dcl_tessellator_output_primitive(sm6, operands[5]); + sm6_parser_emit_dcl_max_tessellation_factor(sm6, node->operands[6]); + + return operands[3]; +} + static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6) { const struct sm6_metadata_value *m = sm6_parser_find_named_metadata(sm6, "dx.entryPoints"); @@ -8758,6 +8926,9 @@ static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6) case SHADER_PROPERTIES_DOMAIN: tessellator_domain = sm6_parser_ds_properties_init(sm6, node->operands[i + 1]); break; + case SHADER_PROPERTIES_HULL: + tessellator_domain = sm6_parser_hs_properties_init(sm6, node->operands[i + 1]); + break; case SHADER_PROPERTIES_COMPUTE: if ((ret = sm6_parser_emit_thread_group(sm6, node->operands[i + 1])) < 0) return ret; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 46130244c..62f17be51 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -223,11 +223,6 @@ enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d } }
-static bool data_type_is_floating_point(enum vkd3d_data_type data_type) -{ - return data_type == VKD3D_DATA_HALF || data_type == VKD3D_DATA_FLOAT || data_type == VKD3D_DATA_DOUBLE; -} - #define VKD3D_SPIRV_VERSION 0x00010000 #define VKD3D_SPIRV_GENERATOR_ID 18 #define VKD3D_SPIRV_GENERATOR_VERSION 11 diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 6eda2039f..9b2fae0c8 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -641,6 +641,11 @@ static inline bool data_type_is_bool(enum vkd3d_data_type data_type) return data_type == VKD3D_DATA_BOOL; }
+static inline bool data_type_is_floating_point(enum vkd3d_data_type data_type) +{ + return data_type == VKD3D_DATA_HALF || data_type == VKD3D_DATA_FLOAT || data_type == VKD3D_DATA_DOUBLE; +} + static inline bool data_type_is_64_bit(enum vkd3d_data_type data_type) { return data_type == VKD3D_DATA_DOUBLE || data_type == VKD3D_DATA_UINT64;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 1333c55b8..062d912b0 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -415,6 +415,7 @@ enum dx_intrinsic_opcode DX_FLATTENED_THREAD_ID_IN_GROUP = 96, DX_MAKE_DOUBLE = 101, DX_SPLIT_DOUBLE = 102, + DX_PRIMITIVE_ID = 108, DX_LEGACY_F32TOF16 = 130, DX_LEGACY_F16TOF32 = 131, DX_RAW_BUFFER_LOAD = 139, @@ -4428,6 +4429,22 @@ static void sm6_parser_dcl_register_builtin(struct sm6_parser *sm6, } }
+static void sm6_parser_emit_dx_input_register_mov(struct sm6_parser *sm6, + struct vkd3d_shader_instruction *ins, enum vkd3d_shader_register_type reg_type, enum vkd3d_data_type data_type) +{ + struct vkd3d_shader_src_param *src_param; + + vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV); + + if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + return; + sm6_parser_dcl_register_builtin(sm6, reg_type, data_type, 1); + vsir_register_init(&src_param->reg, reg_type, data_type, 0); + src_param_init(src_param); + + instruction_dst_param_init_ssa_scalar(ins, sm6); +} + static const struct sm6_descriptor_info *sm6_parser_get_descriptor(struct sm6_parser *sm6, enum vkd3d_shader_descriptor_type type, unsigned int id, const struct sm6_value *address) { @@ -4789,6 +4806,12 @@ static void sm6_parser_emit_dx_make_double(struct sm6_parser *sm6, enum dx_intri instruction_dst_param_init_ssa_scalar(ins, sm6); }
+static void sm6_parser_emit_dx_primitive_id(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, + const struct sm6_value **operands, struct function_emission_state *state) +{ + sm6_parser_emit_dx_input_register_mov(sm6, state->ins, VKD3DSPR_PRIMID, VKD3D_DATA_UINT); +} + static void sm6_parser_emit_dx_raw_buffer_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { @@ -5450,6 +5473,7 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = [DX_LOAD_INPUT ] = {"o", "ii8i", sm6_parser_emit_dx_load_input}, [DX_LOG ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_MAKE_DOUBLE ] = {"d", "ii", sm6_parser_emit_dx_make_double}, + [DX_PRIMITIVE_ID ] = {"i", "", sm6_parser_emit_dx_primitive_id}, [DX_RAW_BUFFER_LOAD ] = {"o", "Hii8i", sm6_parser_emit_dx_raw_buffer_load}, [DX_RAW_BUFFER_STORE ] = {"v", "Hiioooocc", sm6_parser_emit_dx_raw_buffer_store}, [DX_ROUND_NE ] = {"g", "R", sm6_parser_emit_dx_unary},
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 95 +++++++++++++++++++----- libs/vkd3d-shader/ir.c | 14 +++- libs/vkd3d-shader/vkd3d_shader_private.h | 10 +++ 3 files changed, 101 insertions(+), 18 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 062d912b0..b710768f2 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -795,6 +795,7 @@ struct sm6_parser
struct vkd3d_shader_dst_param *output_params; struct vkd3d_shader_dst_param *input_params; + struct vkd3d_shader_dst_param *patch_constant_params; uint32_t input_regs_declared[(VKD3DSPR_COUNT + 0x1f) / 0x20];
struct sm6_function *functions; @@ -2492,7 +2493,7 @@ static size_t sm6_parser_compute_max_value_count(struct sm6_parser *sm6, * overestimate the value count somewhat, but this should be no problem. */ value_count = size_add_with_overflow_check(value_count, max(block->record_count, 1u) - 1); sm6->value_capacity = max(sm6->value_capacity, value_count); - sm6->functions[sm6->function_count].value_count = value_count; + sm6->functions[sm6->function_count++].value_count = value_count; /* The value count returns to its previous value after handling a function. */ if (value_count < SIZE_MAX) value_count = old_value_count; @@ -3496,12 +3497,19 @@ static void src_params_init_from_operands(struct vkd3d_shader_src_param *src_par }
static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shader_signature *s, - enum vkd3d_shader_register_type reg_type, struct vkd3d_shader_dst_param *params) + bool is_input, enum vkd3d_shader_register_type reg_type, struct vkd3d_shader_dst_param *params) { + enum vkd3d_shader_type shader_type = sm6->p.program.shader_version.type; + bool is_patch_constant, is_control_point; struct vkd3d_shader_dst_param *param; const struct signature_element *e; unsigned int i, count;
+ is_patch_constant = reg_type == VKD3DSPR_PATCHCONST; + is_control_point = !is_patch_constant && ((is_input && (shader_type == VKD3D_SHADER_TYPE_HULL + || shader_type == VKD3D_SHADER_TYPE_DOMAIN || shader_type == VKD3D_SHADER_TYPE_GEOMETRY)) + || (!is_input && !is_patch_constant && shader_type == VKD3D_SHADER_TYPE_HULL)); + for (i = 0; i < s->element_count; ++i) { e = &s->elements[i]; @@ -3509,8 +3517,15 @@ static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shade param = ¶ms[i]; dst_param_io_init(param, e, reg_type); count = 0; - if (e->register_count > 1) + if (is_control_point) + { + if (reg_type == VKD3DSPR_OUTPUT) + param->reg.idx[count].rel_addr = instruction_array_create_outpointid_param(&sm6->p.program.instructions); param->reg.idx[count++].offset = 0; + } + if (e->register_count > 1 || (is_patch_constant && sysval_semantic_is_tess_factor(e->sysval_semantic))) + param->reg.idx[count++].offset = 0; + assert(count < ARRAY_SIZE(param->reg.idx)); param->reg.idx[count++].offset = i; param->reg.idx_count = count; } @@ -3518,12 +3533,21 @@ static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shade
static void sm6_parser_init_output_signature(struct sm6_parser *sm6, const struct shader_signature *output_signature) { - sm6_parser_init_signature(sm6, output_signature, VKD3DSPR_OUTPUT, sm6->output_params); + sm6_parser_init_signature(sm6, output_signature, false, VKD3DSPR_OUTPUT, sm6->output_params); }
static void sm6_parser_init_input_signature(struct sm6_parser *sm6, const struct shader_signature *input_signature) { - sm6_parser_init_signature(sm6, input_signature, VKD3DSPR_INPUT, sm6->input_params); + sm6_parser_init_signature(sm6, input_signature, true, VKD3DSPR_INPUT, sm6->input_params); +} + +static void sm6_parser_init_patch_constant_signature(struct sm6_parser *sm6, + const struct shader_signature *patch_constant_signature) +{ + bool is_input = sm6->p.program.shader_version.type == VKD3D_SHADER_TYPE_DOMAIN; + + sm6_parser_init_signature(sm6, patch_constant_signature, is_input, VKD3DSPR_PATCHCONST, + sm6->patch_constant_params); }
static const struct sm6_value *sm6_parser_next_function_definition(struct sm6_parser *sm6) @@ -6908,11 +6932,6 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct sm6_block *code_block; struct sm6_value *dst;
- if (sm6->function_count) - { - FIXME("Multiple functions are not supported yet.\n"); - return VKD3D_ERROR_INVALID_SHADER; - } if (!(function->declaration = sm6_parser_next_function_definition(sm6))) { WARN("Failed to find definition to match function body.\n"); @@ -8576,10 +8595,15 @@ static enum vkd3d_result sm6_parser_signatures_init(struct sm6_parser *sm6, cons { return ret; } - /* TODO: patch constant signature in operand 2. */ + if (m->u.node->operand_count > 1 && (ret = sm6_parser_read_signature(sm6, m->u.node->operands[2], + &sm6->p.program.patch_constant_signature, tessellator_domain)) < 0) + { + return ret; + }
sm6_parser_init_input_signature(sm6, &sm6->p.program.input_signature); sm6_parser_init_output_signature(sm6, &sm6->p.program.output_signature); + sm6_parser_init_patch_constant_signature(sm6, &sm6->p.program.patch_constant_signature);
return VKD3D_OK; } @@ -9109,9 +9133,10 @@ static struct sm6_function *sm6_parser_get_function(const struct sm6_parser *sm6 static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const char *source_name, struct vkd3d_shader_message_context *message_context, struct dxbc_shader_desc *dxbc_desc) { + size_t count, length, function_count, expected_function_count, byte_code_size = dxbc_desc->byte_code_size; + const struct shader_signature *patch_constant_signature = &sm6->p.program.patch_constant_signature; const struct shader_signature *output_signature = &sm6->p.program.output_signature; const struct shader_signature *input_signature = &sm6->p.program.input_signature; - size_t count, length, function_count, byte_code_size = dxbc_desc->byte_code_size; const struct vkd3d_shader_location location = {.source_name = source_name}; uint32_t version_token, dxil_version, token_count, magic; const uint32_t *byte_code = dxbc_desc->byte_code; @@ -9274,7 +9299,9 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const char *sou }
if (!(sm6->output_params = vsir_program_get_dst_params(&sm6->p.program, output_signature->element_count)) - || !(sm6->input_params = vsir_program_get_dst_params(&sm6->p.program, input_signature->element_count))) + || !(sm6->input_params = vsir_program_get_dst_params(&sm6->p.program, input_signature->element_count)) + || !(sm6->patch_constant_params = vsir_program_get_dst_params(&sm6->p.program, + patch_constant_signature->element_count))) { ERR("Failed to allocate input/output parameters.\n"); vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, @@ -9305,6 +9332,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const char *sou "Out of memory allocating DXIL value array."); return VKD3D_ERROR_OUT_OF_MEMORY; } + sm6->function_count = 0; sm6->ssa_next_id = 1;
if ((ret = sm6_parser_globals_init(sm6)) < 0) @@ -9354,7 +9382,8 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const char *sou return ret; }
- if (!sm6_parser_require_space(sm6, output_signature->element_count + input_signature->element_count)) + if (!sm6_parser_require_space(sm6, output_signature->element_count + input_signature->element_count + + patch_constant_signature->element_count)) { vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, "Out of memory emitting shader signature declarations."); @@ -9371,9 +9400,41 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const char *sou return VKD3D_ERROR_INVALID_SHADER; }
- assert(sm6->function_count == 1); - if ((ret = sm6_function_emit_blocks(fn, sm6)) < 0) - return ret; + if (version.type == VKD3D_SHADER_TYPE_HULL) + { + sm6_parser_add_instruction(sm6, VKD3DSIH_HS_CONTROL_POINT_PHASE); + + if ((ret = sm6_function_emit_blocks(fn, sm6)) < 0) + return ret; + + if (!(fn = sm6_parser_get_function(sm6, sm6->patch_constant_function))) + { + WARN("Failed to find patch constant function '%s'.\n", sm6->patch_constant_function); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + "Failed to find the patch constant function '%s' for a hull shader.", + sm6->patch_constant_function); + return VKD3D_ERROR_INVALID_SHADER; + } + + sm6_parser_add_instruction(sm6, VKD3DSIH_HS_FORK_PHASE); + if ((ret = sm6_function_emit_blocks(fn, sm6)) < 0) + return ret; + + expected_function_count = 2; + } + else + { + if ((ret = sm6_function_emit_blocks(fn, sm6)) < 0) + return ret; + expected_function_count = 1; + } + + if (sm6->function_count > expected_function_count) + { + FIXME("%zu unhandled functions.\n", sm6->function_count - expected_function_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + "%zu functions were not emitted.", sm6->function_count - expected_function_count); + }
dxil_block_destroy(&sm6->root_block);
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 7786db055..e92149fbd 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -569,11 +569,14 @@ static bool control_point_normaliser_is_in_control_point_phase(const struct cont return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE; }
-static struct vkd3d_shader_src_param *instruction_array_create_outpointid_param( +struct vkd3d_shader_src_param *instruction_array_create_outpointid_param( struct vkd3d_shader_instruction_array *instructions) { struct vkd3d_shader_src_param *rel_addr;
+ if (instructions->outpointid_param) + return instructions->outpointid_param; + if (!(rel_addr = shader_src_param_allocator_get(&instructions->src_params, 1))) return NULL;
@@ -581,6 +584,7 @@ static struct vkd3d_shader_src_param *instruction_array_create_outpointid_param( rel_addr->swizzle = 0; rel_addr->modifiers = 0;
+ instructions->outpointid_param = rel_addr; return rel_addr; }
@@ -3408,6 +3412,14 @@ static enum vkd3d_result vsir_cfg_init(struct vsir_cfg *cfg, struct vsir_program enum vkd3d_result ret; size_t i;
+ if (program->shader_version.type == VKD3D_SHADER_TYPE_HULL) + { + FIXME("Hull shaders are not supported.\n"); + vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, + "The structurizer does not support hull shaders."); + return VKD3D_ERROR_INVALID_SHADER; + } + memset(cfg, 0, sizeof(*cfg)); cfg->message_context = message_context; cfg->program = program; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 41c828624..33f80093a 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1299,6 +1299,8 @@ struct vkd3d_shader_instruction_array struct vkd3d_shader_immediate_constant_buffer **icbs; size_t icb_capacity; size_t icb_count; + + struct vkd3d_shader_src_param *outpointid_param; };
bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve); @@ -1309,6 +1311,8 @@ bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *ins struct vkd3d_shader_immediate_constant_buffer *icb); bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, unsigned int dst, unsigned int src); +struct vkd3d_shader_src_param *instruction_array_create_outpointid_param( + struct vkd3d_shader_instruction_array *instructions); void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions);
enum vkd3d_shader_config_flags @@ -1632,6 +1636,12 @@ static inline bool component_type_is_64_bit(enum vkd3d_shader_component_type com return component_type == VKD3D_SHADER_COMPONENT_DOUBLE || component_type == VKD3D_SHADER_COMPONENT_UINT64; }
+static inline bool sysval_semantic_is_tess_factor(enum vkd3d_shader_sysval_semantic sysval_semantic) +{ + return sysval_semantic >= VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE + && sysval_semantic <= VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN; +} + enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d_shader_sysval_semantic sysval, unsigned int index);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/ir.c | 40 ++++++++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 2 files changed, 41 insertions(+)
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 8af537390..7786db055 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -5078,6 +5078,46 @@ static void vsir_validate_instruction(struct validation_context *ctx) ctx->dcl_temps_found = false; return;
+ case VKD3DSIH_DCL_HS_MAX_TESSFACTOR: + /* Exclude non-finite values. */ + if (!(instruction->declaration.max_tessellation_factor >= 1.0f + && instruction->declaration.max_tessellation_factor <= 64.0f)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, "Max tessellation factor %f is invalid.", + instruction->declaration.max_tessellation_factor); + return; + + /* The DXIL parser can generate these outside phases, but this is not an issue. */ + case VKD3DSIH_DCL_INPUT: + case VKD3DSIH_DCL_OUTPUT: + return; + + case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT: + if (!instruction->declaration.count || instruction->declaration.count > 32) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, "Output control point count %u is invalid.", + instruction->declaration.count); + return; + + case VKD3DSIH_DCL_TESSELLATOR_DOMAIN: + if (instruction->declaration.tessellator_domain == VKD3D_TESSELLATOR_DOMAIN_INVALID + || instruction->declaration.tessellator_domain >= VKD3D_TESSELLATOR_DOMAIN_COUNT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "Tessellator domain %#x is invalid.", instruction->declaration.tessellator_domain); + return; + + case VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE: + if (!instruction->declaration.tessellator_output_primitive + || instruction->declaration.tessellator_output_primitive > VKD3D_SHADER_TESSELLATOR_OUTPUT_TRIANGLE_CCW) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "Tessellator output primitive %#x is invalid.", instruction->declaration.tessellator_output_primitive); + return; + + case VKD3DSIH_DCL_TESSELLATOR_PARTITIONING: + if (!instruction->declaration.tessellator_partitioning + || instruction->declaration.tessellator_partitioning > VKD3D_SHADER_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION, + "Tessellator partitioning %#x is invalid.", instruction->declaration.tessellator_partitioning); + return; + default: break; } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 9b2fae0c8..41c828624 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -220,6 +220,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX = 9015, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW = 9016, VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE = 9017, + VKD3D_SHADER_ERROR_VSIR_INVALID_TESSELLATION = 9018,
VKD3D_SHADER_WARNING_VSIR_DYNAMIC_DESCRIPTOR_ARRAY = 9300, };
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index b710768f2..848623830 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -415,6 +415,8 @@ enum dx_intrinsic_opcode DX_FLATTENED_THREAD_ID_IN_GROUP = 96, DX_MAKE_DOUBLE = 101, DX_SPLIT_DOUBLE = 102, + DX_LOAD_OUTPUT_CONTROL_POINT = 103, + DX_LOAD_PATCH_CONSTANT = 104, DX_PRIMITIVE_ID = 108, DX_LEGACY_F32TOF16 = 130, DX_LEGACY_F16TOF32 = 131, @@ -2411,10 +2413,12 @@ static void register_index_address_init(struct vkd3d_shader_register_index *idx, if (sm6_value_is_constant(address)) { idx->offset = sm6_value_get_constant_uint(address); + idx->rel_addr = NULL; } else if (sm6_value_is_undef(address)) { idx->offset = 0; + idx->rel_addr = NULL; } else { @@ -4779,18 +4783,36 @@ static void sm6_parser_emit_dx_tertiary(struct sm6_parser *sm6, enum dx_intrinsi static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { + bool is_control_point = op == DX_LOAD_OUTPUT_CONTROL_POINT; + bool is_patch_constant = op == DX_LOAD_PATCH_CONSTANT; struct vkd3d_shader_instruction *ins = state->ins; + const struct vkd3d_shader_dst_param *params; struct vkd3d_shader_src_param *src_param; const struct shader_signature *signature; - unsigned int row_index, column_index; + unsigned int i, row_index, column_index; const struct signature_element *e;
row_index = sm6_value_get_constant_uint(operands[0]); column_index = sm6_value_get_constant_uint(operands[2]); + assert(!is_control_point || !operands[3]->is_undefined);
vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV);
- signature = &sm6->p.program.input_signature; + if (is_patch_constant) + { + signature = &sm6->p.program.patch_constant_signature; + params = sm6->patch_constant_params; + } + else if (is_control_point) + { + signature = &sm6->p.program.output_signature; + params = sm6->output_params; + } + else + { + signature = &sm6->p.program.input_signature; + params = sm6->input_params; + } if (row_index >= signature->element_count) { WARN("Invalid row index %u.\n", row_index); @@ -4802,10 +4824,16 @@ static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, enum dx_intrin
if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) return; - src_param->reg = sm6->input_params[row_index].reg; + src_param->reg = params[row_index].reg; src_param_init_scalar(src_param, column_index); + i = 0; if (e->register_count > 1) - register_index_address_init(&src_param->reg.idx[0], operands[1], sm6); + register_index_address_init(&src_param->reg.idx[i++], operands[1], sm6); + if (is_control_point) + { + assert(src_param->reg.idx_count > i); + register_index_address_init(&src_param->reg.idx[i], operands[3], sm6); + }
instruction_dst_param_init_ssa_scalar(ins, sm6); } @@ -5495,6 +5523,8 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = [DX_LEGACY_F16TOF32 ] = {"f", "i", sm6_parser_emit_dx_unary}, [DX_LEGACY_F32TOF16 ] = {"i", "f", sm6_parser_emit_dx_unary}, [DX_LOAD_INPUT ] = {"o", "ii8i", sm6_parser_emit_dx_load_input}, + [DX_LOAD_OUTPUT_CONTROL_POINT ] = {"o", "ii8i", sm6_parser_emit_dx_load_input}, + [DX_LOAD_PATCH_CONSTANT ] = {"o", "ii8", sm6_parser_emit_dx_load_input}, [DX_LOG ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_MAKE_DOUBLE ] = {"d", "ii", sm6_parser_emit_dx_make_double}, [DX_PRIMITIVE_ID ] = {"i", "", sm6_parser_emit_dx_primitive_id},
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 848623830..454e371be 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -417,6 +417,7 @@ enum dx_intrinsic_opcode DX_SPLIT_DOUBLE = 102, DX_LOAD_OUTPUT_CONTROL_POINT = 103, DX_LOAD_PATCH_CONSTANT = 104, + DX_STORE_PATCH_CONSTANT = 106, DX_PRIMITIVE_ID = 108, DX_LEGACY_F32TOF16 = 130, DX_LEGACY_F16TOF32 = 131, @@ -5238,6 +5239,7 @@ static void sm6_parser_emit_dx_split_double(struct sm6_parser *sm6, enum dx_intr static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { + bool is_patch_constant = op == DX_STORE_PATCH_CONSTANT; struct vkd3d_shader_instruction *ins = state->ins; struct vkd3d_shader_src_param *src_param; struct vkd3d_shader_dst_param *dst_param; @@ -5249,7 +5251,7 @@ static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, enum dx_intr row_index = sm6_value_get_constant_uint(operands[0]); column_index = sm6_value_get_constant_uint(operands[2]);
- signature = &sm6->p.program.output_signature; + signature = is_patch_constant ? &sm6->p.program.patch_constant_signature : &sm6->p.program.output_signature; if (row_index >= signature->element_count) { WARN("Invalid row index %u.\n", row_index); @@ -5281,7 +5283,7 @@ static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, enum dx_intr if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6))) return; dst_param_init_scalar(dst_param, column_index); - dst_param->reg = sm6->output_params[row_index].reg; + dst_param->reg = is_patch_constant ? sm6->patch_constant_params[row_index].reg : sm6->output_params[row_index].reg; if (e->register_count > 1) register_index_address_init(&dst_param->reg.idx[0], operands[1], sm6);
@@ -5546,6 +5548,7 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = [DX_SPLIT_DOUBLE ] = {"S", "d", sm6_parser_emit_dx_split_double}, [DX_SQRT ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_STORE_OUTPUT ] = {"v", "ii8o", sm6_parser_emit_dx_store_output}, + [DX_STORE_PATCH_CONSTANT ] = {"v", "ii8o", sm6_parser_emit_dx_store_output}, [DX_TAN ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_TEXTURE_GATHER ] = {"o", "HHffffiic", sm6_parser_emit_dx_texture_gather}, [DX_TEXTURE_GATHER_CMP ] = {"o", "HHffffiicf", sm6_parser_emit_dx_texture_gather},
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 454e371be..729b8d681 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -417,6 +417,7 @@ enum dx_intrinsic_opcode DX_SPLIT_DOUBLE = 102, DX_LOAD_OUTPUT_CONTROL_POINT = 103, DX_LOAD_PATCH_CONSTANT = 104, + DX_DOMAIN_LOCATION = 105, DX_STORE_PATCH_CONSTANT = 106, DX_PRIMITIVE_ID = 108, DX_LEGACY_F32TOF16 = 130, @@ -4547,6 +4548,24 @@ static void sm6_parser_emit_dx_discard(struct sm6_parser *sm6, enum dx_intrinsic src_param_init_from_value(src_param, operands[0]); }
+static void sm6_parser_emit_dx_domain_location(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, + const struct sm6_value **operands, struct function_emission_state *state) +{ + struct vkd3d_shader_instruction *ins = state->ins; + struct vkd3d_shader_src_param *src_param; + + sm6_parser_dcl_register_builtin(sm6, VKD3DSPR_TESSCOORD, VKD3D_DATA_FLOAT, 3); + + vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV); + if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + return; + vsir_register_init(&src_param->reg, VKD3DSPR_TESSCOORD, VKD3D_DATA_FLOAT, 0); + src_param->reg.dimension = VSIR_DIMENSION_VEC4; + src_param_init_scalar(src_param, sm6_value_get_constant_uint(operands[0])); + + instruction_dst_param_init_ssa_scalar(ins, sm6); +} + static void sm6_parser_emit_dx_dot(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { @@ -5496,6 +5515,7 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = [DX_DERIV_FINEX ] = {"e", "R", sm6_parser_emit_dx_unary}, [DX_DERIV_FINEY ] = {"e", "R", sm6_parser_emit_dx_unary}, [DX_DISCARD ] = {"v", "1", sm6_parser_emit_dx_discard}, + [DX_DOMAIN_LOCATION ] = {"f", "c", sm6_parser_emit_dx_domain_location}, [DX_DOT2 ] = {"g", "RRRR", sm6_parser_emit_dx_dot}, [DX_DOT3 ] = {"g", "RRRRRR", sm6_parser_emit_dx_dot}, [DX_DOT4 ] = {"g", "RRRRRRRR", sm6_parser_emit_dx_dot},
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 729b8d681..4e9d2e145 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -419,6 +419,7 @@ enum dx_intrinsic_opcode DX_LOAD_PATCH_CONSTANT = 104, DX_DOMAIN_LOCATION = 105, DX_STORE_PATCH_CONSTANT = 106, + DX_OUTPUT_CONTROL_POINT_ID = 107, DX_PRIMITIVE_ID = 108, DX_LEGACY_F32TOF16 = 130, DX_LEGACY_F16TOF32 = 131, @@ -4878,6 +4879,12 @@ static void sm6_parser_emit_dx_make_double(struct sm6_parser *sm6, enum dx_intri instruction_dst_param_init_ssa_scalar(ins, sm6); }
+static void sm6_parser_emit_dx_output_control_point_id(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, + const struct sm6_value **operands, struct function_emission_state *state) +{ + sm6_parser_emit_dx_input_register_mov(sm6, state->ins, VKD3DSPR_OUTPOINTID, VKD3D_DATA_UINT); +} + static void sm6_parser_emit_dx_primitive_id(struct sm6_parser *sm6, enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct function_emission_state *state) { @@ -5549,6 +5556,7 @@ static const struct sm6_dx_opcode_info sm6_dx_op_table[] = [DX_LOAD_PATCH_CONSTANT ] = {"o", "ii8", sm6_parser_emit_dx_load_input}, [DX_LOG ] = {"g", "R", sm6_parser_emit_dx_unary}, [DX_MAKE_DOUBLE ] = {"d", "ii", sm6_parser_emit_dx_make_double}, + [DX_OUTPUT_CONTROL_POINT_ID ] = {"i", "", sm6_parser_emit_dx_output_control_point_id}, [DX_PRIMITIVE_ID ] = {"i", "", sm6_parser_emit_dx_primitive_id}, [DX_RAW_BUFFER_LOAD ] = {"o", "Hii8i", sm6_parser_emit_dx_raw_buffer_load}, [DX_RAW_BUFFER_STORE ] = {"v", "Hiioooocc", sm6_parser_emit_dx_raw_buffer_store},