Skip to content

Commit

Permalink
vkd3d: Implement inverted viewport height and depth features.
Browse files Browse the repository at this point in the history
These features correspond to Vulkan-native functionality.
  • Loading branch information
null77 committed Jun 30, 2023
1 parent 4ac1071 commit 1f3ef19
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 6 deletions.
19 changes: 13 additions & 6 deletions libs/vkd3d/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -4088,12 +4088,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CheckFeatureSupport(d3d12_device_i
return E_INVALIDARG;
}

data->UnrestrictedBufferTextureCopyPitchSupported = FALSE;
data->UnrestrictedVertexElementAlignmentSupported = FALSE;
data->InvertedViewportHeightFlipsYSupported = FALSE;
data->InvertedViewportDepthFlipsZSupported = FALSE;
data->TextureCopyBetweenDimensionsSupported = FALSE;
data->AlphaBlendFactorSupported = FALSE;
*data = device->d3d12_caps.options13;

TRACE("Inverted viewport height flips Y supported %u.", data->InvertedViewportHeightFlipsYSupported);
TRACE("Inverted viewport deps flips Z supported %u.", data->InvertedViewportDepthFlipsZSupported);
return S_OK;
}

Expand Down Expand Up @@ -6949,6 +6947,14 @@ static void d3d12_device_caps_init_feature_options11(struct d3d12_device *device
device->device_info.properties2.properties.limits.minStorageBufferOffsetAlignment <= 16;
}

static void d3d12_device_caps_init_feature_options13(struct d3d12_device *device)
{
D3D12_FEATURE_DATA_D3D12_OPTIONS13 *options13 = &device->d3d12_caps.options13;

options13->InvertedViewportHeightFlipsYSupported = TRUE;
options13->InvertedViewportDepthFlipsZSupported = TRUE;
}

static void d3d12_device_caps_init_feature_level(struct d3d12_device *device)
{
const VkPhysicalDeviceFeatures *features = &device->device_info.features2.features;
Expand Down Expand Up @@ -7270,6 +7276,7 @@ static void d3d12_device_caps_init(struct d3d12_device *device)
d3d12_device_caps_init_feature_options9(device);
d3d12_device_caps_init_feature_options10(device);
d3d12_device_caps_init_feature_options11(device);
d3d12_device_caps_init_feature_options13(device);
d3d12_device_caps_init_feature_level(device);

d3d12_device_caps_shader_model_override(device);
Expand Down
1 change: 1 addition & 0 deletions libs/vkd3d/vkd3d_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -4017,6 +4017,7 @@ struct d3d12_caps
D3D12_FEATURE_DATA_D3D12_OPTIONS9 options9;
D3D12_FEATURE_DATA_D3D12_OPTIONS10 options10;
D3D12_FEATURE_DATA_D3D12_OPTIONS11 options11;
D3D12_FEATURE_DATA_D3D12_OPTIONS13 options13;

D3D_FEATURE_LEVEL max_feature_level;
D3D_SHADER_MODEL max_shader_model;
Expand Down
191 changes: 191 additions & 0 deletions tests/d3d12_command.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,197 @@ void test_fractional_viewports(void)
destroy_test_context(&context);
}

