diff --git a/util/test/demos/d3d12/d3d12_pixel_history.cpp b/util/test/demos/d3d12/d3d12_pixel_history.cpp
new file mode 100644
index 000000000..a001d13df
--- /dev/null
+++ b/util/test/demos/d3d12/d3d12_pixel_history.cpp
@@ -0,0 +1,740 @@
+/******************************************************************************
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Baldur Karlsson
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ ******************************************************************************/
+
+#include "d3d12_test.h"
+
+RD_TEST(D3D12_Pixel_History, D3D12GraphicsTest)
+{
+ static constexpr const char *Description = "Tests pixel history";
+
+ std::string common = R"EOSHADER(
+struct v2f
+{
+ float4 pos : SV_POSITION;
+ float4 col : COLOR0;
+ float2 uv : TEXCOORD0;
+};
+
+)EOSHADER";
+
+ const std::string vertex = R"EOSHADER(
+
+struct vertin
+{
+ float3 pos : POSITION;
+ float4 col : COLOR0;
+ float2 uv : TEXCOORD0;
+};
+
+v2f main(vertin IN, uint vid : SV_VertexID)
+{
+ v2f OUT = (v2f)0;
+
+ OUT.pos = float4(IN.pos, 1.0f);
+ OUT.col = IN.col;
+ OUT.uv = IN.uv;
+
+ return OUT;
+}
+
+)EOSHADER";
+
+ const std::string pixel = R"EOSHADER(
+
+float4 main(v2f vertIn) : SV_Target0
+{
+ if (vertIn.pos.x < 151 && vertIn.pos.x > 150)
+ discard;
+ return vertIn.col + float4(0, 0, 0, 1.75);
+}
+
+)EOSHADER";
+
+ std::string mspixel = R"EOSHADER(
+
+float4 main(v2f vertIn, uint primId : SV_PrimitiveID, uint sampleId : SV_SampleIndex) : SV_Target0
+{
+ float4 color = (float4)0;
+ if(primId == 0)
+ {
+ color = float4(1, 0, 1, 2.75);
+ }
+ else
+ {
+ if (sampleId == 0)
+ color = float4(1, 0, 0, 2.75);
+ else if (sampleId == 1)
+ color = float4(0, 0, 1, 2.75);
+ else if (sampleId == 2)
+ color = float4(0, 1, 1, 2.75);
+ else if (sampleId == 3)
+ color = float4(1, 1, 1, 2.75);
+ }
+
+ return color;
+}
+
+)EOSHADER";
+
+ int main()
+ {
+ // initialise, create window, create context, etc
+ if(!Init())
+ return 3;
+
+ DefaultA2V VBData[] = {
+ // this triangle occludes in depth
+ {Vec3f(-0.5f, -0.5f, 0.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(-0.5f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.0f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // this triangle occludes in stencil
+ {Vec3f(-0.5f, 0.0f, 0.9f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(-0.5f, 0.5f, 0.9f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.0f, 0.0f, 0.9f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // this triangle is just in the background to contribute to overdraw
+ {Vec3f(-0.9f, -0.9f, 0.95f), Vec4f(1.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.0f, 0.9f, 0.95f), Vec4f(1.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.9f, -0.9f, 0.95f), Vec4f(1.0f, 0.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // the draw has a few triangles, main one that is occluded for depth, another that is
+ // adding to overdraw complexity, one that is backface culled, then a few more of various
+ // sizes for triangle size overlay
+ {Vec3f(-0.3f, -0.5f, 0.5f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(-0.3f, 0.5f, 0.5f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.5f, 0.0f, 0.5f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ {Vec3f(-0.2f, -0.2f, 0.6f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.2f, 0.0f, 0.6f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.2f, -0.4f, 0.6f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // backface culled
+ {Vec3f(0.1f, 0.0f, 0.5f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.5f, -0.2f, 0.5f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.5f, 0.2f, 0.5f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // depth clipped (i.e. not clamped)
+ {Vec3f(0.6f, 0.0f, 0.5f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.7f, 0.2f, 0.5f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.8f, 0.0f, 1.5f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // small triangles
+ // size=0.005
+ {Vec3f(0.0f, 0.4f, 0.5f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.0f, 0.41f, 0.5f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.01f, 0.4f, 0.5f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // size=0.015
+ {Vec3f(0.0f, 0.5f, 0.5f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.0f, 0.515f, 0.5f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.015f, 0.5f, 0.5f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // size=0.02
+ {Vec3f(0.0f, 0.6f, 0.5f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.0f, 0.62f, 0.5f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.02f, 0.6f, 0.5f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // size=0.025
+ {Vec3f(0.0f, 0.7f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.0f, 0.725f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.025f, 0.7f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // dynamic triangles
+ {Vec3f(-0.6f, -0.75f, 0.5f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(-0.5f, -0.65f, 0.5f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(-0.4f, -0.75f, 0.5f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ {Vec3f(-0.6f, -0.75f, 0.5f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(-0.5f, -0.65f, 0.5f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(-0.4f, -0.75f, 0.5f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ {Vec3f(-0.6f, -0.75f, 0.5f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(-0.5f, -0.65f, 0.5f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(-0.4f, -0.75f, 0.5f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ {Vec3f(-0.6f, -0.75f, 0.5f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(-0.5f, -0.65f, 0.5f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(-0.4f, -0.75f, 0.5f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // Different depth triangles
+ {Vec3f(0.0f, -0.8f, 0.97f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.4f, -0.2f, 0.97f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.8f, -0.8f, 0.97f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ {Vec3f(0.2f, -0.8f, 0.20f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.4f, -0.4f, 0.20f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.6f, -0.8f, 0.20f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ {Vec3f(0.2f, -0.8f, 0.30f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.4f, -0.6f, 0.30f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.6f, -0.8f, 0.30f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ {Vec3f(0.2f, -0.8f, 0.10f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.4f, -0.7f, 0.10f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.6f, -0.8f, 0.10f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // Fails depth bounds test.
+ {Vec3f(0.2f, -0.8f, 0.05f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.4f, -0.7f, 0.05f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.6f, -0.8f, 0.05f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+
+ // Should be back face culled.
+ {Vec3f(0.6f, -0.8f, 0.25f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+ {Vec3f(0.4f, -0.7f, 0.25f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.2f, -0.8f, 0.25f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+
+ // depth bounds prep
+ {Vec3f(0.6f, 0.3f, 0.3f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.7f, 0.5f, 0.5f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.8f, 0.3f, 0.7f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+ // depth bounds clip
+ {Vec3f(0.6f, 0.3f, 0.3f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
+ {Vec3f(0.7f, 0.5f, 0.5f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
+ {Vec3f(0.8f, 0.3f, 0.7f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
+ };
+
+ ID3D12ResourcePtr vb = MakeBuffer().Data(VBData);
+
+ uint32_t rtvIndex = 1; // Start at 1, backbuffer takes id 0
+ uint32_t dsvIndex = 0;
+
+ const DXGI_FORMAT renderSurfaceFormat = DXGI_FORMAT_R8G8B8A8_TYPELESS;
+ const DXGI_FORMAT renderViewFormat = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
+ const DXGI_FORMAT depthFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
+
+ struct PassResources
+ {
+ std::string markerName;
+ D3D_SHADER_MODEL shaderModel;
+
+ ID3D12ResourcePtr mainRT;
+ D3D12_CPU_DESCRIPTOR_HANDLE mainRTV;
+ ID3D12ResourcePtr mainDS;
+ D3D12_CPU_DESCRIPTOR_HANDLE mainDSV;
+
+ ID3D12ResourcePtr mipArrayRT;
+ D3D12_CPU_DESCRIPTOR_HANDLE mipArraySubRTV;
+ ID3D12ResourcePtr mipArrayDS;
+ D3D12_CPU_DESCRIPTOR_HANDLE mipArraySubDSV;
+
+ ID3D12ResourcePtr msaaRT;
+ D3D12_CPU_DESCRIPTOR_HANDLE msaaRTV;
+ ID3D12ResourcePtr msaaDS;
+ D3D12_CPU_DESCRIPTOR_HANDLE msaaDSV;
+
+ ID3D12ResourcePtr msaaMipArrayRT;
+ D3D12_CPU_DESCRIPTOR_HANDLE msaaMipArraySubRTV;
+ ID3D12ResourcePtr msaaMipArrayDS;
+ D3D12_CPU_DESCRIPTOR_HANDLE msaaMipArraySubDSV;
+
+ ID3D12RootSignaturePtr rootSig;
+ ID3D12PipelineStatePtr depthWritePipe;
+ ID3D12PipelineStatePtr dynamicScissorPipe;
+ ID3D12PipelineStatePtr depthPipe;
+ ID3D12PipelineStatePtr stencilWritePipe;
+ ID3D12PipelineStatePtr backgroundPipe;
+ ID3D12PipelineStatePtr noPsPipe;
+ ID3D12PipelineStatePtr mainTestPipe;
+ ID3D12PipelineStatePtr cullFrontPipe;
+ ID3D12PipelineStatePtr depthBoundsPipe;
+ ID3D12PipelineStatePtr whitePipe;
+ ID3D12PipelineStatePtr msaaPipe;
+ };
+
+ struct DepthBoundsTestStream
+ {
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type0 = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE;
+ UINT Padding0;
+ ID3D12RootSignature *RootSignature;
+
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type1 = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1;
+ D3D12_DEPTH_STENCIL_DESC1 DepthStencil;
+ UINT Padding1;
+
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type2 = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER;
+ D3D12_RASTERIZER_DESC Rasterizer;
+
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type3 = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT;
+ D3D12_INPUT_LAYOUT_DESC InputLayout;
+
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type4 =
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS;
+ D3D12_RT_FORMAT_ARRAY RTVFormats;
+
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type5 =
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT;
+ DXGI_FORMAT DSVFormat;
+
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type6 = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS;
+ UINT Padding6;
+ D3D12_SHADER_BYTECODE VS;
+
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type7 = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS;
+ UINT Padding7;
+ D3D12_SHADER_BYTECODE PS;
+ } depthBoundsTestStream;
+
+ D3D12_STATIC_SAMPLER_DESC staticSamp = {};
+ staticSamp.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
+ staticSamp.AddressU = staticSamp.AddressV = staticSamp.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
+ staticSamp.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+
+ PassResources passes[3];
+ passes[0].shaderModel = D3D_SHADER_MODEL_5_1; // DXBC with optional bindless
+ passes[1].shaderModel = D3D_SHADER_MODEL_6_0; // DXIL with optional bindless
+ passes[2].shaderModel = D3D_SHADER_MODEL_6_6; // DXIL with direct heap access bindless
+ passes[0].markerName = "Begin SM5.1";
+ passes[1].markerName = "Begin SM6.0";
+ passes[2].markerName = "Begin SM6.6";
+
+ const std::string profileSuffix[3] = {"_5_1", "_6_0", "_6_6"};
+ const std::wstring nameSuffix[3] = {L"_SM51", L"_SM60", L"_SM66"};
+
+ bool supportSM66 = m_HighestShaderModel >= D3D_SHADER_MODEL_6_6;
+ int numPasses = (supportSM66 && m_DXILSupport) ? 3 : (m_DXILSupport ? 2 : 1);
+ for(int i = 0; i < numPasses; ++i)
+ {
+ PassResources &pass = passes[i];
+ pass.mainRT = MakeTexture(renderSurfaceFormat, screenWidth, screenHeight).RTV();
+ pass.mainRT->SetName((L"mainRT" + nameSuffix[i]).c_str());
+ pass.mainRTV = MakeRTV(pass.mainRT).Format(renderViewFormat).CreateCPU(rtvIndex++);
+
+ pass.mainDS = MakeTexture(depthFormat, screenWidth, screenHeight).DSV();
+ pass.mainDS->SetName((L"mainDS" + nameSuffix[i]).c_str());
+ pass.mainDSV = MakeDSV(pass.mainDS).Format(depthFormat).CreateCPU(dsvIndex++);
+
+ pass.mipArrayRT =
+ MakeTexture(renderSurfaceFormat, screenWidth, screenHeight).RTV().Mips(4).Array(5);
+ pass.mipArrayRT->SetName((L"mipArrayRT" + nameSuffix[i]).c_str());
+
+ pass.mipArraySubRTV = MakeRTV(pass.mipArrayRT)
+ .Format(renderViewFormat)
+ .FirstMip(2)
+ .NumMips(1)
+ .FirstSlice(2)
+ .NumSlices(1)
+ .CreateCPU(rtvIndex++);
+
+ pass.mipArrayDS = MakeTexture(depthFormat, screenWidth, screenHeight).DSV().Mips(4).Array(5);
+ pass.mipArrayDS->SetName((L"mipArrayDS" + nameSuffix[i]).c_str());
+
+ pass.mipArraySubDSV = MakeDSV(pass.mipArrayDS)
+ .Format(depthFormat)
+ .FirstMip(2)
+ .NumMips(1)
+ .FirstSlice(2)
+ .NumSlices(1)
+ .CreateCPU(dsvIndex++);
+
+ pass.msaaRT = MakeTexture(renderSurfaceFormat, screenWidth, screenHeight).RTV().Multisampled(4);
+ pass.msaaRT->SetName((L"msaaRT" + nameSuffix[i]).c_str());
+ pass.msaaRTV = MakeRTV(pass.msaaRT).Format(renderViewFormat).CreateCPU(rtvIndex++);
+
+ pass.msaaDS = MakeTexture(depthFormat, screenWidth, screenHeight).DSV().Multisampled(4);
+ pass.msaaDS->SetName((L"msaaDS" + nameSuffix[i]).c_str());
+ pass.msaaDSV = MakeDSV(pass.msaaDS).Format(depthFormat).CreateCPU(dsvIndex++);
+
+ pass.msaaMipArrayRT = MakeTexture(renderSurfaceFormat, screenWidth, screenHeight)
+ .RTV()
+ .Mips(1)
+ .Array(4)
+ .Multisampled(4);
+ pass.msaaMipArrayRT->SetName((L"msaaMipArrayRT" + nameSuffix[i]).c_str());
+ pass.msaaMipArraySubRTV = MakeRTV(pass.msaaMipArrayRT)
+ .Format(renderViewFormat)
+ .FirstMip(0)
+ .NumMips(1)
+ .FirstSlice(2)
+ .NumSlices(1)
+ .CreateCPU(rtvIndex++);
+
+ pass.msaaMipArrayDS =
+ MakeTexture(depthFormat, screenWidth, screenHeight).DSV().Mips(1).Array(4).Multisampled(4);
+ pass.msaaMipArrayDS->SetName((L"msaaMipArrayDS" + nameSuffix[i]).c_str());
+ pass.msaaMipArraySubDSV = MakeDSV(pass.msaaMipArrayDS)
+ .Format(depthFormat)
+ .FirstMip(0)
+ .NumMips(1)
+ .FirstSlice(2)
+ .NumSlices(1)
+ .CreateCPU(dsvIndex++);
+
+ ID3DBlobPtr vsBlob = Compile(common + vertex, "main", ("vs" + profileSuffix[i]).c_str());
+ ID3DBlobPtr psBlob = Compile(common + pixel, "main", ("ps" + profileSuffix[i]).c_str());
+ ID3DBlobPtr psMsaaBlob = Compile(common + mspixel, "main", ("ps" + profileSuffix[i]).c_str());
+
+ pass.rootSig =
+ MakeSig({}, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, 1, &staticSamp);
+ // TODO: Different root sig setup for SM6.6
+
+ D3D12PSOCreator baselinePSO = MakePSO()
+ .RootSig(pass.rootSig)
+ .InputLayout()
+ .RTVs({DXGI_FORMAT_R8G8B8A8_UNORM_SRGB})
+ .DSV(depthFormat)
+ .VS(vsBlob)
+ .PS(psBlob);
+
+ baselinePSO.GraphicsDesc.RasterizerState.DepthClipEnable = TRUE;
+ baselinePSO.GraphicsDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
+ D3D12_DEPTH_STENCIL_DESC &depthState = baselinePSO.GraphicsDesc.DepthStencilState;
+ depthState.DepthEnable = TRUE;
+ depthState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ depthState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ depthState.StencilEnable = FALSE;
+ depthState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ depthState.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
+ depthState.StencilReadMask = 0xff;
+ depthState.StencilWriteMask = 0xff;
+ depthState.BackFace = depthState.FrontFace;
+
+ depthState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ pass.depthWritePipe = baselinePSO;
+
+ depthState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
+ depthState.DepthEnable = FALSE;
+ pass.dynamicScissorPipe = baselinePSO;
+
+ depthState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
+ depthState.DepthEnable = TRUE;
+ depthState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+
+ depthBoundsTestStream.RootSignature = baselinePSO.GraphicsDesc.pRootSignature;
+ depthBoundsTestStream.DepthStencil.DepthEnable = depthState.DepthEnable;
+ depthBoundsTestStream.DepthStencil.DepthWriteMask = depthState.DepthWriteMask;
+ depthBoundsTestStream.DepthStencil.DepthFunc = depthState.DepthFunc;
+ depthBoundsTestStream.DepthStencil.StencilEnable = depthState.StencilEnable;
+ depthBoundsTestStream.DepthStencil.StencilReadMask = depthState.StencilReadMask;
+ depthBoundsTestStream.DepthStencil.StencilWriteMask = depthState.StencilWriteMask;
+ depthBoundsTestStream.DepthStencil.FrontFace = depthState.FrontFace;
+ depthBoundsTestStream.DepthStencil.BackFace = depthState.BackFace;
+ depthBoundsTestStream.DepthStencil.DepthBoundsTestEnable = TRUE;
+
+ depthBoundsTestStream.Rasterizer = baselinePSO.GraphicsDesc.RasterizerState;
+ depthBoundsTestStream.InputLayout = baselinePSO.GraphicsDesc.InputLayout;
+ depthBoundsTestStream.RTVFormats.NumRenderTargets = baselinePSO.GraphicsDesc.NumRenderTargets;
+ for(int j = 0; j < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++j)
+ depthBoundsTestStream.RTVFormats.RTFormats[j] = baselinePSO.GraphicsDesc.RTVFormats[j];
+ depthBoundsTestStream.DSVFormat = baselinePSO.GraphicsDesc.DSVFormat;
+
+ depthBoundsTestStream.VS.BytecodeLength = vsBlob->GetBufferSize();
+ depthBoundsTestStream.VS.pShaderBytecode = vsBlob->GetBufferPointer();
+ depthBoundsTestStream.PS.BytecodeLength = psBlob->GetBufferSize();
+ depthBoundsTestStream.PS.pShaderBytecode = psBlob->GetBufferPointer();
+
+ D3D12_PIPELINE_STATE_STREAM_DESC depthBoundsTestStreamDesc = {};
+ depthBoundsTestStreamDesc.SizeInBytes = sizeof(depthBoundsTestStream);
+ depthBoundsTestStreamDesc.pPipelineStateSubobjectStream = &depthBoundsTestStream;
+ HRESULT hr = dev2->CreatePipelineState(
+ &depthBoundsTestStreamDesc, __uuidof(ID3D12PipelineState), (void **)&pass.depthPipe);
+ TEST_ASSERT(hr == S_OK, "Pipe created");
+
+ depthState.StencilEnable = TRUE;
+ pass.stencilWritePipe = baselinePSO;
+
+ depthState.StencilEnable = FALSE;
+ pass.backgroundPipe = baselinePSO;
+
+ pass.noPsPipe = baselinePSO.PS(NULL);
+
+ depthState.StencilEnable = TRUE;
+ depthState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_GREATER;
+ pass.mainTestPipe = baselinePSO.PS(psBlob);
+
+ depthState.StencilEnable = FALSE;
+
+ baselinePSO.GraphicsDesc.RasterizerState.CullMode = D3D12_CULL_MODE_FRONT;
+ pass.cullFrontPipe = baselinePSO;
+
+ baselinePSO.GraphicsDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
+
+ depthBoundsTestStream.RootSignature = baselinePSO.GraphicsDesc.pRootSignature;
+ depthBoundsTestStream.DepthStencil.DepthEnable = TRUE;
+ depthBoundsTestStream.DepthStencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ depthBoundsTestStream.DepthStencil.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
+ depthBoundsTestStream.DepthStencil.StencilEnable = depthState.StencilEnable;
+ depthBoundsTestStream.DepthStencil.StencilReadMask = depthState.StencilReadMask;
+ depthBoundsTestStream.DepthStencil.StencilWriteMask = depthState.StencilWriteMask;
+ depthBoundsTestStream.DepthStencil.FrontFace = depthState.FrontFace;
+ depthBoundsTestStream.DepthStencil.BackFace = depthState.BackFace;
+ depthBoundsTestStream.DepthStencil.DepthBoundsTestEnable = TRUE;
+ depthBoundsTestStream.Rasterizer = baselinePSO.GraphicsDesc.RasterizerState;
+ depthBoundsTestStream.InputLayout = baselinePSO.GraphicsDesc.InputLayout;
+ depthBoundsTestStream.RTVFormats.NumRenderTargets = baselinePSO.GraphicsDesc.NumRenderTargets;
+ for(int j = 0; j < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++j)
+ depthBoundsTestStream.RTVFormats.RTFormats[j] = baselinePSO.GraphicsDesc.RTVFormats[j];
+ depthBoundsTestStream.DSVFormat = baselinePSO.GraphicsDesc.DSVFormat;
+
+ // Depth bounds values are set on the command list before draw
+ depthBoundsTestStream.VS.BytecodeLength = vsBlob->GetBufferSize();
+ depthBoundsTestStream.VS.pShaderBytecode = vsBlob->GetBufferPointer();
+ depthBoundsTestStream.PS.BytecodeLength = psBlob->GetBufferSize();
+ depthBoundsTestStream.PS.pShaderBytecode = psBlob->GetBufferPointer();
+ hr = dev2->CreatePipelineState(&depthBoundsTestStreamDesc, __uuidof(ID3D12PipelineState),
+ (void **)&pass.depthBoundsPipe);
+ TEST_ASSERT(hr == S_OK, "Pipe created");
+
+ depthState.StencilEnable = FALSE;
+ depthState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ pass.whitePipe = baselinePSO.DSV(DXGI_FORMAT_UNKNOWN);
+
+ depthState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ pass.msaaPipe = baselinePSO.PS(psMsaaBlob).DSV(depthFormat).SampleCount(4);
+ }
+
+ // TODO: Additional testing:
+ // CS UAV usage that doesn't write, does direct write, does atomic write
+ // Bindless access of target resource as UAV
+ // SM6.6 bindless access of target resource as UAV
+ // Pixel history of RT with depth/stencil changing formats throughout history
+ // Pixel history of DSV with render target changing formats throughout history
+ // Several RTs bound, tracking history for pixel in various RT slots
+ // RTs swapping position in RT array, tracking history of a color pixel
+ // RT/DSV with mips/slices, getting history of pixel in non-0 mip/slice
+
+ while(Running())
+ {
+ ID3D12GraphicsCommandList1Ptr cmd = GetCommandBuffer();
+ Reset(cmd);
+
+ for(int i = 0; i < numPasses; ++i)
+ {
+ PassResources &pass = passes[i];
+
+ pushMarker(cmd, pass.markerName);
+
+ ResourceBarrier(cmd, pass.mainDS, D3D12_RESOURCE_STATE_COMMON,
+ D3D12_RESOURCE_STATE_DEPTH_WRITE);
+ ResourceBarrier(cmd, pass.mainRT, D3D12_RESOURCE_STATE_COMMON,
+ D3D12_RESOURCE_STATE_RENDER_TARGET);
+ cmd->OMSetStencilRef(0x55);
+
+ D3D12_VIEWPORT v;
+ v.TopLeftX = 10;
+ v.TopLeftY = 10;
+ v.MinDepth = 0;
+ v.MaxDepth = 1;
+ v.Width = screenWidth - 20.0f;
+ v.Height = screenHeight - 20.0f;
+ RSSetViewport(cmd, v);
+
+ D3D12_RECT scissor;
+ scissor.left = scissor.top = 0;
+ scissor.right = screenWidth;
+ scissor.bottom = screenHeight;
+ RSSetScissorRect(cmd, scissor);
+
+ IASetVertexBuffer(cmd, vb, sizeof(DefaultA2V), 0);
+ cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+
+ float clearColor[4] = {0.2f, 0.2f, 0.2f, 1.0f};
+ cmd->OMSetRenderTargets(1, &pass.mainRTV, FALSE, &pass.mainDSV);
+ cmd->ClearRenderTargetView(pass.mainRTV, clearColor, 0, NULL);
+ cmd->ClearDepthStencilView(pass.mainDSV, D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL,
+ 1.0f, 0, 0, NULL);
+
+ cmd->SetGraphicsRootSignature(pass.rootSig);
+
+ // Draw the setup triangles
+
+ setMarker(cmd, "Depth Write");
+ cmd->SetPipelineState(pass.depthWritePipe);
+ cmd->DrawInstanced(3, 1, 0, 0);
+
+ setMarker(cmd, "Unbound Fragment Shader");
+ cmd->SetPipelineState(pass.noPsPipe);
+ cmd->DrawInstanced(3, 1, 3, 0);
+
+ setMarker(cmd, "Stencil Write");
+ cmd->SetPipelineState(pass.stencilWritePipe);
+ cmd->DrawInstanced(3, 1, 3, 0);
+
+ setMarker(cmd, "Background");
+ cmd->SetPipelineState(pass.backgroundPipe);
+ cmd->DrawInstanced(3, 1, 6, 0);
+
+ setMarker(cmd, "Cull Front");
+ cmd->SetPipelineState(pass.cullFrontPipe);
+ cmd->DrawInstanced(3, 1, 0, 0);
+
+ setMarker(cmd, "Depth Bounds Prep");
+ cmd->SetPipelineState(pass.depthBoundsPipe);
+ cmd->OMSetDepthBounds(0.0f, 1.0f);
+ cmd->DrawInstanced(3, 1, 63, 0);
+ setMarker(cmd, "Depth Bounds Clip");
+ cmd->OMSetDepthBounds(0.4f, 0.6f);
+ cmd->DrawInstanced(3, 1, 66, 0);
+
+ // Add a marker so we can easily locate this draw
+ setMarker(cmd, "Test Begin");
+
+ cmd->SetPipelineState(pass.mainTestPipe);
+ cmd->DrawInstanced(24, 1, 9, 0);
+
+ setMarker(cmd, "Fixed Scissor Fail");
+ cmd->SetPipelineState(pass.dynamicScissorPipe);
+ D3D12_RECT testScissor;
+ testScissor.left = 95;
+ testScissor.top = 245;
+ testScissor.right = 99;
+ testScissor.bottom = 249;
+ RSSetScissorRect(cmd, testScissor);
+ cmd->DrawInstanced(3, 1, 33, 0);
+
+ setMarker(cmd, "Fixed Scissor Pass");
+ cmd->SetPipelineState(pass.dynamicScissorPipe);
+ testScissor.left = 95;
+ testScissor.top = 245;
+ testScissor.right = 105;
+ testScissor.bottom = 255;
+ RSSetScissorRect(cmd, testScissor);
+ cmd->DrawInstanced(3, 1, 36, 0);
+
+ setMarker(cmd, "Dynamic Stencil Ref");
+ cmd->SetPipelineState(pass.dynamicScissorPipe);
+ RSSetScissorRect(cmd, scissor);
+ cmd->OMSetStencilRef(0x67);
+ cmd->DrawInstanced(3, 1, 39, 0);
+
+ setMarker(cmd, "Dynamic Stencil Mask");
+ cmd->SetPipelineState(pass.dynamicScissorPipe);
+ cmd->DrawInstanced(3, 1, 42, 0);
+
+ // Six triangles, five fragments reported.
+ // 0: Fails depth test
+ // 1: Passes
+ // 2: Fails depth test compared to 1st fragment
+ // 3: Passes
+ // 4: Fails depth bounds test
+ // 5: Fails backface culling, not reported.
+ setMarker(cmd, "Depth Test");
+ cmd->SetPipelineState(pass.depthPipe);
+ cmd->OMSetDepthBounds(0.15f, 1.0f);
+ cmd->DrawInstanced(6 * 3, 1, 45, 0);
+
+ {
+ pushMarker(cmd, "Begin MSAA");
+
+ ResourceBarrier(cmd, pass.msaaDS, D3D12_RESOURCE_STATE_COMMON,
+ D3D12_RESOURCE_STATE_DEPTH_WRITE);
+ ResourceBarrier(cmd, pass.msaaRT, D3D12_RESOURCE_STATE_COMMON,
+ D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ cmd->OMSetRenderTargets(1, &pass.msaaRTV, FALSE, &pass.msaaDSV);
+ float clearColorMsaa[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ cmd->ClearRenderTargetView(pass.msaaRTV, clearColorMsaa, 0, NULL);
+ cmd->ClearDepthStencilView(
+ pass.msaaDSV, D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 0.0f, 0, 0, NULL);
+
+ cmd->SetPipelineState(pass.msaaPipe);
+
+ setMarker(cmd, "Multisampled: test");
+ cmd->DrawInstanced(6, 1, 3, 0);
+
+ ResourceBarrier(cmd, pass.msaaDS, D3D12_RESOURCE_STATE_DEPTH_WRITE,
+ D3D12_RESOURCE_STATE_COMMON);
+ ResourceBarrier(cmd, pass.msaaRT, D3D12_RESOURCE_STATE_RENDER_TARGET,
+ D3D12_RESOURCE_STATE_COMMON);
+
+ popMarker(cmd);
+ }
+
+ v.Width = screenWidth / 4.0f - 10;
+ v.Height = screenHeight / 4.0f - 10;
+ v.TopLeftX = 5.0f;
+ v.TopLeftY = 5.0f;
+
+ scissor.right = (scissor.right - scissor.left) / 4 + scissor.left;
+ scissor.bottom = (scissor.bottom - scissor.top) / 4 + scissor.top;
+
+ // Render to a secondary surface
+ {
+ pushMarker(cmd, "Begin RenderPass Secondary");
+
+ ResourceBarrier(cmd, pass.mipArrayDS, D3D12_RESOURCE_STATE_COMMON,
+ D3D12_RESOURCE_STATE_DEPTH_WRITE);
+ ResourceBarrier(cmd, pass.mipArrayRT, D3D12_RESOURCE_STATE_COMMON,
+ D3D12_RESOURCE_STATE_RENDER_TARGET);
+ cmd->OMSetRenderTargets(1, &pass.mipArraySubRTV, FALSE, NULL);
+ float clearColorSecondary[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ cmd->ClearRenderTargetView(pass.mipArraySubRTV, clearColorSecondary, 0, NULL);
+ cmd->OMSetStencilRef(0x55);
+
+ IASetVertexBuffer(cmd, vb, sizeof(DefaultA2V), 0);
+ cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ cmd->SetPipelineState(pass.whitePipe);
+
+ RSSetViewport(cmd, v);
+ RSSetScissorRect(cmd, scissor);
+
+ setMarker(cmd, "Secondary: background");
+ cmd->DrawInstanced(6, 1, 3, 0);
+ setMarker(cmd, "Secondary: culled");
+ cmd->DrawInstanced(6, 1, 12, 0);
+ setMarker(cmd, "Secondary: pink");
+ cmd->DrawInstanced(9, 1, 24, 0);
+ setMarker(cmd, "Secondary: red and blue");
+ cmd->DrawInstanced(6, 1, 0, 0);
+
+ ResourceBarrier(cmd, pass.mipArrayDS, D3D12_RESOURCE_STATE_DEPTH_WRITE,
+ D3D12_RESOURCE_STATE_COMMON);
+ ResourceBarrier(cmd, pass.mipArrayRT, D3D12_RESOURCE_STATE_RENDER_TARGET,
+ D3D12_RESOURCE_STATE_COMMON);
+ popMarker(cmd);
+ }
+
+ ResourceBarrier(cmd, pass.mainDS, D3D12_RESOURCE_STATE_DEPTH_WRITE,
+ D3D12_RESOURCE_STATE_COMMON);
+ ResourceBarrier(cmd, pass.mainRT, D3D12_RESOURCE_STATE_RENDER_TARGET,
+ D3D12_RESOURCE_STATE_COMMON);
+
+ popMarker(cmd);
+ }
+
+ // Now blit the main render targets to the back buffer
+ ID3D12ResourcePtr bb = StartUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET);
+ for(int i = 0; i < numPasses; ++i)
+ {
+ ResourceBarrier(cmd, passes[i].mainRT, D3D12_RESOURCE_STATE_COMMON,
+ D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+
+ blitToSwap(cmd, passes[i].mainRT, bb, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
+
+ ResourceBarrier(cmd, passes[i].mainRT, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
+ D3D12_RESOURCE_STATE_COMMON);
+ }
+ FinishUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ cmd->Close();
+
+ Submit({cmd});
+ Present();
+ }
+
+ return 0;
+ }
+};
+
+REGISTER_TEST();
diff --git a/util/test/demos/d3d12/d3d12_test.cpp b/util/test/demos/d3d12/d3d12_test.cpp
index b084ac116..dedbf0bf7 100644
--- a/util/test/demos/d3d12/d3d12_test.cpp
+++ b/util/test/demos/d3d12/d3d12_test.cpp
@@ -342,14 +342,14 @@ void D3D12GraphicsTest::PostDeviceCreate()
D3D12_DESCRIPTOR_HEAP_DESC desc;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NodeMask = 1;
- desc.NumDescriptors = 32;
+ desc.NumDescriptors = 128;
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
CHECK_HR(dev->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)&m_RTV));
m_RTV->SetName(L"RTV heap");
- desc.NumDescriptors = 1;
+ desc.NumDescriptors = 16;
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
CHECK_HR(dev->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)&m_DSV));
@@ -1027,7 +1027,7 @@ void D3D12GraphicsTest::popMarker(ID3D12GraphicsCommandListPtr cmd)
}
void D3D12GraphicsTest::blitToSwap(ID3D12GraphicsCommandListPtr cmd, ID3D12ResourcePtr src,
- ID3D12ResourcePtr dst)
+ ID3D12ResourcePtr dst, DXGI_FORMAT srvFormat)
{
D3D12_CPU_DESCRIPTOR_HANDLE rtv = MakeRTV(dst).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(0);
@@ -1040,7 +1040,11 @@ void D3D12GraphicsTest::blitToSwap(ID3D12GraphicsCommandListPtr cmd, ID3D12Resou
idx++;
idx %= 6;
- D3D12_GPU_DESCRIPTOR_HANDLE handle = MakeSRV(src).CreateGPU(1024 + idx);
+ D3D12_GPU_DESCRIPTOR_HANDLE handle;
+ if(srvFormat == DXGI_FORMAT_UNKNOWN)
+ handle = MakeSRV(src).CreateGPU(1024 + idx);
+ else
+ handle = MakeSRV(src).Format(srvFormat).CreateGPU(1024 + idx);
cmd->SetDescriptorHeaps(1, &m_CBVUAVSRV.GetInterfacePtr());
cmd->SetGraphicsRootDescriptorTable(0, handle);
diff --git a/util/test/demos/d3d12/d3d12_test.h b/util/test/demos/d3d12/d3d12_test.h
index e2c5d922e..6a9a261c8 100644
--- a/util/test/demos/d3d12/d3d12_test.h
+++ b/util/test/demos/d3d12/d3d12_test.h
@@ -151,7 +151,8 @@ struct D3D12GraphicsTest : public GraphicsTest
void setMarker(ID3D12GraphicsCommandListPtr cmd, const std::string &name);
void popMarker(ID3D12GraphicsCommandListPtr cmd);
- void blitToSwap(ID3D12GraphicsCommandListPtr cmd, ID3D12ResourcePtr src, ID3D12ResourcePtr dst);
+ void blitToSwap(ID3D12GraphicsCommandListPtr cmd, ID3D12ResourcePtr src, ID3D12ResourcePtr dst,
+ DXGI_FORMAT srvFormat = DXGI_FORMAT_UNKNOWN);
void ResourceBarrier(ID3D12GraphicsCommandListPtr cmd, ID3D12ResourcePtr res,
D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after);
diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj
index 8ab842f39..4b3ca4a97 100644
--- a/util/test/demos/demos.vcxproj
+++ b/util/test/demos/demos.vcxproj
@@ -202,6 +202,7 @@
+
diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters
index 8bc0b96dd..234a05fef 100644
--- a/util/test/demos/demos.vcxproj.filters
+++ b/util/test/demos/demos.vcxproj.filters
@@ -679,6 +679,9 @@
Vulkan\demos
+
+ D3D12\demos
+