From fbab189b06025cfbee78f9f4d6ad117c965005b0 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 16 Oct 2025 14:08:32 +0100 Subject: [PATCH] Move D3D11 test to use common pixel history test framework --- util/test/demos/d3d11/d3d11_pixel_history.cpp | 671 +++++++++++++++ .../demos/d3d11/d3d11_pixel_history_zoo.cpp | 771 ------------------ util/test/demos/demos.vcxproj | 2 +- util/test/demos/demos.vcxproj.filters | 6 +- util/test/tests/D3D11/D3D11_Pixel_History.py | 5 + .../tests/D3D11/D3D11_Pixel_History_Zoo.py | 110 --- 6 files changed, 680 insertions(+), 885 deletions(-) create mode 100644 util/test/demos/d3d11/d3d11_pixel_history.cpp delete mode 100644 util/test/demos/d3d11/d3d11_pixel_history_zoo.cpp create mode 100644 util/test/tests/D3D11/D3D11_Pixel_History.py delete mode 100644 util/test/tests/D3D11/D3D11_Pixel_History_Zoo.py diff --git a/util/test/demos/d3d11/d3d11_pixel_history.cpp b/util/test/demos/d3d11/d3d11_pixel_history.cpp new file mode 100644 index 000000000..1ae0e1aef --- /dev/null +++ b/util/test/demos/d3d11/d3d11_pixel_history.cpp @@ -0,0 +1,671 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2025 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" + +RD_TEST(D3D11_Pixel_History, D3D11GraphicsTest) +{ + static constexpr const char *Description = "Tests pixel history"; + + const std::string vertex = R"EOSHADER( + +void main(float3 pos : POSITION, float4 col : COLOR0, + out float4 outPos : SV_POSITION, out COL_TYPE outCol : COLOR0) +{ + outPos = float4(pos, 1.0f); + outCol = ProcessColor(col); +} + +)EOSHADER"; + + const std::string pixel = R"EOSHADER( + +void main(float4 pos : SV_POSITION, COL_TYPE col : COLOR0 +#if COLOR == 1 + , out COL_TYPE outCol : SV_Target0 +#endif + ) +{ + if (pos.x < DISCARD_X+1 && pos.x > DISCARD_X) + discard; + if (col.x > 10000 && col.y > 10000 && col.z > 10000) + discard; +#if COLOR == 1 + outCol = col + COL_TYPE(0, 0, 0, ProcessColor((ALPHA_ADD).xxxx).x); +#endif +} + +)EOSHADER"; + + std::string mspixel = R"EOSHADER( + +void main(float4 pos : SV_POSITION, uint sampleId : SV_SampleIndex +#if COLOR == 1 + , out COL_TYPE outCol : SV_Target0 +#endif + ) +{ +#if COLOR == 1 + float4 col = 0.0f.xxxx; + if (sampleId == 0) + col = float4(1, 0, 0, 1+ALPHA_ADD); + else if (sampleId == 1) + col = float4(0, 0, 1, 1+ALPHA_ADD); + else if (sampleId == 2) + col = float4(0, 1, 1, 1+ALPHA_ADD); + else if (sampleId == 3) + col = float4(1, 1, 1, 1+ALPHA_ADD); + outCol = ProcessColor(col); +#endif +} + +)EOSHADER"; + + std::string comp = R"EOSHADER( + +IMAGE_TYPE Output : register(u0); + +[numthreads(1, 1, 1)] +void main() +{ + float4 data = float4(3, 3, 3, 9); + + for(int x=0; x < 10; x++) + for(int y=0; y < 10; y++) + Output[STORE_TYPE(STORE_X+x, STORE_Y+y STORE_Z)] = ProcessColor(data); +} + +)EOSHADER"; + + struct D3D11StateSetup + { + struct SetupInfo + { + ID3D11VertexShaderPtr VS; + ID3D11PixelShaderPtr PS; + D3D11_DEPTH_STENCIL_DESC DepthStencilState; + D3D11_RASTERIZER_DESC RasterizerState; + D3D11_BLEND_DESC BlendState; + }; + + ID3D11VertexShaderPtr VS; + ID3D11PixelShaderPtr PS; + ID3D11DepthStencilStatePtr DS; + ID3D11RasterizerStatePtr RS; + ID3D11BlendStatePtr BS; + UINT ref = 0x55; + UINT SampleMask = ~0U; + + void init(ID3D11DevicePtr device, const SetupInfo &info) + { + VS = info.VS; + PS = info.PS; + device->CreateDepthStencilState(&info.DepthStencilState, &DS); + device->CreateRasterizerState(&info.RasterizerState, &RS); + device->CreateBlendState(&info.BlendState, &BS); + } + + void set(ID3D11DeviceContextPtr context) const + { + context->VSSetShader(VS, NULL, 0); + context->PSSetShader(PS, NULL, 0); + context->RSSetState(RS); + context->OMSetDepthStencilState(DS, ref); + context->OMSetBlendState(BS, NULL, SampleMask); + } + }; + + struct D3D11TestBatch + { + std::string name; + + bool uint = false; + + uint32_t mip = 0; + + ID3D11Texture2DPtr colImg2D; + + ID3D11RenderTargetViewPtr RTV; + ID3D11DepthStencilViewPtr DSV; + + DXGI_FORMAT depthFormat; + + ID3D11UnorderedAccessViewPtr compUAV; + ID3D11ComputeShaderPtr comp; + + uint32_t width, height; + + D3D11StateSetup depthWriteState; + D3D11StateSetup scissorState; + D3D11StateSetup stencilRefState; + D3D11StateSetup stencilMaskState; + D3D11StateSetup depthEqualState; + D3D11StateSetup depthState; + D3D11StateSetup stencilWriteState; + D3D11StateSetup backgroundState; + D3D11StateSetup noPsState; + D3D11StateSetup basicState; + D3D11StateSetup colorMaskState; + D3D11StateSetup cullFrontState; + D3D11StateSetup sampleColourState; + }; + + std::vector batches; + + void BuildTestBatch(const std::string &name, uint32_t sampleCount, DXGI_FORMAT colourFormat, + DXGI_FORMAT depthStencilFormat, int targetMip = -1, int targetSlice = -1, + int targetDepthSlice = -1) + { + batches.push_back({}); + + D3D11TestBatch &batch = batches.back(); + batch.name = name; + + batch.width = screenWidth; + batch.height = screenHeight; + + uint32_t arraySize = targetSlice >= 0 ? 5 : 1; + uint32_t mips = targetMip >= 0 ? 4 : 1; + uint32_t depth = targetDepthSlice >= 0 ? 14 : 1; + + uint32_t mip = (uint32_t)std::max(0, targetMip); + uint32_t slice = (uint32_t)std::max(0, targetSlice); + if(depth > 1) + slice = (uint32_t)targetDepthSlice; + + batch.mip = mip; + + std::string defines; + defines += + "#define COLOR " + std::string(colourFormat == DXGI_FORMAT_UNKNOWN ? "0" : "1") + "\n"; + + if(colourFormat == DXGI_FORMAT_R8G8B8A8_UINT || colourFormat == DXGI_FORMAT_R16G16B16A16_UINT || + colourFormat == DXGI_FORMAT_R32G32B32A32_UINT) + { + batch.uint = true; + defines += R"( + +#define COL_TYPE uint4 +#define ALPHA_ADD 3 + +uint4 ProcessColor(float4 col) +{ + uint4 ret = uint4(16*col); + + if(col.x < 0.0f) ret.x = 0xfffffff0; + if(col.y < 0.0f) ret.y = 0xfffffff0; + if(col.z < 0.0f) ret.z = 0xfffffff0; + + + return ret; +} + +)"; + } + else + { + defines += R"( + +#define COL_TYPE float4 +#define ALPHA_ADD 1.75 + +float4 ProcessColor(float4 col) +{ + float4 ret = col; + + // this obviously won't overflow F32 but it will overflow anything 16-bit and under + if(col.x < 0.0f) ret.x = 100000.0f; + if(col.y < 0.0f) ret.y = 100000.0f; + if(col.z < 0.0f) ret.z = 100000.0f; + + return ret; +} + +)"; + } + + defines += "#define DISCARD_X " + std::to_string(150 >> mip) + "\n"; + defines += "#define IMAGE_TYPE " + + std::string(depth > 1 ? "RWTexture3D" + : arraySize > 1 ? "RWTexture2DArray" + : "RWTexture2D") + + "\n"; + defines += "#define STORE_X " + std::to_string(220 >> mip) + "\n"; + defines += "#define STORE_Y " + std::to_string(80 >> mip) + "\n"; + if(depth > 1 || arraySize > 1) + { + defines += "#define STORE_TYPE uint3\n"; + defines += "#define STORE_Z , " + std::to_string(slice) + "\n"; + } + else + { + defines += "#define STORE_TYPE uint2\n"; + defines += "#define STORE_Z \n"; + } + defines += "\n\n"; + + ID3DBlobPtr vsBlob = Compile(defines + vertex, "main", "vs_5_0"); + ID3DBlobPtr psBlob = Compile(defines + pixel, "main", "ps_5_0"); + ID3DBlobPtr psMsaaBlob = Compile(defines + mspixel, "main", "ps_5_0"); + + if(colourFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11TextureCreator colCreator = + MakeTexture(colourFormat, batch.width, batch.height, depth) + .Mips(mips) + // this is DepthOrArraySize so need to set it correctly from either + .Array(arraySize) + .Multisampled(sampleCount) + .SRV() + .RTV(); + + if(sampleCount == 1) + colCreator.UAV(); + + if(depth > 1) + { + ID3D11Texture3DPtr colImg = colCreator; + SetDebugName(colImg, batch.name + " colImg"); + + batch.RTV = MakeRTV(colImg).FirstMip(mip).NumMips(1).FirstSlice(slice).NumSlices(1); + + batch.comp = CreateCS(Compile(defines + comp, "main", "cs_5_0")); + SetDebugName(batch.comp, batch.name + " comp"); + batch.compUAV = MakeUAV(colImg).FirstMip(mip); + SetDebugName(batch.compUAV, batch.name + " compUAV"); + } + else + { + batch.colImg2D = colCreator; + SetDebugName(batch.colImg2D, batch.name + " colImg"); + + batch.RTV = MakeRTV(batch.colImg2D).FirstMip(mip).NumMips(1).FirstSlice(slice).NumSlices(1); + + if(sampleCount == 1) + { + batch.comp = CreateCS(Compile(defines + comp, "main", "cs_5_0")); + SetDebugName(batch.comp, batch.name + " comp"); + batch.compUAV = MakeUAV(batch.colImg2D).FirstMip(mip); + SetDebugName(batch.compUAV, batch.name + " compUAV"); + } + } + } + + batch.depthFormat = depthStencilFormat; + + if(depthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + // can't create 2D views of 3D with depth images, so we just use a normal 2D array image + if(depth > 1) + { + arraySize = depth; + depth = 1; + } + + ID3D11Texture2DPtr depthImg = + MakeTexture(depthStencilFormat, batch.width, batch.height, depth) + .Mips(mips) + // this is DepthOrArraySize so need to set it correctly from either + .Array(arraySize) + .Multisampled(sampleCount) + .DSV(); + SetDebugName(depthImg, batch.name + " depthImg"); + + batch.DSV = MakeDSV(depthImg).FirstMip(mip).NumMips(1).FirstSlice(slice).NumSlices(1); + } + + batch.width >>= mip; + batch.height >>= mip; + + D3D11StateSetup::SetupInfo stateInfo = {}; + + ID3D11VertexShaderPtr VS = CreateVS(vsBlob); + SetDebugName(VS, batch.name + " NormalVS"); + stateInfo.VS = VS; + + ID3D11PixelShaderPtr PS = CreatePS(psBlob); + SetDebugName(PS, batch.name + " NormalPS"); + stateInfo.PS = PS; + + stateInfo.BlendState.RenderTarget[0].RenderTargetWriteMask = 0xf; + + stateInfo.RasterizerState.FillMode = D3D11_FILL_SOLID; + stateInfo.RasterizerState.MultisampleEnable = sampleCount > 1; + stateInfo.RasterizerState.ScissorEnable = TRUE; + stateInfo.RasterizerState.DepthClipEnable = TRUE; + stateInfo.RasterizerState.CullMode = D3D11_CULL_BACK; + + stateInfo.DepthStencilState.DepthEnable = TRUE; + stateInfo.DepthStencilState.DepthFunc = D3D11_COMPARISON_ALWAYS; + stateInfo.DepthStencilState.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + stateInfo.DepthStencilState.StencilEnable = FALSE; + stateInfo.DepthStencilState.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + stateInfo.DepthStencilState.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + stateInfo.DepthStencilState.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + stateInfo.DepthStencilState.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + stateInfo.DepthStencilState.StencilReadMask = 0xff; + stateInfo.DepthStencilState.StencilWriteMask = 0xff; + stateInfo.DepthStencilState.BackFace = stateInfo.DepthStencilState.FrontFace; + + stateInfo.DepthStencilState.DepthFunc = D3D11_COMPARISON_ALWAYS; + batch.depthWriteState.init(dev, stateInfo); + + { + D3D11StateSetup::SetupInfo depthEqualStateInfo = stateInfo; + depthEqualStateInfo.DepthStencilState.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + depthEqualStateInfo.DepthStencilState.DepthFunc = D3D11_COMPARISON_EQUAL; + + batch.depthEqualState.init(dev, depthEqualStateInfo); + } + + { + D3D11StateSetup::SetupInfo scissorStencilStates = stateInfo; + scissorStencilStates.DepthStencilState.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + scissorStencilStates.DepthStencilState.DepthEnable = FALSE; + + batch.scissorState.init(dev, scissorStencilStates); + + batch.stencilRefState.init(dev, scissorStencilStates); + batch.stencilRefState.ref = 0x67; + + scissorStencilStates.DepthStencilState.StencilReadMask = 0; + scissorStencilStates.DepthStencilState.StencilWriteMask = 0; + + batch.stencilMaskState.init(dev, scissorStencilStates); + } + + stateInfo.DepthStencilState.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + + batch.depthState.init(dev, stateInfo); + + stateInfo.DepthStencilState.StencilEnable = TRUE; + batch.stencilWriteState.init(dev, stateInfo); + + stateInfo.DepthStencilState.StencilEnable = FALSE; + batch.backgroundState.init(dev, stateInfo); + + { + stateInfo.PS = NULL; + stateInfo.DepthStencilState.StencilEnable = TRUE; + batch.noPsState.init(dev, stateInfo); + batch.noPsState.ref = 0x33; + stateInfo.PS = PS; + } + + stateInfo.DepthStencilState.StencilEnable = TRUE; + stateInfo.DepthStencilState.FrontFace.StencilFunc = D3D11_COMPARISON_GREATER; + batch.basicState.init(dev, stateInfo); + stateInfo.DepthStencilState.StencilEnable = FALSE; + + { + D3D11StateSetup::SetupInfo maskStateInfo = stateInfo; + maskStateInfo.BlendState.RenderTarget[0].RenderTargetWriteMask = 0x3; + batch.colorMaskState.init(dev, maskStateInfo); + } + + stateInfo.RasterizerState.CullMode = D3D11_CULL_FRONT; + batch.cullFrontState.init(dev, stateInfo); + stateInfo.RasterizerState.CullMode = D3D11_CULL_BACK; + + stateInfo.PS = CreatePS(psMsaaBlob); + SetDebugName(stateInfo.PS, batch.name + " MSAAPS"); + + stateInfo.DepthStencilState.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + batch.sampleColourState.init(dev, stateInfo); + if(sampleCount == 4) + batch.sampleColourState.SampleMask = 0x7; + } + + void RunDraw(const PixelHistory::draw &draw, uint32_t numInstances = 1) + { + ctx->DrawInstanced(draw.count, numInstances, draw.first, 0); + } + + void RunBatch(const D3D11TestBatch &b) + { + float factor = float(b.width) / float(screenWidth); + + D3D11_VIEWPORT v = {}; + v.Width = (float)b.width - (20.0f * factor); + v.Height = (float)b.height - (20.0f * factor); + v.TopLeftX = floorf(10.0f * factor); + v.TopLeftY = floorf(10.0f * factor); + v.MaxDepth = 1.0f; + + D3D11_RECT scissor = {0, 0, (LONG)b.width, (LONG)b.height}; + D3D11_RECT scissorPass = {95 >> b.mip, 245 >> b.mip, 115U >> b.mip, 253U >> b.mip}; + D3D11_RECT scissorFail = {95 >> b.mip, 245 >> b.mip, 103U >> b.mip, 253U >> b.mip}; + + ctx->RSSetViewports(1, &v); + ctx->RSSetScissorRects(1, &scissor); + + ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->IASetInputLayout(defaultLayout); + + // draw the setup triangles + + pushMarker("Setup"); + { + setMarker("Depth Write"); + b.depthWriteState.set(ctx); + RunDraw(PixelHistory::DepthWrite); + + setMarker("Depth Equal Setup"); + RunDraw(PixelHistory::DepthEqualSetup); + + setMarker("Unbound Fragment Shader"); + b.noPsState.set(ctx); + RunDraw(PixelHistory::UnboundPS); + + setMarker("Stencil Write"); + b.stencilWriteState.set(ctx); + RunDraw(PixelHistory::StencilWrite); + + setMarker("Background"); + b.backgroundState.set(ctx); + RunDraw(PixelHistory::Background); + + setMarker("Cull Front"); + b.cullFrontState.set(ctx); + RunDraw(PixelHistory::CullFront); + + // depth bounds would be here but D3D11 does not support it + } + popMarker(); + + pushMarker("Stress Test"); + { + pushMarker("Lots of Drawcalls"); + { + setMarker("300 Draws"); + b.depthWriteState.set(ctx); + for(int d = 0; d < 300; ++d) + RunDraw(PixelHistory::Draws300); + } + popMarker(); + + setMarker("300 Instances"); + RunDraw(PixelHistory::Instances300, 300); + } + popMarker(); + + setMarker("Simple Test"); + b.basicState.set(ctx); + RunDraw(PixelHistory::MainTest); + + b.scissorState.set(ctx); + + setMarker("Scissor Fail"); + ctx->RSSetScissorRects(1, &scissorFail); + RunDraw(PixelHistory::ScissorFail); + + setMarker("Scissor Pass"); + ctx->RSSetScissorRects(1, &scissorPass); + RunDraw(PixelHistory::ScissorPass); + + ctx->RSSetScissorRects(1, &scissor); + + setMarker("Stencil Ref"); + b.stencilRefState.set(ctx); + RunDraw(PixelHistory::StencilRef); + + setMarker("Stencil Mask"); + b.stencilMaskState.set(ctx); + RunDraw(PixelHistory::StencilMask); + + setMarker("Depth Test"); + b.depthState.set(ctx); + RunDraw(PixelHistory::DepthTest); + + setMarker("Sample Colouring"); + b.sampleColourState.set(ctx); + RunDraw(PixelHistory::SampleColour); + + setMarker("Depth Equal Fail"); + b.depthEqualState.set(ctx); + RunDraw(PixelHistory::DepthEqualFail); + + setMarker("Depth Equal Pass"); + b.depthEqualState.set(ctx); + if(b.depthFormat == DXGI_FORMAT_D24_UNORM_S8_UINT) + RunDraw(PixelHistory::DepthEqualPass24); + else if(b.depthFormat == DXGI_FORMAT_D16_UNORM) + RunDraw(PixelHistory::DepthEqualPass16); + else + RunDraw(PixelHistory::DepthEqualPass32); + + setMarker("Colour Masked"); + b.colorMaskState.set(ctx); + RunDraw(PixelHistory::ColourMask); + + setMarker("Overflowing"); + b.backgroundState.set(ctx); + RunDraw(PixelHistory::OverflowingDraw); + + setMarker("Per-Fragment discarding"); + b.backgroundState.set(ctx); + RunDraw(PixelHistory::PerFragDiscard); + } + + int main() + { + // initialise, create window, create device, etc + if(!Init()) + return 3; + + PixelHistory::init(); + + ID3D11BufferPtr vb = MakeBuffer() + .Vertex() + .Size(UINT(sizeof(DefaultA2V) * PixelHistory::vb.size())) + .Data(PixelHistory::vb.data()); + + ID3D11Texture2DPtr bbBlitSource; + + BuildTestBatch("Basic", 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + bbBlitSource = batches.back().colImg2D; + + BuildTestBatch("MSAA", 4, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + BuildTestBatch("Colour Only", 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + BuildTestBatch("Depth Only", 1, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + BuildTestBatch("Mip & Slice", 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + 2, 3); + BuildTestBatch("Slice MSAA", 4, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + -1, 3); + + // can't test 3D textures with depth as 3D depth is not supported and can't mix 3D with 2D array as in other APIs + BuildTestBatch("3D texture", 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, -1, -1, 8); + + BuildTestBatch("D24S8", 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_D24_UNORM_S8_UINT); + + BuildTestBatch("D16", 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_D16_UNORM); + BuildTestBatch("D32", 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_D32_FLOAT); + + BuildTestBatch("F16 UNORM", 1, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + BuildTestBatch("F16 FLOAT", 1, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + BuildTestBatch("F32 FLOAT", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + + BuildTestBatch("8-bit uint", 1, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + BuildTestBatch("16-bit uint", 1, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + BuildTestBatch("32-bit uint", 1, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + + while(Running()) + { + for(const D3D11TestBatch &b : batches) + { + IASetVertexBuffer(vb, sizeof(DefaultA2V), 0); + + { + pushMarker("Batch: " + b.name); + { + setMarker("Begin RenderPass"); + + float clearColor[4] = {0.2f, 0.2f, 0.2f, 1.0f}; + if(b.uint) + { + clearColor[0] = 80.0f; + clearColor[1] = 80.0f; + clearColor[2] = 80.0f; + clearColor[3] = 16.0f; + } + + if(b.RTV) + ctx->ClearRenderTargetView(b.RTV, clearColor); + if(b.DSV) + ctx->ClearDepthStencilView(b.DSV, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + + ID3D11RenderTargetViewPtr RTV = b.RTV; + ctx->OMSetRenderTargets(b.RTV ? 1 : 0, &RTV.GetInterfacePtr(), b.DSV); + + RunBatch(b); + + if(b.comp) + { + setMarker("Compute write"); + + ctx->OMSetRenderTargets(0, NULL, NULL); + ctx->CSSetShader(b.comp, NULL, 0); + ID3D11UnorderedAccessViewPtr UAV = b.compUAV; + ctx->CSSetUnorderedAccessViews(0, 1, &UAV.GetInterfacePtr(), NULL); + ctx->Dispatch(1, 1, 1); + } + } + popMarker(); + } + } + + if(bbBlitSource) + { + ctx->OMSetBlendState(NULL, NULL, ~0U); + blitToSwap(bbBlitSource); + } + + Present(); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/demos/d3d11/d3d11_pixel_history_zoo.cpp b/util/test/demos/d3d11/d3d11_pixel_history_zoo.cpp deleted file mode 100644 index 6b9756b2d..000000000 --- a/util/test/demos/d3d11/d3d11_pixel_history_zoo.cpp +++ /dev/null @@ -1,771 +0,0 @@ -/****************************************************************************** - * The MIT License (MIT) - * - * Copyright (c) 2019-2025 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"; - - std::string pixelUAVWrite = R"EOSHADER( - -struct v2f -{ - float4 pos : SV_POSITION; - float4 col : COLOR0; - float2 uv : TEXCOORD0; -}; - -RWTexture2D uavOut; - -float4 main(v2f IN) : SV_Target0 -{ - uavOut[IN.pos.xy*0.5] = float4(IN.uv.x, IN.uv.y, 0.0f, 1.0f); - return float4(0.1234, 1.0f, 0.0f, 0.5f); -} - -)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")); - ID3D11PixelShaderPtr psUAVWrite = CreatePS(Compile(pixelUAVWrite, "main", "ps_5_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()); - - // texture for UAV write testing - ID3D11UnorderedAccessViewPtr uavView = - MakeUAV(MakeTexture(DXGI_FORMAT_R8G8B8A8_UNORM, 8, 8).UAV().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(); - } - } - - { - float white[] = {1.0f, 1.0f, 1.0f, 1.0f}; - ctx->ClearUnorderedAccessViewFloat(uavView.GetInterfacePtr(), white); - ctx->PSSetShader(psUAVWrite, NULL, 0); - ctx->OMSetRenderTargetsAndUnorderedAccessViews(1, &rts[0].GetInterfacePtr(), NULL, 1, 1, - &uavView.GetInterfacePtr(), NULL); - - setMarker("UAVWrite"); - ctx->Draw(3, 0); - ctx->PSSetShader(psUAVWrite, NULL, 0); - } - - Present(); - } - - return 0; - } -}; - -REGISTER_TEST(); diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index 675a902de..ae75e5aad 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -164,7 +164,7 @@ - + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index e711dae44..433808646 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -451,9 +451,6 @@ D3D12\demos - - D3D11\demos - OpenGL\demos @@ -739,6 +736,9 @@ D3D12\demos + + D3D11\demos + diff --git a/util/test/tests/D3D11/D3D11_Pixel_History.py b/util/test/tests/D3D11/D3D11_Pixel_History.py new file mode 100644 index 000000000..f14025591 --- /dev/null +++ b/util/test/tests/D3D11/D3D11_Pixel_History.py @@ -0,0 +1,5 @@ +import rdtest + +class D3D11_Pixel_History(rdtest.Pixel_History): + demos_test_name = 'D3D11_Pixel_History' + internal = False diff --git a/util/test/tests/D3D11/D3D11_Pixel_History_Zoo.py b/util/test/tests/D3D11/D3D11_Pixel_History_Zoo.py deleted file mode 100644 index c714cbce3..000000000 --- a/util/test/tests/D3D11/D3D11_Pixel_History_Zoo.py +++ /dev/null @@ -1,110 +0,0 @@ -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): - actions = self.controller.GetRootActions() - - for d in self.controller.GetRootActions(): - # Only process test actions - if not d.customName.startswith('Test'): - continue - - # Go to the last child action - self.controller.SetFrameEvent(d.children[-1].eventId, True) - - if any(['UInt tex' in d.customName for d in d.children]): - value_selector = lambda x: x.uintValue - shader_out = (0, 1, 1234, 5) - elif any(['SInt tex' in d.customName 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 = pipe.GetOutputTargets()[0] - - vp: rd.Viewport = pipe.GetViewport(0) - - tex = rt.resource - 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.format.compType) - - # Should be at least two modifications in every test - clear and action - self.check(len(modifs) >= 2) - - self.check_modifiations(modifs, value_selector, 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.format.compType) - - # Also the red channel should be zero, as it indicates errors - self.check(float(value_selector(modifs[-1].postMod.col)[0]) == 0.0) - - self.check_uavwrite() - - def check_uavwrite(self): - uavWrite = self.find_action("UAVWrite") - if uavWrite is None: - rdtest.log.print("UAVWrite Test not found") - return - - self.controller.SetFrameEvent(uavWrite.next.eventId, True) - pipe: rd.PipeState = self.controller.GetPipelineState() - uav = pipe.GetReadWriteResources(rd.ShaderStage.Pixel)[0].descriptor - vp: rd.Viewport = pipe.GetViewport(0) - tex = uav.resource - x, y = 4, 4 - sub = rd.Subresource() - value_selector = lambda x: x.floatValue - shader_out = (0.3451, 0.43922, 0.0, 1.0) - - modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, uav.format.compType) - # Should be two modifications - clear and draw - self.check(len(modifs) == 2) - self.check_modifiations(modifs, value_selector, shader_out) - rdtest.log.success("UAVWrite 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=uav.format.compType) - - def check_modifiations(self, modifs: List[rd.PixelModification], value_selector, shader_out): - # 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))) - - # A fragment event : postMod.stencil should be unknown - if modifs[i].eventId == modifs[i+1].eventId: - if modifs[i].postMod.stencil != -1 and modifs[i].postMod.stencil != -2: - raise rdtest.TestFailureException( - "postmod stencil at {} primitive {}: {} is not unknown".format(modifs[i].eventId, - modifs[i].primitiveID, - modifs[i].postMod.stencil)) - - if self.get_action(modifs[i].eventId).flags & rd.ActionFlags.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)) \ No newline at end of file