diff --git a/Makefile.am b/Makefile.am index f8c3c83a2..83acddb60 100644 --- a/Makefile.am +++ b/Makefile.am @@ -302,6 +302,7 @@ vkd3d_shader_tests = \ tests/hlsl/vector-indexing-uniform.shader_test \ tests/hlsl/vector-indexing.shader_test \ tests/hlsl/vertex-shader-ops.shader_test \ + tests/hlsl/vp-array-index.shader_test \ tests/hlsl/wave-ops-float.shader_test \ tests/hlsl/wave-ops-int.shader_test \ tests/hlsl/wave-ops-uint.shader_test \ diff --git a/tests/d3d12.c b/tests/d3d12.c index cc22a5bf6..a5c6c2aef 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -28673,103 +28673,6 @@ static void test_ps_layer(void) ID3D10Blob_Release(ps_bytecode); } -static void test_ps_viewport_index(void) -{ - ID3D12GraphicsCommandList *command_list; - ID3D10Blob *vs_bytecode, *ps_bytecode; - struct test_context_desc desc; - D3D12_SHADER_BYTECODE vs, ps; - struct test_context context; - D3D12_VIEWPORT viewports[4]; - ID3D12CommandQueue *queue; - D3D12_BOX box; - - static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f}; - static const char vs_code[] = - "float4 main(in uint vertex_id : SV_VertexID, in uint instance_id : SV_InstanceID,\n" - " out uint viewport : SV_ViewportArrayIndex) : SV_Position\n" - "{\n" - " viewport = instance_id;\n" - " switch (vertex_id)\n" - " {\n" - " case 0:\n" - " return float4(-1, 1, 0, 1);\n" - " case 1:\n" - " return float4(3, 1, 0, 1);\n" - " case 2:\n" - " return float4(-1, -3, 0, 1);\n" - " default:\n" - " return float4(0, 0, 0, 0);\n" - " }\n" - "}\n"; - static const char ps_code[] = - "float4 main(float4 p : SV_Position, uint viewport : SV_ViewportArrayIndex) : SV_Target0\n" - "{\n" - " return viewport / 255.0;\n" - "}\n"; - - vs_bytecode = compile_shader(vs_code, sizeof(vs_code) - 1, "vs_4_0"); - vs = shader_bytecode_from_blob(vs_bytecode); - - ps_bytecode = compile_shader(ps_code, sizeof(ps_code) - 1, "ps_4_0"); - ps = shader_bytecode_from_blob(ps_bytecode); - - memset(&desc, 0, sizeof(desc)); - desc.vs = &vs; - desc.ps = &ps; - if (!init_test_context(&context, &desc)) - { - ID3D10Blob_Release(vs_bytecode); - ID3D10Blob_Release(ps_bytecode); - return; - } - - if (!is_vs_array_index_supported(context.device)) - { - skip("The device does not support SV_ViewportArrayIndex in VS.\n"); - destroy_test_context(&context); - return; - } - - command_list = context.list; - queue = context.queue; - - ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL); - - set_viewport(&viewports[0], - 0.0f, 0.0f, - context.render_target_desc.Width / 2, context.render_target_desc.Height / 2, 0.0f, 1.0f); - set_viewport(&viewports[1], - context.render_target_desc.Width / 2, 0.0f, - context.render_target_desc.Width, context.render_target_desc.Height / 2, 0.0f, 1.0f); - set_viewport(&viewports[2], - 0.0f, context.render_target_desc.Height / 2, - context.render_target_desc.Width / 2, context.render_target_desc.Height, 0.0f, 1.0f); - set_viewport(&viewports[3], - context.render_target_desc.Width / 2, context.render_target_desc.Height / 2, - context.render_target_desc.Width, context.render_target_desc.Height, 0.0f, 1.0f); - - ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, NULL); - ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect); - ID3D12GraphicsCommandList_RSSetViewports(command_list, ARRAY_SIZE(viewports), viewports); - ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature); - ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state); - ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 4, 0, 0); - - transition_resource_state(command_list, context.render_target, - D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); - - set_box(&box, 0, 0, 0, context.render_target_desc.Width / 2, context.render_target_desc.Height / 2, 1); - check_sub_resource_uint_with_box(context.render_target, 0, queue, command_list, &box, 0x00000000, 0); - reset_command_list(command_list, context.allocator); - - destroy_test_context(&context); - - ID3D10Blob_Release(vs_bytecode); - ID3D10Blob_Release(ps_bytecode); -} - static void test_nop_tessellation_shaders(void) { static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f}; @@ -39404,7 +39307,6 @@ START_TEST(d3d12) run_test(test_geometry_shader); run_test(test_layered_rendering); run_test(test_ps_layer); - run_test(test_ps_viewport_index); run_test(test_nop_tessellation_shaders); run_test(test_quad_tessellation); run_test(test_tessellation_dcl_index_range); diff --git a/tests/hlsl/vp-array-index.shader_test b/tests/hlsl/vp-array-index.shader_test new file mode 100644 index 000000000..ce8d891e2 --- /dev/null +++ b/tests/hlsl/vp-array-index.shader_test @@ -0,0 +1,43 @@ +[require] +shader model >= 4.0 +rt-vp-array-index + +[rtv 0] +format r32g32b32a32-float +size (2d, 640, 480) + +[vertex shader] +float4 main(in uint vertex_id : SV_VertexID, in uint instance_id : SV_InstanceID, + out uint viewport : SV_ViewportArrayIndex) : SV_Position +{ + viewport = instance_id; + switch (vertex_id) + { + case 0: + return float4(-1, 1, 0, 1); + case 1: + return float4(3, 1, 0, 1); + case 2: + return float4(-1, -3, 0, 1); + default: + return float4(0, 0, 0, 0); + } +} + +[pixel shader] +float4 main(float4 p : SV_Position, uint viewport : SV_ViewportArrayIndex) : SV_Target +{ + return float4(viewport / 4.0, 0.0, 0.0, 1.0); +} + +[test] +viewport 0 ( 0.0, 0.0, 320.0, 240.0) +viewport 1 (320.0, 0.0, 320.0, 240.0) +viewport 2 ( 0.0, 240.0, 320.0, 240.0) +viewport 3 (320.0, 240.0, 320.0, 240.0) +clear rtv 0 1.0 1.0 1.0 1.0 +todo(sm>=6 | glsl) draw triangle list 3 4 +probe rtv 0 (160, 120) f32(0.0, 0.0, 0.0, 1.0) +probe rtv 0 (480, 120) f32(0.25, 0.0, 0.0, 1.0) +probe rtv 0 (160, 360) f32(0.5, 0.0, 0.0, 1.0) +probe rtv 0 (480, 360) f32(0.75, 0.0, 0.0, 1.0) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index da063ea6c..1d1ad6cb5 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -1603,6 +1603,20 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) if (sscanf(line, "%f %f %f %f", &v->x, &v->y, &v->z, &v->w) < 4) fatal_error("Malformed float4 constant '%s'.\n", line); } + else if (match_string(line, "viewport", &line)) + { + unsigned int i; + + read_uint(&line, &i, false); + if (i >= ARRAY_SIZE(runner->viewports)) + fatal_error("Unhandled viewport index %u.\n", i); + + if (sscanf(line, " ( %f , %f , %f , %f )", &runner->viewports[i].x, &runner->viewports[i].y, + &runner->viewports[i].width, &runner->viewports[i].height) < 4) + fatal_error("Malformed viewport '%s'.\n", line); + + runner->viewport_count = max(runner->viewport_count, i + 1); + } else { fatal_error("Unknown test directive '%s'.\n", line); diff --git a/tests/shader_runner.h b/tests/shader_runner.h index f6a0d4f9f..d04cd5b36 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -130,6 +130,14 @@ struct input_element unsigned int index; }; +struct viewport +{ + float x; + float y; + float width; + float height; +}; + #define MAX_RESOURCES 32 #define MAX_SAMPLERS 32 #define DXGI_FORMAT_COUNT (DXGI_FORMAT_B4G4R4A4_UNORM + 1) @@ -254,6 +262,9 @@ struct shader_runner enum fog_mode fog_mode; float fog_start, fog_end, fog_density; bool ortho_fog; + + struct viewport viewports[4]; + unsigned int viewport_count; }; struct shader_runner_ops diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index 19444fe16..1aa52385b 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -973,6 +973,21 @@ static bool d3d11_runner_draw(struct shader_runner *r, ID3D11DeviceContext_RSSetState(context, runner->rasterizer_state); set_viewport(context, 0.0f, 0.0f, fb_width, fb_height, 0.0f, 1.0f); + if (r->viewport_count) + { + D3D11_VIEWPORT viewports[ARRAY_SIZE(r->viewports)]; + for (i = 0; i < r->viewport_count; ++i) + { + viewports[i].TopLeftX = r->viewports[i].x; + viewports[i].TopLeftY = r->viewports[i].y; + viewports[i].Width = r->viewports[i].width; + viewports[i].Height = r->viewports[i].height; + viewports[i].MinDepth = 0.0f; + viewports[i].MaxDepth = 1.0f; + } + ID3D11DeviceContext_RSSetViewports(runner->immediate_context, r->viewport_count, viewports); + } + ID3D11DeviceContext_DrawInstanced(context, vertex_count, instance_count, 0, 0); ID3D11PixelShader_Release(ps); diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index 06ea4ddbe..e53f5674e 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -815,10 +815,12 @@ static bool d3d12_runner_draw(struct shader_runner *r, 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}; + unsigned int uniform_index, fb_width, fb_height, rtv_count = 0, viewport_count; ID3D12GraphicsCommandList1 *command_list1 = test_context->list1; - unsigned int uniform_index, fb_width, fb_height, rtv_count = 0; ID3D12GraphicsCommandList *command_list = test_context->list; + D3D12_VIEWPORT viewports[ARRAY_SIZE(r->viewports)]; ID3D12CommandQueue *queue = test_context->queue; + RECT scissor_rects[ARRAY_SIZE(r->viewports)]; ID3D12Device *device = test_context->device; D3D12_CPU_DESCRIPTOR_HANDLE dsv = {0}; ID3D12PipelineState *pso; @@ -941,14 +943,28 @@ static bool d3d12_runner_draw(struct shader_runner *r, } } + set_rect(&test_context->scissor_rect, 0, 0, fb_width, fb_height); + set_viewport(&test_context->viewport, 0.0f, 0.0f, fb_width, fb_height, 0.0f, 1.0f); + viewports[0] = test_context->viewport; + scissor_rects[0] = test_context->scissor_rect; + viewport_count = max(r->viewport_count, 1); + for (i = 0; i < r->viewport_count; ++i) + { + viewports[i].TopLeftX = r->viewports[i].x; + viewports[i].TopLeftY = r->viewports[i].y; + viewports[i].Width = r->viewports[i].width; + viewports[i].Height = r->viewports[i].height; + viewports[i].MinDepth = 0.0f; + viewports[i].MaxDepth = 1.0f; + scissor_rects[i] = test_context->scissor_rect; + } + ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, rtv_count, rtvs, false, dsv.ptr ? &dsv : NULL); if (runner->r.depth_bounds) ID3D12GraphicsCommandList1_OMSetDepthBounds(command_list1, runner->r.depth_min, runner->r.depth_max); - set_rect(&test_context->scissor_rect, 0, 0, fb_width, fb_height); - ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &test_context->scissor_rect); - set_viewport(&test_context->viewport, 0.0f, 0.0f, fb_width, fb_height, 0.0f, 1.0f); - ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &test_context->viewport); + ID3D12GraphicsCommandList_RSSetScissorRects(command_list, viewport_count, scissor_rects); + ID3D12GraphicsCommandList_RSSetViewports(command_list, viewport_count, viewports); ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, primitive_topology); ID3D12GraphicsCommandList_SetPipelineState(command_list, pso); ID3D12GraphicsCommandList_DrawInstanced(command_list, vertex_count, instance_count, 0, 0); diff --git a/tests/shader_runner_d3d9.c b/tests/shader_runner_d3d9.c index c516f9c77..2709c2d9f 100644 --- a/tests/shader_runner_d3d9.c +++ b/tests/shader_runner_d3d9.c @@ -428,6 +428,8 @@ static bool d3d9_runner_draw(struct shader_runner *r, if (instance_count > 1) fatal_error("Unhandled instance count %u.\n", instance_count); + if (r->viewport_count) + fatal_error("Unhandled viewports.\n"); if (!(vs_code = compile_hlsl(&runner->r, SHADER_TYPE_VS))) return false; diff --git a/tests/shader_runner_gl.c b/tests/shader_runner_gl.c index 27db19fcb..6be3aa60f 100644 --- a/tests/shader_runner_gl.c +++ b/tests/shader_runner_gl.c @@ -1355,7 +1355,18 @@ static bool gl_runner_draw(struct shader_runner *r, glEnable(GL_SAMPLE_MASK); glSampleMaski(0, runner->r.sample_mask); - glViewport(0, 0, fb_width, fb_height); + + if (r->viewport_count) + { + for (i = 0; i < r->viewport_count; ++i) + { + glViewportIndexedf(i, r->viewports[i].x, r->viewports[i].y, r->viewports[i].width, r->viewports[i].height); + } + } + else + { + glViewport(0, 0, fb_width, fb_height); + } glScissor(0, 0, fb_width, fb_height); glDrawBuffers(rt_count, draw_buffers); diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index 7156bd7fa..8ce77661a 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -684,18 +684,18 @@ static VkPipeline create_graphics_pipeline(struct vulkan_shader_runner *runner, VkPipelineMultisampleStateCreateInfo ms_desc = {.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; VkPipelineViewportStateCreateInfo vp_desc = {.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; VkGraphicsPipelineCreateInfo pipeline_desc = {.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; - VkViewport viewport = {.y = runner->rt_size.height, .width = runner->rt_size.width, - .height = -(float)runner->rt_size.height, .maxDepth = 1}; + VkViewport viewports[ARRAY_SIZE(runner->r.viewports)] = {{.y = runner->rt_size.height, + .width = runner->rt_size.width, .height = -(float)runner->rt_size.height, .maxDepth = 1}}; + VkRect2D scissor_rects[ARRAY_SIZE(runner->r.viewports)] = {{.extent = runner->rt_size}}; VkPipelineColorBlendAttachmentState attachment_desc[MAX_RESOURCES] = {0}; const struct vulkan_test_context *context = &runner->context; VkPipelineTessellationStateCreateInfo tessellation_info; VkVertexInputAttributeDescription input_attributes[32]; - const VkRect2D rt_rect = {.extent = runner->rt_size}; VkPipelineDepthStencilStateCreateInfo ds_desc = {0}; VkVertexInputBindingDescription input_bindings[32]; VkPipelineShaderStageCreateInfo stage_desc[5]; + unsigned int stage_count = 0, viewport_count; VkDevice device = context->device; - unsigned int stage_count = 0; VkPipeline pipeline; unsigned int i, j; VkResult vr; @@ -819,16 +819,31 @@ static VkPipeline create_graphics_pipeline(struct vulkan_shader_runner *runner, ia_desc.topology = vulkan_primitive_topology_from_d3d(primitive_topology); + viewport_count = max(runner->r.viewport_count, 1); + for (i = 0; i < runner->r.viewport_count; ++i) + { + viewports[i].x = runner->r.viewports[i].x; + viewports[i].y = runner->r.viewports[i].y + runner->r.viewports[i].height; + viewports[i].width = runner->r.viewports[i].width; + viewports[i].height = -runner->r.viewports[i].height; + viewports[i].maxDepth = 1.0f; + scissor_rects[i].offset.x = 0; + scissor_rects[i].offset.y = 0; + scissor_rects[i].extent = runner->rt_size; + } if (runner->r.minimum_shader_model < SHADER_MODEL_4_0) { - viewport.x += 0.5f; - viewport.y += 0.5f; + for (i = 0; i < viewport_count; ++i) + { + viewports[i].x += 0.5f; + viewports[i].y += 0.5f; + } } - vp_desc.viewportCount = 1; - vp_desc.pViewports = &viewport; - vp_desc.scissorCount = 1; - vp_desc.pScissors = &rt_rect; + vp_desc.viewportCount = viewport_count; + vp_desc.pViewports = viewports; + vp_desc.scissorCount = viewport_count; + vp_desc.pScissors = scissor_rects; rs_desc.cullMode = VK_CULL_MODE_NONE; rs_desc.frontFace = VK_FRONT_FACE_CLOCKWISE; @@ -1790,18 +1805,23 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) /* FIXME: Probably make these optional. */ #define ENABLE_FEATURE(x) \ - if (!ret_features->x) \ + do \ { \ - skip("The selected Vulkan device does not support " #x ".\n"); \ - goto out_destroy_context; \ - } \ - features.x = VK_TRUE + if (!ret_features->x) \ + { \ + skip("The selected Vulkan device does not support " #x ".\n"); \ + goto out_destroy_context; \ + } \ + features.x = VK_TRUE; \ + } while (false) ENABLE_FEATURE(fragmentStoresAndAtomics); ENABLE_FEATURE(sampleRateShading); ENABLE_FEATURE(shaderClipDistance); ENABLE_FEATURE(shaderImageGatherExtended); ENABLE_FEATURE(shaderStorageImageWriteWithoutFormat); + if (runner->caps.shader_caps[SHADER_CAP_RT_VP_ARRAY_INDEX]) + ENABLE_FEATURE(multiViewport); if (ret_features->tessellationShader) {