void test_negative_viewports(void)
{
static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
D3D12_FEATURE_DATA_D3D12_OPTIONS13 options13;
ID3D12GraphicsCommandList *command_list;
D3D12_INPUT_LAYOUT_DESC input_layout;
D3D12_VERTEX_BUFFER_VIEW vbvs[4];
struct test_context_desc desc;
struct test_context context;
struct resource_readback rb;
ID3D12CommandQueue *queue;
D3D12_VIEWPORT viewport;
ID3D12Resource *vbs[4];
unsigned int i, x, y;
ID3D12Device *device;
HRESULT hr;

static const DWORD vs_code[] =
{
#if 0
void main(in float4 in_position : POSITION,
in float2 in_texcoord : TEXCOORD,
out float4 position : SV_Position,
out float2 texcoord : TEXCOORD)
{
position = in_position;
texcoord = in_texcoord;
}
#endif
0x43425844, 0x4df282ca, 0x85c8bbfc, 0xd44ad19f, 0x1158be97, 0x00000001, 0x00000148, 0x00000003,
0x0000002c, 0x00000080, 0x000000d8, 0x4e475349, 0x0000004c, 0x00000002, 0x00000008, 0x00000038,
0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x00000041, 0x00000000, 0x00000000,
0x00000003, 0x00000001, 0x00000303, 0x49534f50, 0x4e4f4954, 0x58455400, 0x524f4f43, 0xabab0044,
0x4e47534f, 0x00000050, 0x00000002, 0x00000008, 0x00000038, 0x00000000, 0x00000001, 0x00000003,
0x00000000, 0x0000000f, 0x00000044, 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000c03,
0x505f5653, 0x7469736f, 0x006e6f69, 0x43584554, 0x44524f4f, 0xababab00, 0x52444853, 0x00000068,
0x00010040, 0x0000001a, 0x0300005f, 0x001010f2, 0x00000000, 0x0300005f, 0x00101032, 0x00000001,
0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x03000065, 0x00102032, 0x00000001, 0x05000036,
0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x05000036, 0x00102032, 0x00000001, 0x00101046,
0x00000001, 0x0100003e,
};
static const D3D12_SHADER_BYTECODE vs = {vs_code, sizeof(vs_code)};
static const DWORD ps_code[] =
{
#if 0
float4 main(float4 position : SV_Position,
float2 texcoord : TEXCOORD) : SV_Target
{
return float4(position.xyz, texcoord.x);
}
#endif
0x43425844, 0xb07f78e3, 0xb7edc8a3, 0xf3c8edf9, 0x6361ba91, 0x00000001, 0x00000120, 0x00000003,
0x0000002c, 0x00000084, 0x000000b8, 0x4e475349, 0x00000050, 0x00000002, 0x00000008, 0x00000038,
0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000070f, 0x00000044, 0x00000000, 0x00000000,
0x00000003, 0x00000001, 0x00000103, 0x505f5653, 0x7469736f, 0x006e6f69, 0x43584554, 0x44524f4f,
0xababab00, 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000,
0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x58454853, 0x00000060,
0x00000050, 0x00000018, 0x0100086a, 0x04002064, 0x00101072, 0x00000000, 0x00000001, 0x03001062,
0x00101012, 0x00000001, 0x03000065, 0x001020f2, 0x00000000, 0x05000036, 0x00102072, 0x00000000,
0x00101246, 0x00000000, 0x05000036, 0x00102082, 0x00000000, 0x0010100a, 0x00000001, 0x0100003e,
};
static const D3D12_SHADER_BYTECODE ps = {ps_code, sizeof(ps_code)};
static const D3D12_INPUT_ELEMENT_DESC layout_desc[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
};
static const struct quad
{
struct vec4 position;
struct vec2 texcoord;
}
quads[4][4] =
{
{
{{0.0f, 1.0f, 1.0f, 1.0f}, {0.1f, 0.1f}},
{{0.0f, 0.0f, 1.0f, 1.0f}, {0.1f, 0.1f}},
{{ 1.0f, 1.0f, 1.0f, 1.0f}, {0.1f, 0.1f}},
{{ 1.0f, 0.0f, 1.0f, 1.0f}, {0.1f, 0.1f}},
},
{
{{-1.0f, 1.0f, -0.5f, 1.0f}, {0.2f, 0.2f}},
{{-1.0f, 0.0f, -0.5f, 1.0f}, {0.2f, 0.2f}},
{{ 0.0f, 1.0f, -0.5f, 1.0f}, {0.2f, 0.2f}},
{{ 0.0f, 0.0f, -0.5f, 1.0f}, {0.2f, 0.2f}},
},
{
{{0.0f, 0.0f, 0.5f, 1.0f}, {0.3f, 0.3f}},
{{0.0f, -1.0f, 0.5f, 1.0f}, {0.3f, 0.3f}},
{{ 1.0f, 0.0f, 0.5f, 1.0f}, {0.3f, 0.3f}},
{{ 1.0f, -1.0f, 0.5f, 1.0f}, {0.3f, 0.3f}},
},
{
{{-1.0f, 0.0f, -1.0f, 1.0f}, {0.4f, 0.4f}},
{{-1.0f, -1.0f, -1.0f, 1.0f}, {0.4f, 0.4f}},
{{ 0.0f, 0.0f, -1.0f, 1.0f}, {0.4f, 0.4f}},
{{ 0.0f, -1.0f, -1.0f, 1.0f}, {0.4f, 0.4f}},
},
};

memset(&desc, 0, sizeof(desc));
desc.rt_format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.no_root_signature = true;
if (!init_test_context(&context, &desc))
return;
command_list = context.list;
queue = context.queue;
device = context.device;

memset(&options13, 0, sizeof(options13));
hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS13, &options13, sizeof(options13));
ok(SUCCEEDED(hr), "OPTIONS13 is not supported by runtime.\n");

