tests: Replace test_ps_viewport_index() with a shader runner test.

Mainly to allow testing the functionality in question with DXIL shaders
as well.
This commit is contained in:
Conor McCarthy
2024-05-01 14:36:30 +10:00
committed by Henri Verbeet
parent 55fe8df979
commit cd8cea6913
Notes: Henri Verbeet 2025-07-31 15:06:45 +02:00
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1663
10 changed files with 154 additions and 119 deletions

View File

@@ -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 \

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -1355,7 +1355,18 @@ static bool gl_runner_draw(struct shader_runner *r,
glEnable(GL_SAMPLE_MASK);
glSampleMaski(0, runner->r.sample_mask);
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);

View File

@@ -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) \
do \
{ \
if (!ret_features->x) \
{ \
skip("The selected Vulkan device does not support " #x ".\n"); \
goto out_destroy_context; \
} \
features.x = VK_TRUE
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)
{