blob: 8c7e4f3f8f942a212e61ff09a8d90b8fc0fefca1 [file] [edit]
/*
* Copyright 2016-2017 Józef Kucia for CodeWeavers
* Copyright 2020-2021 Philip Rebohle for Valve Corporation
* Copyright 2020-2021 Joshua Ashton for Valve Corporation
* Copyright 2020-2021 Hans-Kristian Arntzen for Valve Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define VKD3D_DBG_CHANNEL VKD3D_DBG_CHANNEL_API
#include "d3d12_crosstest.h"
void test_srgb_unorm_mismatch_usage_aliasing(void)
{
D3D12_RESOURCE_ALLOCATION_INFO unorm_alloc_info;
D3D12_RESOURCE_ALLOCATION_INFO srgb_alloc_info;
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
static float white[] = { 1, 1, 1, 1 };
D3D12_RESOURCE_DESC resource_desc;
D3D12_ROOT_SIGNATURE_DESC rs_desc;
struct test_context_desc desc;
struct resource_readback rb;
struct test_context context;
D3D12_HEAP_DESC heap_desc;
ID3D12Resource *unorm;
ID3D12Resource *srgb;
D3D12_VIEWPORT vp;
unsigned int x, y;
ID3D12Heap *heap;
D3D12_RECT sci;
HRESULT hr;
#include "shaders/render_target/headers/srgb_unorm_mismatch_vs.h"
#include "shaders/render_target/headers/srgb_unorm_mismatch_ps.h"
memset(&desc, 0, sizeof(desc));
desc.no_pipeline = true;
desc.no_render_target = true;
if (!init_test_context(&context, &desc))
return;
memset(&rs_desc, 0, sizeof(rs_desc));
create_root_signature(context.device, &rs_desc, &context.root_signature);
init_pipeline_state_desc(&pso_desc, context.root_signature, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
&srgb_unorm_mismatch_vs_dxbc, &srgb_unorm_mismatch_ps_dxbc, NULL);
pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&context.pipeline_state);
ok(SUCCEEDED(hr), "Failed to create PSO, hr #%x\n", hr);
/* Triages an AC: Shadows bug where these resources are aliased on top of a heap and game expects this to "just werk". */
memset(&resource_desc, 0, sizeof(resource_desc));
resource_desc.Width = 264;
resource_desc.Height = 264;
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resource_desc.SampleDesc.Count = 1;
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resource_desc.MipLevels = 1;
resource_desc.DepthOrArraySize = 1;
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
unorm_alloc_info = ID3D12Device_GetResourceAllocationInfo(context.device, 0, 1, &resource_desc);
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
srgb_alloc_info = ID3D12Device_GetResourceAllocationInfo(context.device, 0, 1, &resource_desc);
memset(&heap_desc, 0, sizeof(heap_desc));
heap_desc.Flags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED | D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
heap_desc.SizeInBytes = 64 * 1024 + max(unorm_alloc_info.SizeInBytes, srgb_alloc_info.SizeInBytes);
hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void **)&heap);
ok(SUCCEEDED(hr), "Failed to create heap, hr #%x\n", hr);
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
hr = ID3D12Device_CreatePlacedResource(context.device, heap, 64 * 1024, &resource_desc, D3D12_RESOURCE_STATE_COPY_SOURCE, NULL, &IID_ID3D12Resource, (void **)&unorm);
ok(SUCCEEDED(hr), "Failed to create placed resource, hr #%x\n", hr);
/* AC: Shadows does not add this UAV flag, but D3D12 has requirements about aliasing if all things match,
* and we should be using VK_IMAGE_CREATE_ALIAS_BIT for all placed resoures, which makes this test pass on RDNA4.
* This should work as expected on all GPUs more or less ... */
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
hr = ID3D12Device_CreatePlacedResource(context.device, heap, 64 * 1024, &resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&srgb);
ok(SUCCEEDED(hr), "Failed to create placed resource, hr #%x\n", hr);
context.rtv_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1);
context.rtv = get_cpu_rtv_handle(&context, context.rtv_heap, 0);
ID3D12Device_CreateRenderTargetView(context.device, srgb, NULL, context.rtv);
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, context.rtv, white, 0, NULL);
ID3D12GraphicsCommandList_OMSetRenderTargets(context.list, 1, &context.rtv, TRUE, NULL);
set_viewport(&vp, 0, 0, resource_desc.Width, resource_desc.Height, 0, 1);
set_rect(&sci, 0, 0, resource_desc.Width, resource_desc.Height);
ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &vp);
ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &sci);
ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, context.root_signature);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 1, 0, 0);
transition_resource_state(context.list, srgb, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
/* Massive UB. This will only work if the layout of the image matches. */
vkd3d_mute_validation_message("09600", "Image layout tracking does not work across VK_IMAGE_CREATE_ALIAS_BIT.");
get_texture_readback_with_command_list(unorm, 0, &rb, context.queue, context.list);
vkd3d_unmute_validation_message("09600");
for (y = 0; y < resource_desc.Height; y++)
{
for (x = 0; x < resource_desc.Width; x++)
{
uint32_t readback, readback_x, readback_y;
readback = get_readback_uint(&rb, x, y, 0);
readback_x = (readback >> 0) & 0xff;
readback_y = (readback >> 8) & 0xff;
ok(readback_x == min(x, 255) && readback_y == min(y, 255), "%u, %u: Expected %u, %u, got %u, %u\n", x, y, min(x, 255), min(y, 255), readback_x, readback_y);
}
}
release_resource_readback(&rb);
ID3D12Heap_Release(heap);
ID3D12Resource_Release(srgb);
ID3D12Resource_Release(unorm);
destroy_test_context(&context);
}
void test_unbound_rtv_rendering(void)
{
static const struct vec4 red = { 1.0f, 0.0f, 0.0f, 1.0f };
static const float white[] = { 1.0f, 1.0f, 1.0f, 1.0f };
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
ID3D12GraphicsCommandList *command_list;
D3D12_CPU_DESCRIPTOR_HANDLE rt_handle;
struct test_context_desc desc;
struct test_context context;
ID3D12CommandQueue *queue;
ID3D12Resource *fp32_rt;
HRESULT hr;
#include "shaders/render_target/headers/ps_unbound_rtv.h"
memset(&desc, 0, sizeof(desc));
desc.rt_format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.rt_width = 32;
desc.rt_height = 32;
desc.rt_descriptor_count = 2;
desc.no_pipeline = true;
if (!init_test_context(&context, &desc))
return;
command_list = context.list;
queue = context.queue;
fp32_rt = create_default_texture2d(context.device, 32, 32,
1, 1, DXGI_FORMAT_R32_FLOAT, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
D3D12_RESOURCE_STATE_RENDER_TARGET);
rt_handle = context.rtv;
rt_handle.ptr += ID3D12Device_GetDescriptorHandleIncrementSize(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
ID3D12Device_CreateRenderTargetView(context.device, fp32_rt, NULL, rt_handle);
/* Apparently, rendering to an NULL RTV is fine. D3D12 validation does not complain about this case at all. */
init_pipeline_state_desc(&pso_desc, context.root_signature, 0, NULL, &ps_unbound_rtv_dxbc, NULL);
pso_desc.NumRenderTargets = 2;
pso_desc.RTVFormats[0] = DXGI_FORMAT_R32G32B32A32_FLOAT;
pso_desc.RTVFormats[1] = DXGI_FORMAT_R32_FLOAT;
pso_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
pso_desc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0xf;
pso_desc.BlendState.RenderTarget[1].RenderTargetWriteMask = 0xf;
pso_desc.DepthStencilState.DepthEnable = false;
pso_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&context.pipeline_state);
ok(hr == S_OK, "Failed to create state, hr %#x.\n", hr);
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rt_handle, white, 0, NULL);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.5f, 0.5f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
/* First, render to both RTs, but then only render to 1 RT. */
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 2, &context.rtv, true, NULL);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, NULL);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_resource_state(command_list, fp32_rt,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_vec4(context.render_target, 0, queue, command_list, &red, 0);
reset_command_list(command_list, context.allocator);
check_sub_resource_float(fp32_rt, 0, queue, command_list, 0.5f, 0);
ID3D12Resource_Release(fp32_rt);
destroy_test_context(&context);
}
void test_unknown_rtv_format(void)
{
static const struct vec4 vec4_white = {1.0f, 1.0f, 1.0f, 1.0f};
static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
struct vec4 expected_vec4 = {0.0f, 0.0f, 0.0f, 1.0f};
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
ID3D12GraphicsCommandList *command_list;
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc;
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[3];
ID3D12Resource *render_targets[2];
struct depth_stencil_resource ds;
struct test_context_desc desc;
struct test_context context;
ID3D12CommandQueue *queue;
unsigned int i;
HRESULT hr;
#include "shaders/render_target/headers/ps_unknown_rtv.h"
memset(&desc, 0, sizeof(desc));
desc.rt_format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.rt_descriptor_count = 16;
desc.no_pipeline = true;
if (!init_test_context(&context, &desc))
return;
command_list = context.list;
queue = context.queue;
init_depth_stencil(&ds, context.device, 32, 32, 1, 1, DXGI_FORMAT_D32_FLOAT, 0, NULL);
init_pipeline_state_desc(&pso_desc, context.root_signature, 0, NULL, &ps_unknown_rtv_dxbc, NULL);
pso_desc.NumRenderTargets = ARRAY_SIZE(rtvs);
for (i = 0; i < ARRAY_SIZE(rtvs); ++i)
pso_desc.RTVFormats[i] = desc.rt_format;
pso_desc.RTVFormats[0] = DXGI_FORMAT_UNKNOWN;
pso_desc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
pso_desc.DepthStencilState.DepthEnable = true;
pso_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&context.pipeline_state);
ok(hr == S_OK, "Failed to create state, hr %#x.\n", hr);
rtvs[0] = get_cpu_rtv_handle(&context, context.rtv_heap, 0);
rtvs[1] = get_cpu_rtv_handle(&context, context.rtv_heap, 1);
rtvs[2] = get_cpu_rtv_handle(&context, context.rtv_heap, 2);
create_render_target(&context, &desc, &render_targets[0], &rtvs[1]);
create_render_target(&context, &desc, &render_targets[1], &rtvs[2]);
for (i = 0; i < ARRAY_SIZE(rtvs); ++i)
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtvs[i], white, 0, NULL);
/* NULL RTV */
memset(&rtv_desc, 0, sizeof(rtv_desc));
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
rtv_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
rtv_desc.Texture2D.MipSlice = 0;
rtv_desc.Texture2D.PlaneSlice = 0;
ID3D12Device_CreateRenderTargetView(context.device, NULL, &rtv_desc,
get_cpu_rtv_handle(&context, context.rtv_heap, 0));
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, ARRAY_SIZE(rtvs), rtvs, false, &ds.dsv_handle);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.5f, 0.5f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_resource_state(command_list, render_targets[0],
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_resource_state(command_list, render_targets[1],
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_vec4(context.render_target, 0, queue, command_list, &vec4_white, 0);
reset_command_list(command_list, context.allocator);
expected_vec4.x = 2.0f;
check_sub_resource_vec4(render_targets[0], 0, queue, command_list, &expected_vec4, 0);
reset_command_list(command_list, context.allocator);
expected_vec4.x = 3.0f;
check_sub_resource_vec4(render_targets[1], 0, queue, command_list, &expected_vec4, 0);
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, ds.texture,
D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_float(ds.texture, 0, queue, command_list, 0.5f, 1);
for (i = 0; i < ARRAY_SIZE(render_targets); ++i)
ID3D12Resource_Release(render_targets[i]);
destroy_depth_stencil(&ds);
destroy_test_context(&context);
}
void test_unknown_dsv_format(void)
{
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
ID3D12GraphicsCommandList *command_list;
struct depth_stencil_resource ds;
D3D12_CLEAR_VALUE clear_value;
struct test_context_desc desc;
struct test_context context;
ID3D12CommandQueue *queue;
HRESULT hr;
#include "shaders/render_target/headers/ps_color.h"
static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
static const struct vec4 green = {0.0f, 1.0f, 0.0f, 1.0f};
static const struct vec4 red = {1.0f, 0.0f, 0.0f, 1.0f};
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;
clear_value.Format = DXGI_FORMAT_D32_FLOAT;
clear_value.DepthStencil.Depth = 0.5f;
clear_value.DepthStencil.Stencil = 0;
init_depth_stencil(&ds, context.device, 32, 32, 1, 1, DXGI_FORMAT_D32_FLOAT, 0, &clear_value);
context.root_signature = create_32bit_constants_root_signature(context.device,
0, 4, D3D12_SHADER_VISIBILITY_PIXEL);
/* DSVFormat = DXGI_FORMAT_UNKNOWN and D3D12_DEPTH_WRITE_MASK_ZERO */
init_pipeline_state_desc(&pso_desc, context.root_signature, desc.rt_format, NULL, &ps_color_dxbc, NULL);
pso_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
pso_desc.DepthStencilState.DepthEnable = true;
pso_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_EQUAL;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&context.pipeline_state);
ok(hr == S_OK, "Failed to create graphics pipeline state, hr %#x.\n", hr);
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
ID3D12GraphicsCommandList_ClearDepthStencilView(command_list, ds.dsv_handle,
D3D12_CLEAR_FLAG_DEPTH, 0.5f, 0, 0, NULL);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, &ds.dsv_handle);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &green.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.5f, 0.5f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &red.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 1.0f, 1.0f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.0f, 0.0f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.55f, 0.55f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, ds.texture,
D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_float(ds.texture, 0, queue, command_list, 0.5f, 1);
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_vec4(context.render_target, 0, queue, command_list, &green, 0);
/* DSVFormat = DXGI_FORMAT_UNKNOWN and no DSV */
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, ds.texture,
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
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_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &red.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.0f, 0.0f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &green.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.5f, 0.5f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_vec4(context.render_target, 0, queue, command_list, &green, 0);
/* DSVFormat = DXGI_FORMAT_UNKNOWN and D3D12_COMPARISON_FUNC_ALWAYS */
ID3D12PipelineState_Release(context.pipeline_state);
pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&context.pipeline_state);
ok(hr == S_OK, "Failed to create graphics pipeline state, hr %#x.\n", hr);
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, &ds.dsv_handle);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &red.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.0f, 0.0f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &green.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.6f, 0.6f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_vec4(context.render_target, 0, queue, command_list, &green, 0);
/* DSVFormat = DXGI_FORMAT_UNKNOWN and depth write */
ID3D12PipelineState_Release(context.pipeline_state);
pso_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&context.pipeline_state);
ok(hr == S_OK, "Failed to create graphics pipeline state, hr %#x.\n", hr);
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
ID3D12GraphicsCommandList_ClearDepthStencilView(command_list, ds.dsv_handle,
D3D12_CLEAR_FLAG_DEPTH, 0.0f, 0, 0, NULL);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, &ds.dsv_handle);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &red.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 1.0f, 1.0f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, NULL);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &green.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.6f, 0.6f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_vec4(context.render_target, 0, queue, command_list, &green, 0);
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, ds.texture,
D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_float(ds.texture, 0, queue, command_list, 1.0f, 1);
destroy_depth_stencil(&ds);
destroy_test_context(&context);
}
void test_depth_stencil_test_no_dsv(void)
{
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
ID3D12GraphicsCommandList *command_list;
struct depth_stencil_resource ds;
struct test_context_desc desc;
struct test_context context;
ID3D12CommandQueue *queue;
HRESULT hr;
#include "shaders/render_target/headers/ps_color.h"
static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
static const struct vec4 red = {1.0f, 0.0f, 0.0f, 1.0f};
static const struct vec4 green = { 0.0f, 1.0f, 0.0f, 1.0f };
static const struct vec4 blue = { 0.0f, 0.0f, 1.0f, 1.0f };
memset(&desc, 0, sizeof(desc));
desc.rt_format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.no_root_signature = true;
desc.rt_width = 32;
desc.rt_height = 32;
if (!init_test_context(&context, &desc))
return;
command_list = context.list;
queue = context.queue;
init_depth_stencil(&ds, context.device, 32, 32, 1, 1, DXGI_FORMAT_D32_FLOAT, 0, NULL);
context.root_signature = create_32bit_constants_root_signature(context.device,
0, 4, D3D12_SHADER_VISIBILITY_PIXEL);
init_pipeline_state_desc(&pso_desc, context.root_signature, desc.rt_format, NULL, &ps_color_dxbc, NULL);
pso_desc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
pso_desc.DepthStencilState.DepthEnable = true;
pso_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&context.pipeline_state);
ok(hr == S_OK, "Failed to create graphics pipeline state, hr %#x.\n", hr);
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
ID3D12GraphicsCommandList_ClearDepthStencilView(command_list, ds.dsv_handle, D3D12_CLEAR_FLAG_DEPTH,
1.0f, 0, 0, NULL);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, &ds.dsv_handle);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &green.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.5f, 0.5f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &red.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.9f, 0.9f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
/* Now, dynamically disable the depth attachment. */
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, NULL);
/* Native behavior seems to be that depth test is just disabled entirely here.
* This last draw is the color we should get on NV at least.
* D3D12 validation layers report errors here of course,
* but Metro Exodus relies on depth testing on DSV NULL apparently. */
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, 4, &blue.x, 0);
set_viewport(&context.viewport, 0.0f, 0.0f, 32.0f, 32.0f, 0.55f, 0.55f);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
/* vkd3d-proton just skips the draw call in this situation.
* At least test that we don't crash. */
check_sub_resource_vec4(context.render_target, 0, queue, command_list, &blue, 0);
destroy_depth_stencil(&ds);
destroy_test_context(&context);
}
void test_render_a8_dxbc(void)
{
static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f};
ID3D12GraphicsCommandList *command_list;
struct test_context_desc desc;
struct test_context context;
ID3D12CommandQueue *queue;
#include "shaders/render_target/headers/ps_render_a8.h"
memset(&desc, 0, sizeof(desc));
desc.rt_format = DXGI_FORMAT_A8_UNORM;
desc.ps = &ps_render_a8_dxbc;
if (!init_test_context(&context, &desc))
return;
command_list = context.list;
queue = context.queue;
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, black, 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_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint8(context.render_target, 0, queue, command_list, 0xff, 0);
destroy_test_context(&context);
}
void test_render_a8_dxil(void)
{
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f};
ID3D12GraphicsCommandList *command_list;
struct test_context_desc desc;
struct test_context context;
ID3D12CommandQueue *queue;
ID3D12Device *device;
HRESULT hr;
#include "shaders/render_target/headers/ps_render_a8.h"
memset(&desc, 0, sizeof(desc));
desc.rt_format = DXGI_FORMAT_A8_UNORM;
desc.no_pipeline = true;
if (!init_test_context(&context, &desc))
return;
if (!context_supports_dxil(&context))
{
destroy_test_context(&context);
return;
}
device = context.device;
command_list = context.list;
queue = context.queue;
init_pipeline_state_desc_dxil(&pso_desc, context.root_signature, 0, NULL, NULL, NULL);
pso_desc.RTVFormats[0] = DXGI_FORMAT_A8_UNORM;
pso_desc.NumRenderTargets = 1;
pso_desc.PS = ps_render_a8_dxil;
hr = ID3D12Device_CreateGraphicsPipelineState(device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&context.pipeline_state);
ok(hr == S_OK, "Failed to create graphics pipeline state, hr %#x.\n", hr);
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, black, 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_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint8(context.render_target, 0, queue, command_list, 0xff, 0);
destroy_test_context(&context);
}
void test_multisample_rendering(void)
{
static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
ID3D12GraphicsCommandList *command_list;
ID3D12PipelineState *ms_pipeline_state;
D3D12_CPU_DESCRIPTOR_HANDLE ms_rtv;
ID3D12Resource *ms_render_target;
struct test_context_desc desc;
struct test_context context;
ID3D12DescriptorHeap *heap;
ID3D12CommandQueue *queue;
uint32_t sample;
unsigned int i;
HRESULT hr;
#include "shaders/render_target/headers/ps_multisample_color.h"
#include "shaders/render_target/headers/ps_multisample_resolve.h"
static const unsigned int expected_colors[] = {0xff0000ff, 0xff00ff00, 0xffff0000, 0xff000000};
if (use_warp_device)
{
skip("Sample shading tests fail on WARP.\n");
return;
}
memset(&desc, 0, sizeof(desc));
desc.rt_width = desc.rt_height = 32;
desc.rt_descriptor_count = 2;
desc.no_root_signature = true;
if (!init_test_context(&context, &desc))
return;
command_list = context.list;
queue = context.queue;
context.root_signature = create_texture_root_signature(context.device,
D3D12_SHADER_VISIBILITY_PIXEL, 2, 0);
init_pipeline_state_desc(&pso_desc, context.root_signature,
context.render_target_desc.Format, NULL, &ps_multisample_resolve_dxbc, NULL);
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&context.pipeline_state);
ok(hr == S_OK, "Failed to create pipeline, hr %#x.\n", hr);
pso_desc.PS = ps_multisample_color_dxbc;
pso_desc.SampleDesc.Count = 4;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&ms_pipeline_state);
ok(hr == S_OK, "Failed to create pipeline, hr %#x.\n", hr);
ms_rtv = get_cpu_rtv_handle(&context, context.rtv_heap, 1);
desc.sample_desc.Count = 4;
create_render_target(&context, &desc, &ms_render_target, &ms_rtv);
heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
ID3D12Device_CreateShaderResourceView(context.device, ms_render_target, NULL,
get_cpu_descriptor_handle(&context, heap, 0));
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, ms_rtv, white, 0, NULL);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &ms_rtv, false, NULL);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(command_list, ms_pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 1, &heap);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0,
get_gpu_descriptor_handle(&context, heap, 0));
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, ms_render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_DEST);
ID3D12GraphicsCommandList_ResolveSubresource(command_list,
context.render_target, 0, ms_render_target, 0, context.render_target_desc.Format);
transition_resource_state(command_list, ms_render_target,
D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff404040, 2);
for (i = 0; i < ARRAY_SIZE(expected_colors); ++i)
{
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
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_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 1, &heap);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0,
get_gpu_descriptor_handle(&context, heap, 0));
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 1, 1, &desc.rt_width, 1);
sample = i;
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 1, 1, &sample, 0);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(context.render_target, 0, queue, command_list, expected_colors[i], 0);
}
/* Multisampled PSO on single-sampled RT. Native drivers are
* robust here and only render sample 0. */
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
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, ms_pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 1, &heap);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0,
get_gpu_descriptor_handle(&context, heap, 0));
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(context.render_target, 0, queue, command_list, expected_colors[0], 0);
ID3D12PipelineState_Release(ms_pipeline_state);
/* Single-sampled PSO on multisampled RT. Behaviour is not well
* defined here, but happens to work on native. */
pso_desc.SampleDesc.Count = 1;
vkd3d_set_out_of_spec_test_behavior(VKD3D_DEBUG_CONTROL_OUT_OF_SPEC_BEHAVIOR_SAMPLE_COUNT_MISMATCH, TRUE);
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&ms_pipeline_state);
ok(hr == S_OK, "Failed to create pipeline, hr %#x.\n", hr);
vkd3d_set_out_of_spec_test_behavior(VKD3D_DEBUG_CONTROL_OUT_OF_SPEC_BEHAVIOR_SAMPLE_COUNT_MISMATCH, FALSE);
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, ms_render_target,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, ms_rtv, white, 0, NULL);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &ms_rtv, false, NULL);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(command_list, ms_pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, ms_render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
for (i = 0; i < ARRAY_SIZE(expected_colors); ++i)
{
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
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_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 1, &heap);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0,
get_gpu_descriptor_handle(&context, heap, 0));
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 1, 1, &desc.rt_width, 1);
sample = i;
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 1, 1, &sample, 0);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
hr = ID3D12GraphicsCommandList_Close(command_list);
ok(hr == S_OK, "Failed to close command list, hr %#x.\n", hr);
exec_command_list(queue, command_list);
wait_queue_idle(context.device, queue);
reset_command_list(command_list, context.allocator);
}
ID3D12DescriptorHeap_Release(heap);
ID3D12Resource_Release(ms_render_target);
ID3D12PipelineState_Release(ms_pipeline_state);
destroy_test_context(&context);
}
void test_rendering_no_attachments_layers(void)
{
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
D3D12_FEATURE_DATA_D3D12_OPTIONS options;
D3D12_ROOT_SIGNATURE_DESC rs_desc;
D3D12_ROOT_PARAMETER root_param;
struct test_context_desc desc;
struct test_context context;
struct resource_readback rb;
unsigned int layer, x, y;
ID3D12Resource *buffer;
const struct vec4 *val;
D3D12_VIEWPORT vp;
D3D12_RECT sci;
HRESULT hr;
#include "shaders/render_target/headers/ps_no_attachments.h"
#include "shaders/render_target/headers/vs_no_attachments.h"
memset(&desc, 0, sizeof(desc));
desc.no_render_target = true;
desc.no_pipeline = true;
desc.no_root_signature = true;
if (!init_test_context(&context, &desc))
return;
if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options))) ||
!options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation)
{
skip("Cannot render layers from VS. Skipping.\n");
destroy_test_context(&context);
return;
}
memset(&root_param, 0, sizeof(root_param));
memset(&rs_desc, 0, sizeof(rs_desc));
rs_desc.NumParameters = 1;
rs_desc.pParameters = &root_param;
root_param.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
root_param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;
create_root_signature(context.device, &rs_desc, &context.root_signature);
buffer = create_default_buffer(context.device, 64 * 1024,
D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
init_pipeline_state_desc(&pso_desc, context.root_signature, DXGI_FORMAT_UNKNOWN,
&vs_no_attachments_dxbc, &ps_no_attachments_dxbc, NULL);
pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void**)&context.pipeline_state);
ok(SUCCEEDED(hr), "Failed to create PSO, hr #%x.\n", hr);
ID3D12GraphicsCommandList_OMSetRenderTargets(context.list, 0, NULL, FALSE, NULL);
set_viewport(&vp, 10000.0f, 12000.0f, 4.0f, 4.0f, 0.0f, 1.0f);
set_rect(&sci, 10000, 12000, 10004, 12004);
ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &vp);
ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &sci);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_SetGraphicsRootUnorderedAccessView(context.list, 0, ID3D12Resource_GetGPUVirtualAddress(buffer));
ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 16, 0, 0);
transition_resource_state(context.list, buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
get_buffer_readback_with_command_list(buffer, DXGI_FORMAT_R32G32B32A32_FLOAT, &rb, context.queue, context.list);
for (layer = 0; layer < 16; layer++)
{
for (y = 0; y < 4; y++)
{
for (x = 0; x < 4; x++)
{
val = get_readback_vec4(&rb, layer * 16 + y * 4 + x, 0);
ok(val->x == 10000.5f + (float)x, "%u, %u, %u: Unexpected value (x) = %f.\n", x, y, layer, val->x);
ok(val->y == 12000.5f + (float)y, "%u, %u, %u: Unexpected value (y) = %f.\n", x, y, layer, val->y);
ok(val->z == (float)layer, "%u, %u, %u: Unexpected value (z) = %f.\n", x, y, layer, val->z);
ok(val->w == 0.0f, "%u, %u, %u: Unexpected value (w) = %f.\n", x, y, layer, val->w);
}
}
}
release_resource_readback(&rb);
ID3D12Resource_Release(buffer);
destroy_test_context(&context);
}
void test_renderpass_validation(void)
{
D3D12_RENDER_PASS_RENDER_TARGET_DESC rtv_infos[2];
D3D12_FEATURE_DATA_D3D12_OPTIONS18 options18;
ID3D12GraphicsCommandList4 *command_list4;
D3D12_HEAP_PROPERTIES heap_properties;
ID3D12CommandAllocator *allocator;
D3D12_RESOURCE_DESC resource_desc;
ID3D12DescriptorHeap *rtv_heap;
ID3D12Resource *rt[4], *ds;
ID3D12Device* device;
unsigned int i;
HRESULT hr;
static const FLOAT black[] = { 0.0f, 0.0f, 0.0f, 0.0f };
if (!(device = create_device()))
return;
memset(&options18, 0, sizeof(options18));
ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS18, &options18, sizeof(options18));
if (!options18.RenderPassesValid)
{
skip("Render passes not supported.\n");
ID3D12Device_Release(device);
return;
}
hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_DIRECT, &IID_ID3D12CommandAllocator, (void**)&allocator);
ok(hr == S_OK, "Failed to create command allocator, hr %#x.\n", hr);
hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
if (FAILED(hr))
{
skip("ID3D12GraphicsCommandList4 not supported.\n");
ID3D12Device_Release(device);
return;
}
rtv_heap = create_cpu_descriptor_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, ARRAY_SIZE(rt));
/* Create dummy resources to bind as render targets */
memset(&heap_properties, 0, sizeof(heap_properties));
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
memset(&resource_desc, 0, sizeof(resource_desc));
resource_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
resource_desc.Width = 4;
resource_desc.Height = 4;
resource_desc.DepthOrArraySize = 1;
resource_desc.MipLevels = 1;
resource_desc.SampleDesc.Count = 1;
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, 0, &resource_desc,
D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void**)&rt[0]);
ok(hr == S_OK, "Failed to create render target, hr %#x.\n", hr);
resource_desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, 0, &resource_desc,
D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void**)&rt[1]);
ok(hr == S_OK, "Failed to create render target, hr %#x.\n", hr);
resource_desc.Width = 16;
resource_desc.Height = 16;
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, 0, &resource_desc,
D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void**)&rt[2]);
ok(hr == S_OK, "Failed to create render target, hr %#x.\n", hr);
resource_desc.SampleDesc.Count = 4;
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, 0, &resource_desc,
D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void**)&rt[3]);
ok(hr == S_OK, "Failed to create render target, hr %#x.\n", hr);
resource_desc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
resource_desc.SampleDesc.Count = 1;
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, 0, &resource_desc, D3D12_RESOURCE_STATE_DEPTH_WRITE, NULL, &IID_ID3D12Resource, (void**)&ds);
ok(hr == S_OK, "Failed to create render target, hr %#x.\n", hr);
for (i = 0; i < ARRAY_SIZE(rt); i++)
ID3D12Device_CreateRenderTargetView(device, rt[i], NULL, get_cpu_handle(device, rtv_heap, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, i));
/* Test whether beginning a render pass with no attachments is allowed */
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 0, NULL, NULL, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
hr = ID3D12GraphicsCommandList4_Close(command_list4);
ok(SUCCEEDED(hr), "Got hr %#x, expected S_OK.\n", hr);
ID3D12GraphicsCommandList4_Release(command_list4);
/* Test that binding a simple RTV works */
ID3D12CommandAllocator_Reset(allocator);
ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
memset(rtv_infos, 0, sizeof(rtv_infos));
for (i = 0; i < ARRAY_SIZE(rtv_infos); i++)
{
rtv_infos[i].cpuDescriptor = get_cpu_handle(device, rtv_heap, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, i);
rtv_infos[i].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
rtv_infos[i].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
}
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 1, rtv_infos, NULL, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
hr = ID3D12GraphicsCommandList4_Close(command_list4);
ok(SUCCEEDED(hr), "Got hr %#x, expected S_OK.\n", hr);
ID3D12GraphicsCommandList4_Release(command_list4);
/* Test that not matching BeginRenderPass and EndRenderPass fails */
ID3D12CommandAllocator_Reset(allocator);
ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 1, rtv_infos, NULL, 0);
hr = ID3D12GraphicsCommandList4_Close(command_list4);
ok(FAILED(hr), "Got hr %#x, expected E_FAIL.\n", hr);
ID3D12GraphicsCommandList4_Release(command_list4);
ID3D12CommandAllocator_Reset(allocator);
ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
hr = ID3D12GraphicsCommandList4_Close(command_list4);
ok(FAILED(hr), "Got hr %#x, expected E_INVALIDARG.\n", hr);
ID3D12GraphicsCommandList4_Release(command_list4);
ID3D12CommandAllocator_Reset(allocator);
ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 1, rtv_infos, NULL, 0);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 1, rtv_infos, NULL, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
hr = ID3D12GraphicsCommandList4_Close(command_list4);
ok(FAILED(hr), "Got hr %#x, expected E_INVALIDARG.\n", hr);
ID3D12GraphicsCommandList4_Release(command_list4);
ID3D12CommandAllocator_Reset(allocator);
ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 1, rtv_infos, NULL, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
hr = ID3D12GraphicsCommandList4_Close(command_list4);
ok(FAILED(hr), "Got hr %#x, expected E_INVALIDARG.\n", hr);
ID3D12GraphicsCommandList4_Release(command_list4);
/* Test consecutive render pass validation with suspend/resume flags */
ID3D12CommandAllocator_Reset(allocator);
ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 2, rtv_infos, NULL, D3D12_RENDER_PASS_FLAG_SUSPENDING_PASS);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 2, rtv_infos, NULL, D3D12_RENDER_PASS_FLAG_SUSPENDING_PASS | D3D12_RENDER_PASS_FLAG_RESUMING_PASS);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
/* Changing the render target order is explicitly allowed */
for (i = 0; i < 2; i++)
rtv_infos[i].cpuDescriptor = get_cpu_handle(device, rtv_heap, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1 - i);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 2, rtv_infos, NULL, D3D12_RENDER_PASS_FLAG_RESUMING_PASS);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
/* This is invalid, but not checked by the runtime */
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 2, rtv_infos, NULL, D3D12_RENDER_PASS_FLAG_RESUMING_PASS);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
hr = ID3D12GraphicsCommandList4_Close(command_list4);
ok(SUCCEEDED(hr), "Got hr %#x, expected S_OK.\n", hr);
ID3D12GraphicsCommandList4_Release(command_list4);
ID3D12CommandAllocator_Reset(allocator);
ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
/* Changing render targets in any way is not permited for suspend/resume within the same command list */
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 1, rtv_infos, NULL, D3D12_RENDER_PASS_FLAG_SUSPENDING_PASS);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 2, rtv_infos, NULL, D3D12_RENDER_PASS_FLAG_RESUMING_PASS);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
hr = ID3D12GraphicsCommandList4_Close(command_list4);
todo ok(FAILED(hr), "Got hr %#x, expected E_INVALIDARG.\n", hr);
ID3D12GraphicsCommandList4_Release(command_list4);
ID3D12CommandAllocator_Reset(allocator);
ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
/* Unlike resume after resume, suspend after suspend is checked by the runtime */
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 2, rtv_infos, NULL, D3D12_RENDER_PASS_FLAG_SUSPENDING_PASS);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 2, rtv_infos, NULL, D3D12_RENDER_PASS_FLAG_SUSPENDING_PASS);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
hr = ID3D12GraphicsCommandList4_Close(command_list4);
todo ok(FAILED(hr), "Got hr %#x, expected E_INVALIDARG.\n", hr);
ID3D12GraphicsCommandList4_Release(command_list4);
/* Test that executing certain commands during a render pass fails */
ID3D12CommandAllocator_Reset(allocator);
ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
allocator, NULL, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 2, rtv_infos, NULL, 0);
ID3D12GraphicsCommandList4_ClearRenderTargetView(command_list4, get_cpu_handle(device, rtv_heap, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 0), black, 0, NULL);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
hr = ID3D12GraphicsCommandList4_Close(command_list4);
ok(FAILED(hr), "Got hr %#x, expected E_FAIL.\n", hr);
ID3D12GraphicsCommandList4_Release(command_list4);
/* Barriers inside render passes, GPU work occuring between render passes with
* PRESERVE_LOCAL or suspend/resume flags are not validated by the runtime. */
ID3D12CommandAllocator_Release(allocator);
for (i = 0; i < ARRAY_SIZE(rt); i++)
ID3D12Resource_Release(rt[i]);
ID3D12Resource_Release(ds);
ID3D12DescriptorHeap_Release(rtv_heap);
ID3D12Device_Release(device);
}
void test_renderpass_rendering(void)
{
D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS rtv_resolves[5];
D3D12_RENDER_PASS_RENDER_TARGET_DESC rtv_infos[3];
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC dsv_info;
D3D12_FEATURE_DATA_D3D12_OPTIONS18 options18;
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
ID3D12GraphicsCommandList4 *command_list4;
ID3D12DescriptorHeap *rtv_heap, *dsv_heap;
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc;
D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc;
D3D12_HEAP_PROPERTIES heap_properties;
ID3D12RootSignature *root_signature;
D3D12_ROOT_SIGNATURE_DESC rs_desc;
D3D12_RESOURCE_DESC resource_desc;
ID3D12PipelineState *pso, *pso_ms;
ID3D12Resource *rt, *rt_ms, *ds;
struct test_context_desc desc;
D3D12_ROOT_PARAMETER rs_param;
struct resource_readback rb;
struct test_context context;
D3D12_VIEWPORT viewport;
unsigned int i, x, y;
D3D12_RECT scissor;
HRESULT hr;
static const float black[] = { 0.0f, 0.0f, 0.0f, 0.0f };
static const float white[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static const float red[] = { 1.0f, 0.0f, 0.0f, 1.0f };
static const float green[] = { 0.0f, 1.0f, 0.0f, 1.0f };
static const float blue[] = { 0.0f, 0.0f, 1.0f, 1.0f };
#include "shaders/render_target/headers/ps_renderpass.h"
struct
{
float depth;
uint32_t colors[3];
uint32_t sample_mask;
} shader_args;
memset(&desc, 0, sizeof(desc));
desc.no_render_target = true;
desc.no_root_signature = true;
desc.no_pipeline = true;
if (!init_test_context(&context, &desc))
return;
memset(&options18, 0, sizeof(options18));
ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS18, &options18, sizeof(options18));
if (!options18.RenderPassesValid)
{
skip("Render passes not supported.\n");
destroy_test_context(&context);
return;
}
hr = ID3D12GraphicsCommandList_QueryInterface(context.list, &IID_ID3D12GraphicsCommandList4, (void**)&command_list4);
if (FAILED(hr))
{
skip("ID3D12GraphicsCommandList4 not supported.\n");
destroy_test_context(&context);
return;
}
memset(&heap_properties, 0, sizeof(heap_properties));
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
memset(&resource_desc, 0, sizeof(resource_desc));
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resource_desc.Width = 4;
resource_desc.Height = 4;
resource_desc.DepthOrArraySize = 3;
resource_desc.MipLevels = 1;
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
resource_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
resource_desc.SampleDesc.Count = 1;
hr = ID3D12Device_CreateCommittedResource(context.device, &heap_properties,
D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET,
NULL, &IID_ID3D12Resource, (void**)&rt);
ok(hr == S_OK, "Failed to create render target, hr %#x.\n", hr);
resource_desc.Alignment = D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT;
resource_desc.SampleDesc.Count = 4;
hr = ID3D12Device_CreateCommittedResource(context.device, &heap_properties,
D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET,
NULL, &IID_ID3D12Resource, (void**)&rt_ms);
ok(hr == S_OK, "Failed to create render target, hr %#x.\n", hr);
resource_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
resource_desc.DepthOrArraySize = 1;
resource_desc.SampleDesc.Count = 1;
resource_desc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
hr = ID3D12Device_CreateCommittedResource(context.device, &heap_properties,
D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_DEPTH_WRITE,
NULL, &IID_ID3D12Resource, (void**)&ds);
ok(hr == S_OK, "Failed to create render target, hr %#x.\n", hr);
rtv_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 8);
dsv_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1);
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = 4.0f;
viewport.Height = 4.0f;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
scissor.left = 0;
scissor.top = 0;
scissor.right = 4;
scissor.bottom = 4;
memset(&rs_param, 0, sizeof(rs_param));
rs_param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
rs_param.Constants.Num32BitValues = sizeof(shader_args) / sizeof(uint32_t);
rs_param.Constants.ShaderRegister = 0;
rs_param.Constants.RegisterSpace = 0;
rs_param.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
memset(&rs_desc, 0, sizeof(rs_desc));
rs_desc.NumParameters = 1;
rs_desc.pParameters = &rs_param;
create_root_signature(context.device, &rs_desc, &root_signature);
init_pipeline_state_desc(&pso_desc, root_signature, 0, NULL, &ps_renderpass_dxbc, NULL);
pso_desc.NumRenderTargets = 3;
pso_desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
pso_desc.RTVFormats[1] = DXGI_FORMAT_R8G8B8A8_UNORM;
pso_desc.RTVFormats[2] = DXGI_FORMAT_R8G8B8A8_UNORM;
pso_desc.DSVFormat = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
pso_desc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0xf;
pso_desc.BlendState.RenderTarget[1].RenderTargetWriteMask = 0xf;
pso_desc.BlendState.RenderTarget[2].RenderTargetWriteMask = 0xf;
pso_desc.DepthStencilState.DepthEnable = true;
pso_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
pso_desc.DepthStencilState.StencilEnable = TRUE;
pso_desc.DepthStencilState.StencilWriteMask = 0xff;
pso_desc.DepthStencilState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
pso_desc.DepthStencilState.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_REPLACE;
pso_desc.DepthStencilState.FrontFace.StencilFailOp = D3D12_STENCIL_OP_REPLACE;
pso_desc.DepthStencilState.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
pso_desc.DepthStencilState.BackFace = pso_desc.DepthStencilState.FrontFace;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&pso);
ok(hr == S_OK, "Failed to create state, hr %#x.\n", hr);
pso_desc.SampleDesc.Count = 4;
pso_desc.SampleMask = 0xf;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&pso_ms);
ok(hr == S_OK, "Failed to create state, hr %#x.\n", hr);
memset(&rtv_desc, 0, sizeof(rtv_desc));
rtv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
for (i = 0; i < 3; i++)
{
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
rtv_desc.Texture2DArray.MipSlice = 0;
rtv_desc.Texture2DArray.FirstArraySlice = i;
rtv_desc.Texture2DArray.ArraySize = 1;
ID3D12Device_CreateRenderTargetView(context.device, rt, &rtv_desc,
get_cpu_rtv_handle(&context, rtv_heap, i));
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
rtv_desc.Texture2DMSArray.FirstArraySlice = i;
rtv_desc.Texture2DMSArray.ArraySize = 1;
ID3D12Device_CreateRenderTargetView(context.device, rt_ms, &rtv_desc,
get_cpu_rtv_handle(&context, rtv_heap, i + 4));
}
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
rtv_desc.Texture2DArray.MipSlice = 0;
rtv_desc.Texture2DArray.FirstArraySlice = 0;
rtv_desc.Texture2DArray.ArraySize = 3;
ID3D12Device_CreateRenderTargetView(context.device, rt, &rtv_desc,
get_cpu_rtv_handle(&context, rtv_heap, 3));
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
rtv_desc.Texture2DMSArray.FirstArraySlice = 0;
rtv_desc.Texture2DMSArray.ArraySize = 3;
ID3D12Device_CreateRenderTargetView(context.device, rt_ms, &rtv_desc,
get_cpu_rtv_handle(&context, rtv_heap, 7));
memset(&dsv_desc, 0, sizeof(dsv_desc));
dsv_desc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
dsv_desc.Texture2D.MipSlice = 0;
ID3D12Device_CreateDepthStencilView(context.device, ds, &dsv_desc,
get_cpu_dsv_handle(&context, dsv_heap, 0));
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = 4.0f;
viewport.Height = 4.0f;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
scissor.left = 0;
scissor.top = 0;
scissor.right = 4;
scissor.bottom = 4;
/* Initialize all render target subresources */
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, get_cpu_rtv_handle(&context, rtv_heap, 3), white, 0, NULL);
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, get_cpu_rtv_handle(&context, rtv_heap, 7), white, 0, NULL);
ID3D12GraphicsCommandList_ClearDepthStencilView(context.list, get_cpu_dsv_handle(&context, dsv_heap, 0),
D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0xff, 0, NULL);
/* Test basic clear and preserve load ops */
memset(rtv_infos, 0, sizeof(rtv_infos));
for (i = 0; i < ARRAY_SIZE(rtv_infos); i++)
{
rtv_infos[i].cpuDescriptor = get_cpu_rtv_handle(&context, rtv_heap, i);
rtv_infos[i].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
rtv_infos[i].BeginningAccess.Clear.ClearValue.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
rtv_infos[i].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
}
rtv_infos[0].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
memcpy(rtv_infos[0].BeginningAccess.Clear.ClearValue.Color, green, sizeof(green));
rtv_infos[2].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
memcpy(rtv_infos[2].BeginningAccess.Clear.ClearValue.Color, red, sizeof(red));
memset(&dsv_info, 0, sizeof(dsv_info));
dsv_info.cpuDescriptor = get_cpu_dsv_handle(&context, dsv_heap, 0);
dsv_info.DepthBeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
dsv_info.DepthBeginningAccess.Clear.ClearValue.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
dsv_info.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth = 0.5f;
dsv_info.StencilBeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
dsv_info.StencilBeginningAccess.Clear.ClearValue.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
dsv_info.StencilBeginningAccess.Clear.ClearValue.DepthStencil.Stencil = 0x55;
dsv_info.DepthEndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
dsv_info.StencilEndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, ARRAY_SIZE(rtv_infos), rtv_infos, &dsv_info, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_resource_state(context.list, ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(rt, 0, context.queue, context.list, 0xff00ff00u, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(rt, 1, context.queue, context.list, 0xffffffffu, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(rt, 2, context.queue, context.list, 0xff0000ffu, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_float(ds, 0, context.queue, context.list, 0.5f, 0.0f);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint8(ds, 1, context.queue, context.list, 0x55, 0);
reset_command_list(context.list, context.allocator);
/* Test rendering with a render pass */
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
transition_resource_state(context.list, ds, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE);
for (i = 0; i < ARRAY_SIZE(rtv_infos); i++)
{
rtv_infos[i].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
memcpy(&rtv_infos[i].BeginningAccess.Clear.ClearValue.Color, &black, sizeof(black));
}
dsv_info.DepthBeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
dsv_info.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth = 0.0f;
dsv_info.StencilBeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
dsv_info.StencilBeginningAccess.Clear.ClearValue.DepthStencil.Stencil = 0x00;
shader_args.depth = 1.0f;
shader_args.colors[0] = 0xff0000ff;
shader_args.colors[1] = 0xff00ff00;
shader_args.colors[2] = 0xffff0000;
shader_args.sample_mask = ~0u;
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, ARRAY_SIZE(rtv_infos), rtv_infos, &dsv_info, 0);
ID3D12GraphicsCommandList4_IASetPrimitiveTopology(command_list4, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList4_RSSetViewports(command_list4, 1, &viewport);
ID3D12GraphicsCommandList4_RSSetScissorRects(command_list4, 1, &scissor);
ID3D12GraphicsCommandList4_OMSetStencilRef(command_list4, 0xff);
ID3D12GraphicsCommandList4_SetGraphicsRootSignature(command_list4, root_signature);
ID3D12GraphicsCommandList4_SetPipelineState(command_list4, pso);
ID3D12GraphicsCommandList4_SetGraphicsRoot32BitConstants(command_list4,
0, sizeof(shader_args) / sizeof(uint32_t), &shader_args, 0);
ID3D12GraphicsCommandList4_DrawInstanced(command_list4, 3, 1, 0, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
/* Ensure that render targets are unbound after the render pass */
shader_args.depth = 0.5f;
shader_args.colors[0] = 0xdeadbeef;
shader_args.colors[1] = 0xdeadbeef;
shader_args.colors[2] = 0xdeadbeef;
ID3D12GraphicsCommandList4_SetGraphicsRoot32BitConstants(command_list4,
0, sizeof(shader_args) / sizeof(uint32_t), &shader_args, 0);
ID3D12GraphicsCommandList4_DrawInstanced(command_list4, 3, 1, 0, 0);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_resource_state(context.list, ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(rt, 0, context.queue, context.list, 0xff0000ff, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(rt, 1, context.queue, context.list, 0xff00ff00, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(rt, 2, context.queue, context.list, 0xffff0000, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_float(ds, 0, context.queue, context.list, 1.0f, 0.0f);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint8(ds, 1, context.queue, context.list, 0xff, 0);
reset_command_list(context.list, context.allocator);
/* Test clearing depth and stencil aspects indiviually */
dsv_info.DepthBeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
dsv_info.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth = 0.5f;
dsv_info.StencilBeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
dsv_info.StencilBeginningAccess.Clear.ClearValue.DepthStencil.Stencil = 0x00;
transition_resource_state(context.list, ds, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, ARRAY_SIZE(rtv_infos), rtv_infos, &dsv_info, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
transition_resource_state(context.list, ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_float(ds, 0, context.queue, context.list, 0.5f, 0.0f);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint8(ds, 1, context.queue, context.list, 0xff, 0);
reset_command_list(context.list, context.allocator);
dsv_info.DepthBeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
dsv_info.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth = 1.0f;
dsv_info.StencilBeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
dsv_info.StencilBeginningAccess.Clear.ClearValue.DepthStencil.Stencil = 0x40;
transition_resource_state(context.list, ds, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, ARRAY_SIZE(rtv_infos), rtv_infos, &dsv_info, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
transition_resource_state(context.list, ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_float(ds, 0, context.queue, context.list, 0.5f, 0.0f);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint8(ds, 1, context.queue, context.list, 0x40, 0);
reset_command_list(context.list, context.allocator);
/* Test clear behaviour with SUSPEND/RESUME flags */
rtv_infos[0].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
memcpy(&rtv_infos[0].BeginningAccess.Clear.ClearValue.Color, &blue, sizeof(green));
shader_args.colors[0] = 0xff00ff00u;
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 1, rtv_infos, NULL, D3D12_RENDER_PASS_FLAG_SUSPENDING_PASS);
ID3D12GraphicsCommandList4_IASetPrimitiveTopology(command_list4, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList4_RSSetViewports(command_list4, 1, &viewport);
ID3D12GraphicsCommandList4_RSSetScissorRects(command_list4, 1, &scissor);
ID3D12GraphicsCommandList4_OMSetStencilRef(command_list4, 0xff);
ID3D12GraphicsCommandList4_SetGraphicsRootSignature(command_list4, root_signature);
ID3D12GraphicsCommandList4_SetPipelineState(command_list4, pso);
ID3D12GraphicsCommandList4_SetGraphicsRoot32BitConstants(command_list4,
0, sizeof(shader_args) / sizeof(uint32_t), &shader_args, 0);
ID3D12GraphicsCommandList4_DrawInstanced(command_list4, 3, 1, 0, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 1, rtv_infos, NULL, D3D12_RENDER_PASS_FLAG_RESUMING_PASS);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(rt, 0, context.queue, context.list, 0xff00ff00, 0);
reset_command_list(context.list, context.allocator);
/* Test bind-to-rasterizer behaviour of different beginning access types */
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
rtv_infos[0].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
rtv_infos[0].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
memcpy(rtv_infos[0].BeginningAccess.Clear.ClearValue.Color, white, sizeof(white));
rtv_infos[1].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
rtv_infos[1].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_RENDER;
memcpy(rtv_infos[1].BeginningAccess.Clear.ClearValue.Color, white, sizeof(white));
rtv_infos[2].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
rtv_infos[2].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_SRV;
memcpy(rtv_infos[2].BeginningAccess.Clear.ClearValue.Color, white, sizeof(white));
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, ARRAY_SIZE(rtv_infos), rtv_infos, NULL, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
transition_sub_resource_state(context.list, rt, 2, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
ID3D12GraphicsCommandList4_IASetPrimitiveTopology(command_list4, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList4_RSSetViewports(command_list4, 1, &viewport);
ID3D12GraphicsCommandList4_RSSetScissorRects(command_list4, 1, &scissor);
ID3D12GraphicsCommandList4_OMSetStencilRef(command_list4, 0xff);
ID3D12GraphicsCommandList4_SetGraphicsRootSignature(command_list4, root_signature);
ID3D12GraphicsCommandList4_SetPipelineState(command_list4, pso);
rtv_infos[0].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS;
rtv_infos[0].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS;
rtv_infos[1].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_RENDER;
rtv_infos[1].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE_LOCAL_SRV;
rtv_infos[2].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_SRV;
rtv_infos[2].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD;
shader_args.colors[0] = 0xff00ff00u;
shader_args.colors[1] = 0xdeadbeefu;
shader_args.colors[2] = 0xdeadbeefu;
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, ARRAY_SIZE(rtv_infos), rtv_infos, NULL, 0);
ID3D12GraphicsCommandList4_SetGraphicsRoot32BitConstants(command_list4,
0, sizeof(shader_args) / sizeof(uint32_t), &shader_args, 0);
ID3D12GraphicsCommandList4_DrawInstanced(command_list4, 3, 1, 0, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
transition_sub_resource_state(context.list, rt, 1, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
transition_sub_resource_state(context.list, rt, 2, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
rtv_infos[0].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
rtv_infos[0].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
rtv_infos[1].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE_LOCAL_SRV;
rtv_infos[1].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
rtv_infos[2].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD;
rtv_infos[2].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
shader_args.colors[0] = 0xffff00ffu;
shader_args.colors[1] = 0xffff0000u;
shader_args.colors[2] = 0xdeadbeefu;
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, ARRAY_SIZE(rtv_infos), rtv_infos, NULL, 0);
ID3D12GraphicsCommandList4_SetGraphicsRoot32BitConstants(command_list4,
0, sizeof(shader_args) / sizeof(uint32_t), &shader_args, 0);
ID3D12GraphicsCommandList4_DrawInstanced(command_list4, 3, 1, 0, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
transition_sub_resource_state(context.list, rt, 0, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_sub_resource_state(context.list, rt, 1, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_sub_resource_state(context.list, rt, 2, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(rt, 0, context.queue, context.list, 0xffff00ff, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(rt, 1, context.queue, context.list, 0xff00ff00, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(rt, 2, context.queue, context.list, 0xffff0000, 0);
reset_command_list(context.list, context.allocator);
/* Test render pass resolves */
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);
for (i = 0; i < ARRAY_SIZE(rtv_infos); i++)
{
rtv_infos[i].cpuDescriptor = get_cpu_rtv_handle(&context, rtv_heap, 4 + i);
rtv_infos[i].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD;
rtv_infos[i].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE;
rtv_infos[i].EndingAccess.Resolve.pSrcResource = rt_ms;
rtv_infos[i].EndingAccess.Resolve.pDstResource = rt;
rtv_infos[i].EndingAccess.Resolve.SubresourceCount = 1;
rtv_infos[i].EndingAccess.Resolve.pSubresourceParameters = &rtv_resolves[i];
rtv_infos[i].EndingAccess.Resolve.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
rtv_infos[i].EndingAccess.Resolve.PreserveResolveSource = TRUE;
rtv_resolves[i].SrcSubresource = i;
rtv_resolves[i].DstSubresource = i;
rtv_resolves[i].DstX = 0;
rtv_resolves[i].DstY = 0;
rtv_resolves[i].SrcRect.left = 0;
rtv_resolves[i].SrcRect.top = 0;
rtv_resolves[i].SrcRect.right = 4;
rtv_resolves[i].SrcRect.bottom = 4;
}
rtv_infos[0].EndingAccess.Resolve.ResolveMode = D3D12_RESOLVE_MODE_MIN;
rtv_infos[1].EndingAccess.Resolve.ResolveMode = D3D12_RESOLVE_MODE_MAX;
rtv_infos[2].EndingAccess.Resolve.ResolveMode = D3D12_RESOLVE_MODE_AVERAGE;
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, ARRAY_SIZE(rtv_infos), rtv_infos, NULL, 0);
ID3D12GraphicsCommandList4_IASetPrimitiveTopology(command_list4, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList4_RSSetViewports(command_list4, 1, &viewport);
ID3D12GraphicsCommandList4_RSSetScissorRects(command_list4, 1, &scissor);
ID3D12GraphicsCommandList4_SetGraphicsRootSignature(command_list4, root_signature);
ID3D12GraphicsCommandList4_SetPipelineState(command_list4, pso_ms);
for (i = 0; i < 4; i++)
{
shader_args.depth = (float)i / 3.0f;
shader_args.colors[0] = (85 * i) << 0;
shader_args.colors[1] = (85 * i) << 8;
shader_args.colors[2] = (85 * i) << 16;
shader_args.sample_mask = 1u << (i ^ 1);
ID3D12GraphicsCommandList4_OMSetStencilRef(command_list4, 16 * i + 8);
ID3D12GraphicsCommandList4_SetGraphicsRoot32BitConstants(command_list4,
0, sizeof(shader_args) / sizeof(uint32_t), &shader_args, 0);
ID3D12GraphicsCommandList4_DrawInstanced(command_list4, 3, 1, 0, 0);
}
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(rt, 0, context.queue, context.list, 0x00000000, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(rt, 1, context.queue, context.list, 0x0000ff00, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(rt, 2, context.queue, context.list, 0x00800000, 1);
reset_command_list(context.list, context.allocator);
/* Test per-subresource resolve areas */
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, get_cpu_rtv_handle(&context, rtv_heap, 3), white, 0, NULL);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_DEST);
for (i = 0; i < 3; i++)
{
rtv_resolves[i].SrcSubresource = i;
rtv_resolves[i].DstSubresource = i;
rtv_resolves[i].DstX = i == 1 ? 1 : 0;
rtv_resolves[i].DstY = i == 1 ? 2 : 0;
rtv_resolves[i].SrcRect.left = i == 2 ? 2 : 0;
rtv_resolves[i].SrcRect.top = i == 2 ? 1 : 0;
rtv_resolves[i].SrcRect.right = rtv_resolves[i].SrcRect.left + 2;
rtv_resolves[i].SrcRect.bottom = rtv_resolves[i].SrcRect.top + 2;
}
rtv_infos[0].cpuDescriptor = get_cpu_rtv_handle(&context, rtv_heap, 7);
rtv_infos[0].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
rtv_infos[0].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE;
rtv_infos[0].EndingAccess.Resolve.pSrcResource = rt_ms;
rtv_infos[0].EndingAccess.Resolve.pDstResource = rt;
rtv_infos[0].EndingAccess.Resolve.SubresourceCount = 3;
rtv_infos[0].EndingAccess.Resolve.pSubresourceParameters = &rtv_resolves[0];
rtv_infos[0].EndingAccess.Resolve.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
rtv_infos[0].EndingAccess.Resolve.ResolveMode = D3D12_RESOLVE_MODE_AVERAGE;
rtv_infos[0].EndingAccess.Resolve.PreserveResolveSource = TRUE;
ID3D12GraphicsCommandList4_BeginRenderPass(command_list4, 1, rtv_infos, NULL, 0);
ID3D12GraphicsCommandList4_EndRenderPass(command_list4);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
for (i = 0; i < 3; i++)
{
uint32_t multiplier = 1u << (8 * i);
get_texture_readback_with_command_list(rt, i, &rb, context.queue, context.list);
for (x = 0; x < 4; x++)
{
for (y = 0; y < 4; y++)
{
uint32_t got = get_readback_uint(&rb, x, y, 0);
bool inside = x >= rtv_resolves[i].DstX && y >= rtv_resolves[i].DstY &&
x < rtv_resolves[i].DstX + rtv_resolves[i].SrcRect.right - rtv_resolves[i].SrcRect.left &&
y < rtv_resolves[i].DstY + rtv_resolves[i].SrcRect.bottom - rtv_resolves[i].SrcRect.top;
if (inside)
{
ok(got >= (0x7f * multiplier) && got <= (0x81 * multiplier),
"Got %#x, expected %#x at (%u,%u,%u).\n", got, 0x80 * multiplier, x, y, i);
}
else
ok(got == 0xffffffffu, "Got %#x, expected %#x at (%u,%u,%u).\n", got, 0xffffffffu, x, y, i);
}
}
release_resource_readback(&rb);
reset_command_list(context.list, context.allocator);
}
ID3D12DescriptorHeap_Release(rtv_heap);
ID3D12DescriptorHeap_Release(dsv_heap);
ID3D12Resource_Release(rt);
ID3D12Resource_Release(ds);
ID3D12Resource_Release(rt_ms);
ID3D12PipelineState_Release(pso);
ID3D12PipelineState_Release(pso_ms);
ID3D12RootSignature_Release(root_signature);
ID3D12GraphicsCommandList4_Release(command_list4);
destroy_test_context(&context);
}
void test_scissor_clamping(void)
{
const float black[4] = { 1.0f / 255.0f, 1.0f / 255.0, 1.0f / 255.0f, 1.0f / 255.0f };
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
struct test_context_desc context_desc;
D3D12_CPU_DESCRIPTOR_HANDLE desc[3];
D3D12_ROOT_SIGNATURE_DESC rs_desc;
ID3D12DescriptorHeap *rtv_heap;
struct test_context context;
ID3D12Resource *highres[2];
ID3D12Resource *lowres;
D3D12_VIEWPORT vp;
D3D12_RECT sci;
unsigned int i;
HRESULT hr;
#include "shaders/render_target/headers/vs_flat_color.h"
#include "shaders/render_target/headers/ps_flat_color.h"
memset(&context_desc, 0, sizeof(context_desc));
context_desc.no_render_target = true;
context_desc.no_pipeline = true;
if (!init_test_context(&context, &context_desc))
return;
memset(&rs_desc, 0, sizeof(rs_desc));
create_root_signature(context.device, &rs_desc, &context.root_signature);
init_pipeline_state_desc(&pso_desc, context.root_signature, DXGI_FORMAT_R8G8B8A8_UNORM, &vs_flat_color_dxbc, &ps_flat_color_dxbc, NULL);
pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&context.pipeline_state);
ok(SUCCEEDED(hr), "Failed to create PSO, hr #%x.\n", hr);
rtv_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 3);
highres[0] = create_default_texture2d(context.device, 1920, 1080, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET);
highres[1] = create_default_texture2d(context.device, 1920, 1080, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET);
lowres = create_default_texture2d(context.device, 480, 270, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET);
for (i = 0; i < 3; i++)
desc[i] = get_cpu_rtv_handle(&context, rtv_heap, i);
ID3D12Device_CreateRenderTargetView(context.device, highres[0], NULL, desc[0]);
ID3D12Device_CreateRenderTargetView(context.device, lowres, NULL, desc[1]);
ID3D12Device_CreateRenderTargetView(context.device, highres[1], NULL, desc[2]);
set_rect(&sci, 0, 0, 1920, 1080);
set_viewport(&vp, 0, 0, 1920, 1080, 0, 1);
/* Try clearing out of bounds too. Does not trigger validation error either >_< */
for (i = 0; i < 3; i++)
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, desc[i], black, 1, &sci);
transition_resource_state(context.list, highres[0], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_resource_state(context.list, highres[1], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_resource_state(context.list, lowres, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(highres[0], 0, context.queue, context.list, 0x01010101, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(highres[1], 0, context.queue, context.list, 0x01010101, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(lowres, 0, context.queue, context.list, 0x01010101, 0);
reset_command_list(context.list, context.allocator);
transition_resource_state(context.list, highres[0], D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
transition_resource_state(context.list, highres[1], D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
transition_resource_state(context.list, lowres, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &sci);
ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &vp);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
/* When rendering low-res target, it will have scissor out of bounds. There is no validation error when doing so. */
for (i = 0; i < 3; i++)
{
ID3D12GraphicsCommandList_OMSetRenderTargets(context.list, 1, &desc[i], TRUE, NULL);
ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 1, 0, 0);
}
transition_resource_state(context.list, highres[0], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_resource_state(context.list, highres[1], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
transition_resource_state(context.list, lowres, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(highres[0], 0, context.queue, context.list, ~0u, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(highres[1], 0, context.queue, context.list, ~0u, 0);
reset_command_list(context.list, context.allocator);
check_sub_resource_uint(lowres, 0, context.queue, context.list, ~0u, 0);
reset_command_list(context.list, context.allocator);
ID3D12Resource_Release(highres[0]);
ID3D12Resource_Release(highres[1]);
ID3D12Resource_Release(lowres);
ID3D12DescriptorHeap_Release(rtv_heap);
destroy_test_context(&context);
}
void test_mismatching_rtv_dsv_size(void)
{
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
ID3D12DescriptorHeap *rtv_heap, *dsv_heap;
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[2], dsv;
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc;
D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc;
struct test_context_desc context_desc;
D3D12_HEAP_PROPERTIES heap_properties;
D3D12_ROOT_SIGNATURE_DESC rs_desc;
D3D12_RESOURCE_DESC resource_desc;
ID3D12Resource *rt[3], *ds[3];
unsigned int i, j, x, y, w, h;
struct resource_readback rb;
struct test_context context;
D3D12_VIEWPORT viewport;
RECT scissor;
HRESULT hr;
#include "shaders/render_target/headers/ps_rt_mismatch.h"
static const FLOAT red[] = { 1.0f, 0.0, 0.0f, 1.0f };
static const uint32_t rt_ds_size[][2] =
{
{ 4, 4 },
{ 6, 2 },
{ 8, 8 },
};
struct
{
uint32_t rt_count;
uint32_t rtvs[2];
uint32_t dsv;
bool expected;
}
tests[] =
{
/* Mismatched RTV-DSV size */
{ 1, { 0, 0 }, 0 },
{ 1, { 0, 0 }, 1 },
{ 1, { 0, 0 }, 2 },
{ 1, { 1, 0 }, 0 },
{ 1, { 1, 0 }, 1 },
{ 1, { 1, 0 }, 2 },
{ 1, { 2, 0 }, 0 },
{ 1, { 2, 0 }, 1 },
{ 1, { 2, 0 }, 2 },
/* Mismatched RTV sizes with no DSV */
{ 2, { 0, 1 }, ~0u },
{ 2, { 0, 2 }, ~0u },
{ 2, { 1, 0 }, ~0u },
{ 2, { 1, 2 }, ~0u },
{ 2, { 2, 0 }, ~0u },
{ 2, { 2, 1 }, ~0u },
/* Mismatched RTV sizes with max size dsv */
{ 2, { 0, 1 }, 2 },
{ 2, { 0, 2 }, 2 },
{ 2, { 1, 0 }, 2 },
{ 2, { 1, 2 }, 2 },
{ 2, { 2, 0 }, 2 },
{ 2, { 2, 1 }, 2 },
};
memset(&context_desc, 0, sizeof(context_desc));
context_desc.no_render_target = true;
context_desc.no_pipeline = true;
if (!init_test_context(&context, &context_desc))
return;
memset(&rs_desc, 0, sizeof(rs_desc));
hr = create_root_signature(context.device, &rs_desc, &context.root_signature);
ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr);
init_pipeline_state_desc(&pso_desc, context.root_signature, 0, NULL, &ps_rt_mismatch_dxbc, NULL);
pso_desc.DepthStencilState.DepthEnable = TRUE;
pso_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
pso_desc.NumRenderTargets = ARRAY_SIZE(rtvs);
for (i = 0; i < ARRAY_SIZE(rtvs); i++)
pso_desc.RTVFormats[i] = DXGI_FORMAT_R8G8B8A8_UNORM;
pso_desc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc, &IID_ID3D12PipelineState, (void**)&context.pipeline_state);
ok(hr == S_OK, "Failed to create graphics pipeline, hr %#x.\n", hr);
rtv_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, ARRAY_SIZE(rt_ds_size));
dsv_heap = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, ARRAY_SIZE(rt_ds_size));
memset(&heap_properties, 0, sizeof(heap_properties));
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
memset(&resource_desc, 0, sizeof(resource_desc));
for (i = 0; i < ARRAY_SIZE(rt_ds_size); i++)
{
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resource_desc.Width = rt_ds_size[i][0];
resource_desc.Height = rt_ds_size[i][1];
resource_desc.DepthOrArraySize = 1;
resource_desc.MipLevels = 1;
resource_desc.SampleDesc.Count = 1;
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
hr = ID3D12Device_CreateCommittedResource(context.device, &heap_properties, D3D12_HEAP_FLAG_NONE,
&resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void**)&rt[i]);
ok(hr == S_OK, "Failed to create color image, hr %#x.\n", hr);
memset(&rtv_desc, 0, sizeof(rtv_desc));
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
ID3D12Device_CreateRenderTargetView(context.device, rt[i], &rtv_desc, get_cpu_rtv_handle(&context, rtv_heap, i));
resource_desc.Format = DXGI_FORMAT_D32_FLOAT;
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
hr = ID3D12Device_CreateCommittedResource(context.device, &heap_properties, D3D12_HEAP_FLAG_NONE,
&resource_desc, D3D12_RESOURCE_STATE_DEPTH_WRITE, NULL, &IID_ID3D12Resource, (void**)&ds[i]);
ok(hr == S_OK, "Failed to create depth image, hr %#x.\n", hr);
memset(&dsv_desc, 0, sizeof(dsv_desc));
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
ID3D12Device_CreateDepthStencilView(context.device, ds[i], &dsv_desc, get_cpu_dsv_handle(&context, dsv_heap, i));
}
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = 8.0f;
viewport.Height = 8.0f;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
scissor.left = 0;
scissor.top = 0;
scissor.bottom = 8;
scissor.right = 8;
for (i = 0; i < ARRAY_SIZE(tests); i++)
{
vkd3d_test_set_context("Test %u", i);
w = scissor.right;
h = scissor.bottom;
for (j = 0; j < tests[i].rt_count; j++)
{
rtvs[j] = get_cpu_rtv_handle(&context, rtv_heap, tests[i].rtvs[j]);
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, rtvs[j], red, 0, NULL);
w = min(w, rt_ds_size[tests[i].rtvs[j]][0]);
h = min(h, rt_ds_size[tests[i].rtvs[j]][1]);
}
if (tests[i].dsv != ~0u)
{
dsv = get_cpu_dsv_handle(&context, dsv_heap, tests[i].dsv);
ID3D12GraphicsCommandList_ClearDepthStencilView(context.list, dsv, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, NULL);
w = min(w, rt_ds_size[tests[i].dsv][0]);
h = min(h, rt_ds_size[tests[i].dsv][1]);
}
ID3D12GraphicsCommandList_OMSetRenderTargets(context.list,
tests[i].rt_count, rtvs, FALSE, tests[i].dsv != ~0u ? &dsv : NULL);
ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &scissor);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 1, 0, 0);
for (j = 0; j < tests[i].rt_count; j++)
transition_resource_state(context.list, rt[tests[i].rtvs[j]], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
if (tests[i].dsv != ~0u)
transition_resource_state(context.list, ds[tests[i].dsv], D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE);
/* This is undefined behaviour, and the exact areas written to the respective
* RTVs and DSV differ by vendor. The common denominator is that the all pixels
* included in all bound views get written. */
for (j = 0; j < tests[i].rt_count; j++)
{
get_texture_readback_with_command_list(rt[tests[i].rtvs[j]], 0, &rb, context.queue, context.list);
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
uint32_t got = get_readback_uint(&rb, x, y, 0);
uint32_t expected = 0xff00ff00;
ok(got == expected, "Got %#x, expected %#x at %u,%u.\n", got, expected, x, y);
if (got != expected)
break;
}
}
release_resource_readback(&rb);
reset_command_list(context.list, context.allocator);
transition_resource_state(context.list, rt[tests[i].rtvs[j]], D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
}
if (tests[i].dsv != ~0u)
{
get_texture_readback_with_command_list(ds[tests[i].dsv], 0, &rb, context.queue, context.list);
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
float got = get_readback_float(&rb, x, y);
float expected = 0.0f;
ok(got == expected, "Got %f, expected %f at %u,%u.\n", got, expected, x, y);
if (got != expected)
break;
}
}
release_resource_readback(&rb);
reset_command_list(context.list, context.allocator);
transition_resource_state(context.list, ds[tests[i].dsv], D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE);
}
}
ID3D12DescriptorHeap_Release(rtv_heap);
ID3D12DescriptorHeap_Release(dsv_heap);
for (i = 0; i < ARRAY_SIZE(rt_ds_size); i++)
{
ID3D12Resource_Release(rt[i]);
ID3D12Resource_Release(ds[i]);
}
destroy_test_context(&context);
}
void decode_rgb9e5(uint32_t packed, float color[3])
{
// No inf, nan, or implied 1 and thus no denorms
uint32_t r = (packed >> 0) & 0x1ffu;
uint32_t g = (packed >> 9) & 0x1ffu;
uint32_t b = (packed >> 18) & 0x1ffu;
uint32_t e = (packed >> 27);
float factor = (float)(1u << e) / (float)(1u << 24u);
color[0] = (float)r * factor;
color[1] = (float)g * factor;
color[2] = (float)b * factor;
}
void test_rgb9e5_rendering(void)
{
D3D12_FEATURE_DATA_FORMAT_SUPPORT format_query;
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
D3D12_CPU_DESCRIPTOR_HANDLE rtv_descriptor;
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc;
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc;
D3D12_HEAP_PROPERTIES heap_properties;
D3D12_ROOT_SIGNATURE_DESC rs_desc;
ID3D12DescriptorHeap *rtv_heap;
struct test_context_desc desc;
struct resource_readback rb;
struct test_context context;
D3D12_RESOURCE_DESC rt_desc;
ID3D12PipelineState *pso;
unsigned int i, x, y;
ID3D12Resource *rt;
D3D12_VIEWPORT vp;
D3D12_RECT sci;
HRESULT hr;
static uint32_t reference[16][16];
static const FLOAT white[] = { 1.0f, 1.0f, 1.0f, 1.0f };
#include "shaders/render_target/headers/ps_gradient.h"
#include "shaders/render_target/headers/vs_gradient.h"
memset(&desc, 0, sizeof(desc));
desc.no_pipeline = true;
desc.no_render_target = true;
if (!init_test_context(&context, &desc))
return;
memset(&format_query, 0, sizeof(format_query));
format_query.Format = DXGI_FORMAT_R9G9B9E5_SHAREDEXP;
hr = ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_FORMAT_SUPPORT, &format_query, sizeof(format_query));
if (FAILED(hr) || !(format_query.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET))
{
skip("RGB9E5 not supported for rendering.\n");
destroy_test_context(&context);
return;
}
memset(&rtv_heap_desc, 0, sizeof(rtv_heap_desc));
rtv_heap_desc.NumDescriptors = 1u;
rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
hr = ID3D12Device_CreateDescriptorHeap(context.device, &rtv_heap_desc, &IID_ID3D12DescriptorHeap, (void**)&rtv_heap);
ok(hr == S_OK, "Failed to create descriptor heap, hr %#x.\n", hr);
rtv_descriptor = get_cpu_rtv_handle(&context, rtv_heap, 0);
memset(&heap_properties, 0, sizeof(heap_properties));
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
memset(&rt_desc, 0, sizeof(rt_desc));
rt_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
rt_desc.Width = 16;
rt_desc.Height = 16;
rt_desc.DepthOrArraySize = 1;
rt_desc.MipLevels = 1;
rt_desc.SampleDesc.Count = 1;
rt_desc.Format = DXGI_FORMAT_R9G9B9E5_SHAREDEXP;
rt_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
rt_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
hr = ID3D12Device_CreateCommittedResource(context.device, &heap_properties, D3D12_HEAP_FLAG_NONE,
&rt_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void**)&rt);
ok(hr == S_OK, "Failed to create render target, hr %#x.\n", hr);
memset(&rtv_desc, 0, sizeof(rtv_desc));
rtv_desc.Format = DXGI_FORMAT_R9G9B9E5_SHAREDEXP;
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
ID3D12Device_CreateRenderTargetView(context.device, rt, &rtv_desc, rtv_descriptor);
memset(&rs_desc, 0, sizeof(rs_desc));
create_root_signature(context.device, &rs_desc, &context.root_signature);
init_pipeline_state_desc(&pso_desc, context.root_signature, DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
&vs_gradient_dxbc, &ps_gradient_dxbc, NULL);
pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc, &IID_ID3D12PipelineState, (void**)&pso);
ok(hr == S_OK, "Failed to create graphics pipeline, hr %#x.\n", hr);
memset(&vp, 0, sizeof(vp));
vp.Width = 16.0f;
vp.Height = 16.0f;
vp.MaxDepth = 1.0f;
memset(&sci, 0, sizeof(sci));
sci.right = 16;
sci.bottom = 16;
ID3D12GraphicsCommandList_OMSetRenderTargets(context.list, 1, &rtv_descriptor, TRUE, NULL);
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, rtv_descriptor, white, 0, NULL);
ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &vp);
ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &sci);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(context.list, pso);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 1, 0, 0);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
get_texture_readback_with_command_list(rt, 0, &rb, context.queue, context.list);
for (x = 0; x < 16; x++)
{
for (y = 0; y < 16; y++)
{
float rgb_got[3], rgb_expected[3];
uint32_t packed = get_readback_uint(&rb, x, y, 0);
rgb_expected[0] = (((float)x) + 0.5f) / 16.0f;
rgb_expected[1] = 1.0f - (((float)y) + 0.5f) / 16.0f;
rgb_expected[2] = rgb_expected[0] + rgb_expected[1];
decode_rgb9e5(packed, rgb_got);
for (i = 0; i < 3; i++)
ok(fabs(rgb_got[i] - rgb_expected[i]) < 0.01f, "Got %f, expected %f for channel %u at %u,%u.\n", rgb_got[i], rgb_expected[i], i, x, y);
reference[x][y] = packed;
}
}
release_resource_readback(&rb);
ID3D12PipelineState_Release(pso);
reset_command_list(context.list, context.allocator);
pso_desc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0x7u; /* no alpha */
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc, &IID_ID3D12PipelineState, (void**)&pso);
ok(hr == S_OK, "Failed to create graphics pipeline, hr %#x.\n", hr);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
ID3D12GraphicsCommandList_OMSetRenderTargets(context.list, 1, &rtv_descriptor, TRUE, NULL);
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, rtv_descriptor, white, 0, NULL);
ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &vp);
ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &sci);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(context.list, pso);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 1, 0, 0);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
get_texture_readback_with_command_list(rt, 0, &rb, context.queue, context.list);
for (x = 0; x < 16; x++)
{
for (y = 0; y < 16; y++)
{
uint32_t packed = get_readback_uint(&rb, x, y, 0);
ok(packed == reference[x][y], "Got %#x, expected %#x at %u,%u.\n", packed, reference[x][y], x, y);
}
}
release_resource_readback(&rb);
ID3D12PipelineState_Release(pso);
reset_command_list(context.list, context.allocator);
pso_desc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0x8u; /* only alpha */
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc, &IID_ID3D12PipelineState, (void**)&pso);
ok(hr == S_OK, "Failed to create graphics pipeline, hr %#x.\n", hr);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
ID3D12GraphicsCommandList_OMSetRenderTargets(context.list, 1, &rtv_descriptor, TRUE, NULL);
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, rtv_descriptor, white, 0, NULL);
ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &vp);
ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &sci);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(context.list, pso);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 1, 0, 0);
transition_resource_state(context.list, rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
get_texture_readback_with_command_list(rt, 0, &rb, context.queue, context.list);
for (x = 0; x < 16; x++)
{
for (y = 0; y < 16; y++)
{
float rgb_got[3];
uint32_t packed = get_readback_uint(&rb, x, y, 0);
decode_rgb9e5(packed, rgb_got);
for (i = 0; i < 3; i++)
ok(rgb_got[i] == 1.0f, "Got %f, expected 1.0 for channel %u at %u,%u.\n", rgb_got[i], i, x, y);
}
}
release_resource_readback(&rb);
ID3D12PipelineState_Release(pso);
ID3D12Resource_Release(rt);
ID3D12DescriptorHeap_Release(rtv_heap);
destroy_test_context(&context);
}