if (!options13.InvertedViewportHeightFlipsYSupported)
{
skip("Device does not support negative viewport height.\n");
destroy_test_context(&context);
return;
}

context.root_signature = create_empty_root_signature(context.device,
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

input_layout.pInputElementDescs = layout_desc;
input_layout.NumElements = ARRAY_SIZE(layout_desc);

context.pipeline_state = create_pipeline_state(context.device,
context.root_signature, desc.rt_format, &vs, &ps, &input_layout);

for (i = 0; i < 4; i++)
{
vbs[i] = create_upload_buffer(context.device, sizeof(quads[i]), quads[i]);

vbvs[i].BufferLocation = ID3D12Resource_GetGPUVirtualAddress(vbs[i]);
vbvs[i].StrideInBytes = sizeof(quads[i][0]);
vbvs[i].SizeInBytes = sizeof(quads[i]);
}

set_viewport(&viewport, 0, context.render_target_desc.Height,
context.render_target_desc.Width, -(float)context.render_target_desc.Height, 1.0f, 0.0f);

ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);

ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, NULL);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);

for (i = 0; i < 4; i++)
{
ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 1, &vbvs[i]);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
}

transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);

get_texture_readback_with_command_list(context.render_target, 0, &rb, queue, command_list);
for (y = 0; y < rb.height; ++y)
{
for (x = 0; x < rb.width; ++x)
{
const struct vec4 *actual = get_readback_vec4(&rb, x, y);
int expected_quad_index = ((x < rb.width / 2) ? 1 : 0) + ((y < rb.height / 2) ? 2 : 0);
struct vec2 expected_fragcoord = {x + 0.5f, y + 0.5f};
const struct vec2 *expected_texcoord = &quads[expected_quad_index][0].texcoord;
const float expected_depth = -quads[expected_quad_index][0].position.z + 1.0f;
ok(compare_float(actual->x, expected_fragcoord.x, 0) && compare_float(actual->y, expected_fragcoord.y, 0),
"Got fragcoord {%.8e, %.8e}, expected {%.8e, %.8e} at (%u, %u).\n",
actual->x, actual->y, expected_fragcoord.x, expected_fragcoord.y, x, y);
ok(compare_float(actual->z, expected_depth, 2),
"Got depth {%.8e}, expected {%.8e} at (%u, %u).\n",
actual->z, expected_depth, x, y);
ok(compare_float(actual->w, expected_texcoord->x, 2),
"Got texcoord {%.8e}, expected {%.8e} at (%u, %u).\n",
actual->w, expected_texcoord->x, x, y);
}
}
release_resource_readback(&rb);

reset_command_list(command_list, context.allocator);

for (i = 0; i < 4; i++)
{
ID3D12Resource_Release(vbs[i]);
}
destroy_test_context(&context);
}

void test_scissor(void)
{
ID3D12GraphicsCommandList *command_list;
Expand Down
1 change: 1 addition & 0 deletions tests/d3d12_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ decl_test(test_append_aligned_element);
decl_test(test_gpu_virtual_address);
decl_test(test_fragment_coords);
decl_test(test_fractional_viewports);
decl_test(test_negative_viewports);
decl_test(test_scissor);
decl_test(test_draw_depth_no_ps);
decl_test(test_draw_depth_only);
Expand Down

0 comments on commit 1f3ef19

Please sign in to comment.