diff --git a/util/test/demos/d3d11/d3d11_helpers.cpp b/util/test/demos/d3d11/d3d11_helpers.cpp index 332c79cc5..fc14e8be2 100644 --- a/util/test/demos/d3d11/d3d11_helpers.cpp +++ b/util/test/demos/d3d11/d3d11_helpers.cpp @@ -738,7 +738,7 @@ D3D11ViewCreator::operator ID3D11ShaderResourceViewPtr() if(desc.srv.ViewDimension == D3D11_SRV_DIMENSION_BUFFER) { D3D11_BUFFER_DESC bufdesc; - ((ID3D11Buffer *)m_Res)->GetDesc(&bufdesc); + ((ID3D11BufferPtr)m_Res)->GetDesc(&bufdesc); if(bufdesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) { @@ -772,7 +772,7 @@ D3D11ViewCreator::operator ID3D11UnorderedAccessViewPtr() if(desc.uav.ViewDimension == D3D11_UAV_DIMENSION_BUFFER) { D3D11_BUFFER_DESC bufdesc; - ((ID3D11Buffer *)m_Res)->GetDesc(&bufdesc); + ((ID3D11BufferPtr)m_Res)->GetDesc(&bufdesc); if(bufdesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) desc.uav.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW; diff --git a/util/test/demos/d3d11/d3d11_helpers.h b/util/test/demos/d3d11/d3d11_helpers.h index aadbdc724..73aef4037 100644 --- a/util/test/demos/d3d11/d3d11_helpers.h +++ b/util/test/demos/d3d11/d3d11_helpers.h @@ -161,6 +161,9 @@ public: operator ID3D11Texture2DPtr() const; operator ID3D11Texture3DPtr() const; + ID3D11Texture1DPtr Tex1D() const { return (ID3D11Texture1DPtr) * this; }; + ID3D11Texture2DPtr Tex2D() const { return (ID3D11Texture2DPtr) * this; }; + ID3D11Texture3DPtr Tex3D() const { return (ID3D11Texture3DPtr) * this; }; protected: D3D11GraphicsTest *m_Test; @@ -271,7 +274,7 @@ private: void SetupDescriptors(); D3D11GraphicsTest *m_Test; - ID3D11Resource *m_Res; + ID3D11ResourcePtr m_Res; ViewType m_ViewType; ResourceType m_ResType; diff --git a/util/test/demos/d3d11/d3d11_pixel_history_zoo.cpp b/util/test/demos/d3d11/d3d11_pixel_history_zoo.cpp new file mode 100644 index 000000000..770e805ed --- /dev/null +++ b/util/test/demos/d3d11/d3d11_pixel_history_zoo.cpp @@ -0,0 +1,736 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2020 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 "d3d11_test.h" + +const std::string dxgiFormatName[] = { + "DXGI_FORMAT_UNKNOWN", + "DXGI_FORMAT_R32G32B32A32_TYPELESS", + "DXGI_FORMAT_R32G32B32A32_FLOAT", + "DXGI_FORMAT_R32G32B32A32_UINT", + "DXGI_FORMAT_R32G32B32A32_SINT", + "DXGI_FORMAT_R32G32B32_TYPELESS", + "DXGI_FORMAT_R32G32B32_FLOAT", + "DXGI_FORMAT_R32G32B32_UINT", + "DXGI_FORMAT_R32G32B32_SINT", + "DXGI_FORMAT_R16G16B16A16_TYPELESS", + "DXGI_FORMAT_R16G16B16A16_FLOAT", + "DXGI_FORMAT_R16G16B16A16_UNORM", + "DXGI_FORMAT_R16G16B16A16_UINT", + "DXGI_FORMAT_R16G16B16A16_SNORM", + "DXGI_FORMAT_R16G16B16A16_SINT", + "DXGI_FORMAT_R32G32_TYPELESS", + "DXGI_FORMAT_R32G32_FLOAT", + "DXGI_FORMAT_R32G32_UINT", + "DXGI_FORMAT_R32G32_SINT", + "DXGI_FORMAT_R32G8X24_TYPELESS", + "DXGI_FORMAT_D32_FLOAT_S8X24_UINT", + "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS", + "DXGI_FORMAT_X32_TYPELESS_G8X24_UINT", + "DXGI_FORMAT_R10G10B10A2_TYPELESS", + "DXGI_FORMAT_R10G10B10A2_UNORM", + "DXGI_FORMAT_R10G10B10A2_UINT", + "DXGI_FORMAT_R11G11B10_FLOAT", + "DXGI_FORMAT_R8G8B8A8_TYPELESS", + "DXGI_FORMAT_R8G8B8A8_UNORM", + "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", + "DXGI_FORMAT_R8G8B8A8_UINT", + "DXGI_FORMAT_R8G8B8A8_SNORM", + "DXGI_FORMAT_R8G8B8A8_SINT", + "DXGI_FORMAT_R16G16_TYPELESS", + "DXGI_FORMAT_R16G16_FLOAT", + "DXGI_FORMAT_R16G16_UNORM", + "DXGI_FORMAT_R16G16_UINT", + "DXGI_FORMAT_R16G16_SNORM", + "DXGI_FORMAT_R16G16_SINT", + "DXGI_FORMAT_R32_TYPELESS", + "DXGI_FORMAT_D32_FLOAT", + "DXGI_FORMAT_R32_FLOAT", + "DXGI_FORMAT_R32_UINT", + "DXGI_FORMAT_R32_SINT", + "DXGI_FORMAT_R24G8_TYPELESS", + "DXGI_FORMAT_D24_UNORM_S8_UINT", + "DXGI_FORMAT_R24_UNORM_X8_TYPELESS", + "DXGI_FORMAT_X24_TYPELESS_G8_UINT", + "DXGI_FORMAT_R8G8_TYPELESS", + "DXGI_FORMAT_R8G8_UNORM", + "DXGI_FORMAT_R8G8_UINT", + "DXGI_FORMAT_R8G8_SNORM", + "DXGI_FORMAT_R8G8_SINT", + "DXGI_FORMAT_R16_TYPELESS", + "DXGI_FORMAT_R16_FLOAT", + "DXGI_FORMAT_D16_UNORM", + "DXGI_FORMAT_R16_UNORM", + "DXGI_FORMAT_R16_UINT", + "DXGI_FORMAT_R16_SNORM", + "DXGI_FORMAT_R16_SINT", + "DXGI_FORMAT_R8_TYPELESS", + "DXGI_FORMAT_R8_UNORM", + "DXGI_FORMAT_R8_UINT", + "DXGI_FORMAT_R8_SNORM", + "DXGI_FORMAT_R8_SINT", + "DXGI_FORMAT_A8_UNORM", + "DXGI_FORMAT_R1_UNORM", + "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", + "DXGI_FORMAT_R8G8_B8G8_UNORM", + "DXGI_FORMAT_G8R8_G8B8_UNORM", + "DXGI_FORMAT_BC1_TYPELESS", + "DXGI_FORMAT_BC1_UNORM", + "DXGI_FORMAT_BC1_UNORM_SRGB", + "DXGI_FORMAT_BC2_TYPELESS", + "DXGI_FORMAT_BC2_UNORM", + "DXGI_FORMAT_BC2_UNORM_SRGB", + "DXGI_FORMAT_BC3_TYPELESS", + "DXGI_FORMAT_BC3_UNORM", + "DXGI_FORMAT_BC3_UNORM_SRGB", + "DXGI_FORMAT_BC4_TYPELESS", + "DXGI_FORMAT_BC4_UNORM", + "DXGI_FORMAT_BC4_SNORM", + "DXGI_FORMAT_BC5_TYPELESS", + "DXGI_FORMAT_BC5_UNORM", + "DXGI_FORMAT_BC5_SNORM", + "DXGI_FORMAT_B5G6R5_UNORM", + "DXGI_FORMAT_B5G5R5A1_UNORM", + "DXGI_FORMAT_B8G8R8A8_UNORM", + "DXGI_FORMAT_B8G8R8X8_UNORM", + "DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM", + "DXGI_FORMAT_B8G8R8A8_TYPELESS", + "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB", + "DXGI_FORMAT_B8G8R8X8_TYPELESS", + "DXGI_FORMAT_B8G8R8X8_UNORM_SRGB", + "DXGI_FORMAT_BC6H_TYPELESS", + "DXGI_FORMAT_BC6H_UF16", + "DXGI_FORMAT_BC6H_SF16", + "DXGI_FORMAT_BC7_TYPELESS", + "DXGI_FORMAT_BC7_UNORM", + "DXGI_FORMAT_BC7_UNORM_SRGB", + "DXGI_FORMAT_AYUV", + "DXGI_FORMAT_Y410", + "DXGI_FORMAT_Y416", + "DXGI_FORMAT_NV12", + "DXGI_FORMAT_P010", + "DXGI_FORMAT_P016", + "DXGI_FORMAT_420_OPAQUE", + "DXGI_FORMAT_YUY2", + "DXGI_FORMAT_Y210", + "DXGI_FORMAT_Y216", + "DXGI_FORMAT_NV11", + "DXGI_FORMAT_AI44", + "DXGI_FORMAT_IA44", + "DXGI_FORMAT_P8", + "DXGI_FORMAT_A8P8", + "DXGI_FORMAT_B4G4R4A4_UNORM", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "DXGI_FORMAT_P208", + "DXGI_FORMAT_V208", + "DXGI_FORMAT_V408", +}; + +RD_TEST(D3D11_Pixel_History_Zoo, D3D11GraphicsTest) +{ + static constexpr const char *Description = + "Checks pixel history on different formats, scenarios, overdraw, etc."; + + bool IsUIntFormat(DXGI_FORMAT f) + { + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R8_UINT: return true; + default: break; + } + + return false; + } + + bool IsSIntFormat(DXGI_FORMAT f) + { + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_SINT: + case DXGI_FORMAT_R32G32B32_SINT: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_R8_SINT: return true; + default: break; + } + + return false; + } + + DXGI_FORMAT GetTypelessFormat(DXGI_FORMAT f) + { + switch(f) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: return DXGI_FORMAT_R32G32B32A32_TYPELESS; + + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: return DXGI_FORMAT_R32G32B32_TYPELESS; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: return DXGI_FORMAT_R16G16B16A16_TYPELESS; + + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: return DXGI_FORMAT_R32G32_TYPELESS; + + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: return DXGI_FORMAT_R32G8X24_TYPELESS; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: // maybe not valid cast? + return DXGI_FORMAT_R10G10B10A2_TYPELESS; + + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: return DXGI_FORMAT_R8G8B8A8_TYPELESS; + + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: return DXGI_FORMAT_R16G16_TYPELESS; + + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: // maybe not valid cast? + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + return DXGI_FORMAT_R32_TYPELESS; + + // maybe not valid casts? + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: return DXGI_FORMAT_R24G8_TYPELESS; + + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8_B8G8_UNORM: // maybe not valid cast? + case DXGI_FORMAT_G8R8_G8B8_UNORM: // maybe not valid cast? + return DXGI_FORMAT_B8G8R8A8_TYPELESS; + + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8X8_TYPELESS; + + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: return DXGI_FORMAT_R8G8_TYPELESS; + + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: return DXGI_FORMAT_R16_TYPELESS; + + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: return DXGI_FORMAT_R8_TYPELESS; + + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: return DXGI_FORMAT_BC1_TYPELESS; + + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: return DXGI_FORMAT_BC4_TYPELESS; + + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: return DXGI_FORMAT_BC2_TYPELESS; + + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: return DXGI_FORMAT_BC3_TYPELESS; + + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: return DXGI_FORMAT_BC5_TYPELESS; + + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: return DXGI_FORMAT_BC6H_TYPELESS; + + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: return DXGI_FORMAT_BC7_TYPELESS; + + case DXGI_FORMAT_R1_UNORM: + case DXGI_FORMAT_A8_UNORM: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_YUY2: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + case DXGI_FORMAT_NV11: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + case DXGI_FORMAT_P208: + case DXGI_FORMAT_V208: + case DXGI_FORMAT_V408: + case DXGI_FORMAT_B4G4R4A4_UNORM: return f; + + case DXGI_FORMAT_UNKNOWN: return DXGI_FORMAT_UNKNOWN; + + default: return DXGI_FORMAT_UNKNOWN; + } + } + + std::string vertex = R"EOSHADER( + +struct vertin +{ + float3 pos : POSITION; + float4 col : COLOR0; + float2 uv : TEXCOORD0; +}; + +struct v2f +{ + float4 pos : SV_POSITION; + float4 col : COLOR0; + float2 uv : TEXCOORD0; +}; + +v2f main(vertin IN, uint vid : SV_VertexID) +{ + v2f OUT = (v2f)0; + + OUT.pos = float4(IN.pos.xy, 0.5f, 1.0f); + OUT.col = IN.col; + OUT.uv = IN.uv; + + return OUT; +} + +)EOSHADER"; + + std::string pixel = R"EOSHADER( + +cbuffer refcounter : register(b0) +{ + uint expected; +}; + +cbuffer uavcounter : register(b1) +{ + uint actual; +}; + +float4 main() : SV_Target0 +{ + if(expected != actual) + return float4(1.0f, 0.0f, 0.0f, 1.0f); + return float4(0.0f, 1.0f, 0.1234f, 0.5f); +} + +)EOSHADER"; + + std::string pixelUInt = R"EOSHADER( + +cbuffer refcounter : register(b0) +{ + uint expected; +}; + +cbuffer uavcounter : register(b1) +{ + uint actual; +}; + +uint4 main() : SV_Target0 +{ + if(expected != actual) + return uint4(1, 0, 0, 1); + return uint4(0, 1, 1234, 5); +} + +)EOSHADER"; + + std::string pixelSInt = R"EOSHADER( + +cbuffer refcounter : register(b0) +{ + uint expected; +}; + +cbuffer uavcounter : register(b1) +{ + uint actual; +}; + +int4 main() : SV_Target0 +{ + if(expected != actual) + return int4(1, 0, 0, 1); + return int4(0, 1, -1234, 5); +} + +)EOSHADER"; + + std::string compute = R"EOSHADER( + +RWBuffer buf : register(u0); + +[numthreads(1,1,1)] +void main() +{ + InterlockedAdd(buf[0], 1); +} + +)EOSHADER"; + + int main() + { + // initialise, create window, create device, etc + if(!Init()) + return 3; + + ID3DBlobPtr vsblob = Compile(vertex, "main", "vs_4_0"); + + CreateDefaultInputLayout(vsblob); + + ID3D11VertexShaderPtr vs = CreateVS(vsblob); + ID3D11PixelShaderPtr ps = CreatePS(Compile(pixel, "main", "ps_4_0")); + ID3D11PixelShaderPtr psUInt = CreatePS(Compile(pixelUInt, "main", "ps_4_0")); + ID3D11PixelShaderPtr psSInt = CreatePS(Compile(pixelSInt, "main", "ps_4_0")); + + ID3D11ComputeShaderPtr cs = CreateCS(Compile(compute, "main", "cs_5_0")); + + ID3D11BufferPtr vb = MakeBuffer().Vertex().Data(DefaultTri); + + const DXGI_FORMAT depthFormats[] = { + DXGI_FORMAT_D32_FLOAT, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_R32G8X24_TYPELESS, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + }; + + const DXGI_FORMAT dsvFormats[] = { + DXGI_FORMAT_D32_FLOAT, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + }; + + static_assert(sizeof(depthFormats) == sizeof(dsvFormats), + "depth arrays should be identical sizes."); + + ID3D11BufferPtr bufRef = MakeBuffer().Size(256).Constant(); + ID3D11BufferPtr bufCounter = MakeBuffer().Size(256).UAV(); + ID3D11BufferPtr bufCounterCB = MakeBuffer().Size(256).Constant(); + ID3D11UnorderedAccessViewPtr bufCounterUAV = MakeUAV(bufCounter).Format(DXGI_FORMAT_R32_UINT); + + ctx->CSSetUnorderedAccessViews(0, 1, &bufCounterUAV.GetInterfacePtr(), NULL); + ctx->CSSetShader(cs, NULL, 0); + + std::vector dsvs; + std::vector rts; + + for(size_t i = 0; i < ARRAY_COUNT(dsvFormats); i++) + { + // normal + dsvs.push_back( + MakeDSV(MakeTexture(depthFormats[i], 16, 16).DSV().Tex2D()).Format(dsvFormats[i])); + + // submip and subslice selected + dsvs.push_back(MakeDSV(MakeTexture(depthFormats[i], 32, 32).Array(32).DSV().Mips(2).Tex2D()) + .Format(dsvFormats[i]) + .FirstMip(1) + .NumMips(1) + .FirstSlice(4) + .NumSlices(1)); + } + + const DXGI_FORMAT colorFormats[] = { + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R32G32B32_UINT, + DXGI_FORMAT_R32G32B32_SINT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_R32G32_UINT, + DXGI_FORMAT_R32G32_SINT, + DXGI_FORMAT_R10G10B10A2_UNORM, + DXGI_FORMAT_R10G10B10A2_UINT, + DXGI_FORMAT_R11G11B10_FLOAT, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_SNORM, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_R16G16_FLOAT, + DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_R16G16_UINT, + DXGI_FORMAT_R16G16_SNORM, + DXGI_FORMAT_R16G16_SINT, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_R32_UINT, + DXGI_FORMAT_R32_SINT, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8_UINT, + DXGI_FORMAT_R8G8_SNORM, + DXGI_FORMAT_R8G8_SINT, + DXGI_FORMAT_R16_FLOAT, + DXGI_FORMAT_R16_UNORM, + DXGI_FORMAT_R16_UINT, + DXGI_FORMAT_R16_SNORM, + DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8_UINT, + DXGI_FORMAT_R8_SNORM, + DXGI_FORMAT_R8_SINT, + DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_R1_UNORM, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G5R5A1_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8X8_UNORM, + DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, + DXGI_FORMAT_B4G4R4A4_UNORM, + }; + + for(size_t i = 0; i < ARRAY_COUNT(colorFormats); i++) + { + DXGI_FORMAT f = colorFormats[i]; + + UINT supp = 0; + dev->CheckFormatSupport(f, &supp); + + if((supp & D3D11_FORMAT_SUPPORT_RENDER_TARGET) == 0) + continue; + + std::vector fmts = {f}; + + // test typeless->casted for the first three (RGBA32) + if(i < 3) + fmts.push_back(GetTypelessFormat(f)); + + for(DXGI_FORMAT tex_fmt : fmts) + { + // make a normal one + rts.push_back(MakeRTV(MakeTexture(tex_fmt, 16, 16).RTV().Tex2D()).Format(f)); + + // make a subslice and submip one + rts.push_back(MakeRTV(MakeTexture(tex_fmt, 32, 32).Array(32).Mips(2).RTV().Tex2D()) + .Format(f) + .FirstMip(1) + .NumMips(1) + .FirstSlice(4) + .NumSlices(1)); + } + } + + // make a simple dummy texture for MRT testing + ID3D11RenderTargetViewPtr mrt = + MakeRTV(MakeTexture(DXGI_FORMAT_R8G8B8A8_UNORM, 16, 16).RTV().Tex2D()); + + while(Running()) + { + ClearRenderTargetView(bbRTV, {0.2f, 0.2f, 0.2f, 1.0f}); + + IASetVertexBuffer(vb, sizeof(DefaultA2V), 0); + ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->IASetInputLayout(defaultLayout); + + ctx->VSSetShader(vs, NULL, 0); + ctx->PSSetShader(ps, NULL, 0); + + RSSetViewport({0.0f, 0.0f, 16.0f, 16.0f, 0.0f, 1.0f}); + + UINT zero[4] = {}; + ctx->ClearUnorderedAccessViewUint(bufCounterUAV, zero); + + uint32_t testCounter = 0; + + // for each DSV and for none + for(size_t dsvIdx = 0; dsvIdx <= dsvs.size(); dsvIdx++) + { + ID3D11DepthStencilViewPtr dsv = dsvIdx < dsvs.size() ? dsvs[dsvIdx] : NULL; + + DXGI_FORMAT df = DXGI_FORMAT_UNKNOWN; + if(dsv) + { + D3D11_DEPTH_STENCIL_VIEW_DESC desc; + dsv->GetDesc(&desc); + df = desc.Format; + } + + // for each RT + for(size_t rtIdx = 0; rtIdx < rts.size(); rtIdx++) + { + ID3D11RenderTargetViewPtr rt = rts[rtIdx]; + + ID3D11RenderTargetViewPtr dummy = mrt; + DXGI_FORMAT f = DXGI_FORMAT_UNKNOWN; + { + D3D11_RENDER_TARGET_VIEW_DESC desc; + rt->GetDesc(&desc); + f = desc.Format; + } + + // for all but the first DSV and the last (none) DSV, skip the bulk of the colour tests to + // reduce the test matrix. + if(dsvIdx > 0 && dsvIdx < dsvs.size()) + { + if(rtIdx > 10) + break; + } + + pushMarker("Test RTV: " + dxgiFormatName[f] + " & depth: " + + (df == DXGI_FORMAT_UNKNOWN ? "None" : dxgiFormatName[df])); + + ctx->OMSetRenderTargets(1, &rt.GetInterfacePtr(), dsv); + + // dispatch the CS to increment the buffer counter on the GPU + ctx->Dispatch(1, 1, 1); + // increment the CPU counter + testCounter++; + + // update CBs so we can check for validity + uint32_t data[256 / 4]; + data[0] = testCounter; + ctx->UpdateSubresource(bufRef, 0, NULL, data, 256, 256); + ctx->CopyResource(bufCounterCB, bufCounter); + + ctx->PSSetConstantBuffers(0, 1, &bufRef.GetInterfacePtr()); + ctx->PSSetConstantBuffers(1, 1, &bufCounterCB.GetInterfacePtr()); + + setMarker("Test " + std::to_string(testCounter)); + + if(IsUIntFormat(f)) + { + setMarker("UInt tex"); + ctx->PSSetShader(psUInt, NULL, 0); + } + else if(IsSIntFormat(f)) + { + setMarker("SInt tex"); + ctx->PSSetShader(psSInt, NULL, 0); + } + else + { + setMarker("Float tex"); + ctx->PSSetShader(ps, NULL, 0); + } + + if(dsv) + { + setMarker("DSVClear"); + ctx->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + } + + setMarker("RTVClear"); + ClearRenderTargetView(rt, Vec4f(1.0f, 0.0f, 1.0f, 1.0f)); + + setMarker("BasicDraw"); + ctx->Draw(3, 0); + + popMarker(); + } + } + + Present(); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index 1f2e3e56d..49ca0fe09 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -140,6 +140,7 @@ + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index 9104c9505..cfab4031b 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -454,6 +454,9 @@ D3D12\demos + + D3D11\demos + diff --git a/util/test/rdtest/testcase.py b/util/test/rdtest/testcase.py index 49d89d6a4..4333e929f 100644 --- a/util/test/rdtest/testcase.py +++ b/util/test/rdtest/testcase.py @@ -214,7 +214,7 @@ class TestCase: draw: rd.DrawcallDescription for draw in draw_list: # If this draw matches, return it - if draw.eventId >= start_event and name in draw.name: + if draw.eventId >= start_event and (name == '' or name in draw.name): return draw # Recurse to children - depth-first search @@ -240,6 +240,16 @@ class TestCase: return self._find_draw(name, start_event, self.controller.GetDrawcalls()) + def get_draw(self, event: int = 0): + """ + Finds the drawcall for the given event + + :param event: The eventId to search for. + :return: + """ + + return self._find_draw('', event, self.controller.GetDrawcalls()) + def get_vsin(self, draw: rd.DrawcallDescription, first_index: int=0, num_indices: int=0, instance: int=0, view: int=0): ib: rd.BoundVBuffer = self.controller.GetPipelineState().GetIBuffer() @@ -299,26 +309,36 @@ class TestCase: log.success("Mesh data is identical to reference") - def check_pixel_value(self, tex: rd.ResourceId, x, y, value, eps=util.FLT_EPSILON): + def check_pixel_value(self, tex: rd.ResourceId, x, y, value, sub=None, cast=None, eps=util.FLT_EPSILON): tex_details = self.get_texture(tex) res_details = self.get_resource(tex) + if sub is None: + sub = rd.Subresource(0,0,0) + if cast is None: + cast = rd.CompType.Typeless + if type(x) is float: x = int((tex_details.width-1) * x) if type(y) is float: y = int((tex_details.height-1) * y) - cast = rd.CompType.Typeless - if tex_details.creationFlags & rd.TextureCategory.SwapBuffer: + if cast == rd.CompType.Typeless and tex_details.creationFlags & rd.TextureCategory.SwapBuffer: cast = rd.CompType.UNormSRGB # Reduce epsilon for RGBA8 textures if it's not already reduced if tex_details.format.compByteWidth == 1 and eps == util.FLT_EPSILON: eps = (1.0 / 255.0) - picked: rd.PixelValue = self.controller.PickPixel(tex, x, y, rd.Subresource(0, 0, 0), cast) + picked: rd.PixelValue = self.controller.PickPixel(tex, x, y, sub, cast) - if not util.value_compare(picked.floatValue, value, eps): + picked_value = picked.floatValue + if cast == rd.CompType.UInt: + picked_value = picked.uintValue + elif cast == rd.CompType.SInt: + picked_value = picked.intValue + + if not util.value_compare(picked_value, value, eps): save_data = rd.TextureSave() save_data.resourceId = tex save_data.destType = rd.FileType.PNG @@ -328,45 +348,11 @@ class TestCase: self.controller.SaveTexture(save_data, img_path) raise TestFailureException( - "Picked value {} at {},{} doesn't match expectation of {}".format(picked.floatValue, x, y, value), + "Picked value {} at {},{} doesn't match expectation of {}".format(picked_value, x, y, value), img_path) log.success("Picked value at {},{} in {} is as expected".format(x, y, res_details.name)) - def check_pixel_sample_value(self, tex: rd.ResourceId, x, y, sample, value, eps=util.FLT_EPSILON): - tex_details = self.get_texture(tex) - res_details = self.get_resource(tex) - - if type(x) is float: - x = int((tex_details.width-1) * x) - if type(y) is float: - y = int((tex_details.height-1) * y) - - cast = rd.CompType.Typeless - if tex_details.creationFlags & rd.TextureCategory.SwapBuffer: - cast = rd.CompType.UNormSRGB - - # Reduce epsilon for RGBA8 textures if it's not already reduced - if tex_details.format.compByteWidth == 1 and eps == util.FLT_EPSILON: - eps = (1.0 / 255.0) - - picked: rd.PixelValue = self.controller.PickPixel(tex, x, y, rd.Subresource(0, 0, sample), cast) - - if not util.value_compare(picked.floatValue, value, eps): - save_data = rd.TextureSave() - save_data.resourceId = tex - save_data.destType = rd.FileType.PNG - - img_path = util.get_tmp_path('output.png') - - self.controller.SaveTexture(save_data, img_path) - - raise TestFailureException( - "Picked value {} at {},{} sample {} doesn't match expectation of {}". - format(picked.floatValue, x, y, sample, value), img_path) - - log.success("Picked value at {},{} sample {} in {} is as expected".format(x, y, sample, res_details.name)) - def check_triangle(self, out = None, back = None, fore = None, vp = None): pipe: rd.PipeState = self.controller.GetPipelineState() diff --git a/util/test/tests/D3D11/D3D11_Pixel_History_Zoo.py b/util/test/tests/D3D11/D3D11_Pixel_History_Zoo.py new file mode 100644 index 000000000..268a5789d --- /dev/null +++ b/util/test/tests/D3D11/D3D11_Pixel_History_Zoo.py @@ -0,0 +1,74 @@ +import renderdoc as rd +import rdtest +from typing import List + + +class D3D11_Pixel_History_Zoo(rdtest.TestCase): + slow_test = True + demos_test_name = 'D3D11_Pixel_History_Zoo' + + def check_capture(self): + draws = self.controller.GetDrawcalls() + + for d in self.controller.GetDrawcalls(): + # Only process test draws + if not d.name.startswith('Test'): + continue + + # Go to the last child draw + self.controller.SetFrameEvent(d.children[-1].eventId, True) + + if any(['UInt tex' in d.name for d in d.children]): + value_selector = lambda x: x.uintValue + shader_out = (0, 1, 1234, 5) + elif any(['SInt tex' in d.name for d in d.children]): + value_selector = lambda x: x.intValue + shader_out = (0, 1, -1234, 5) + else: + value_selector = lambda x: x.floatValue + shader_out = (0.0, 1.0, 0.1234, 0.5) + + pipe: rd.PipeState = self.controller.GetPipelineState() + + rt: rd.BoundResource = pipe.GetOutputTargets()[0] + + vp: rd.Viewport = pipe.GetViewport(0) + + tex = rt.resourceId + x, y = (int(vp.width / 2), int(vp.height / 2)) + + tex_details = self.get_texture(tex) + + sub = rd.Subresource() + if tex_details.arraysize > 1: + sub.slice = rt.firstSlice + if tex_details.mips > 1: + sub.mip = rt.firstMip + + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + + # Should be at least two modifications in every test - clear and draw + self.check(len(modifs) >= 2) + + # Check that the modifications are self consistent - postmod of each should match premod of the next + for i in range(len(modifs) - 1): + if value_selector(modifs[i].postMod.col) != value_selector(modifs[i + 1].preMod.col): + raise rdtest.TestFailureException( + "postmod at {}: {} doesn't match premod at {}: {}".format(modifs[i].eventId, + value_selector(modifs[i].postMod.col), + modifs[i + 1].eventId, + value_selector(modifs[i].preMod.col))) + + if self.get_draw(modifs[i].eventId).flags & rd.DrawFlags.Drawcall: + if not rdtest.value_compare(value_selector(modifs[i].shaderOut.col), shader_out): + raise rdtest.TestFailureException( + "Shader output {} isn't as expected {}".format(value_selector(modifs[i].shaderOut.col), + shader_out)) + + rdtest.log.success("shader output and premod/postmod is consistent") + + # The current pixel value should match the last postMod + self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) + + # Also the red channel should be zero, as it indicates errors + self.check(float(value_selector(modifs[-1].postMod.col)[0]) == 0.0) diff --git a/util/test/tests/D3D11/D3D11_Shader_Debug_Zoo.py b/util/test/tests/D3D11/D3D11_Shader_Debug_Zoo.py index c60f2a377..bac89d88d 100644 --- a/util/test/tests/D3D11/D3D11_Shader_Debug_Zoo.py +++ b/util/test/tests/D3D11/D3D11_Shader_Debug_Zoo.py @@ -63,11 +63,11 @@ class D3D11_Shader_Debug_Zoo(rdtest.TestCase): output = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0) - debugged = self.evalute_source_var(output, variables) + debugged = self.evaluate_source_var(output, variables) # Validate the debug output result try: - self.check_pixel_sample_value(pipe.GetOutputTargets()[0].resourceId, 4, 4, test, debugged.value.fv[0:4], 0.0) + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 4, 4, debugged.value.fv[0:4], 0.0, sub=rd.Subresource(0, 0, test)) except rdtest.TestFailureException as ex: failed = True rdtest.log.error("Test {} did not match. {}".format(test, str(ex))) diff --git a/util/test/tests/D3D12/D3D12_Shader_Debug_Zoo.py b/util/test/tests/D3D12/D3D12_Shader_Debug_Zoo.py index 349161812..d0e6d6103 100644 --- a/util/test/tests/D3D12/D3D12_Shader_Debug_Zoo.py +++ b/util/test/tests/D3D12/D3D12_Shader_Debug_Zoo.py @@ -72,11 +72,11 @@ class D3D12_Shader_Debug_Zoo(rdtest.TestCase): output = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0) - debugged = self.evalute_source_var(output, variables) + debugged = self.evaluate_source_var(output, variables) # Validate the debug output result try: - self.check_pixel_sample_value(pipe.GetOutputTargets()[0].resourceId, 4, 4, test, debugged.value.fv[0:4], 0.0) + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 4, 4, debugged.value.fv[0:4], 0.0, sub=rd.Subresource(0, 0, test)) except rdtest.TestFailureException as ex: failed = True rdtest.log.error("Test {} did not match. {}".format(test, str(ex)))