diff options
| author | lucy96chen <47800040+lucy96chen@users.noreply.github.com> | 2022-06-14 21:08:51 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-14 21:08:51 -0700 |
| commit | 69cb218100f593036d1a89357303f9c1368841ea (patch) | |
| tree | 7fe28be1c354267dd440bfbb4d1f37647436b769 | |
| parent | ebcda2ec8b1cfb54f52329bb1134511ca4d4dbff (diff) | |
Swapchain resize now draws both before and after the resize operation (#2281)
4 files changed, 218 insertions, 4 deletions
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj index 97fb723b4..7c8c6102c 100644 --- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj @@ -313,6 +313,7 @@ <None Include="..\..\..\tools\gfx-unit-test\resolve-resource-shader.slang" />
<None Include="..\..\..\tools\gfx-unit-test\root-shader-parameter.slang" />
<None Include="..\..\..\tools\gfx-unit-test\sampler-array.slang" />
+ <None Include="..\..\..\tools\gfx-unit-test\swapchain-shader.slang" />
<None Include="..\..\..\tools\gfx-unit-test\trivial-copy-textures.slang" />
<None Include="..\..\..\tools\gfx-unit-test\trivial-copy.slang" />
</ItemGroup>
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters index dffe6e25e..e4cab3ca6 100644 --- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters @@ -136,6 +136,9 @@ <None Include="..\..\..\tools\gfx-unit-test\sampler-array.slang">
<Filter>Source Files</Filter>
</None>
+ <None Include="..\..\..\tools\gfx-unit-test\swapchain-shader.slang">
+ <Filter>Source Files</Filter>
+ </None>
<None Include="..\..\..\tools\gfx-unit-test\trivial-copy-textures.slang">
<Filter>Source Files</Filter>
</None>
diff --git a/tools/gfx-unit-test/swap-chain-resize-test.cpp b/tools/gfx-unit-test/swap-chain-resize-test.cpp index 903deba30..3940ebd6d 100644 --- a/tools/gfx-unit-test/swap-chain-resize-test.cpp +++ b/tools/gfx-unit-test/swap-chain-resize-test.cpp @@ -11,6 +11,20 @@ using namespace Slang; namespace gfx_test { + struct Vertex + { + float position[3]; + }; + + static const int kVertexCount = 3; + static const Vertex kVertexData[kVertexCount] = + { + // Triangle 1 + { 0, 0, 1 }, + { 4, 0, 1 }, + { 0, 4, 1 }, + }; + struct SwapchainResizeTest { IDevice* device; @@ -20,9 +34,18 @@ namespace gfx_test ComPtr<ICommandQueue> queue; ComPtr<ISwapchain> swapchain; - static const GfxCount width = 500; - static const GfxCount height = 500; + ComPtr<ITransientResourceHeap> transientHeap; + ComPtr<gfx::IFramebufferLayout> framebufferLayout; + ComPtr<IPipelineState> pipelineState; + ComPtr<IRenderPassLayout> renderPass; + List<ComPtr<IFramebuffer>> framebuffers; + + ComPtr<IBufferResource> vertexBuffer; + + GfxCount width = 500; + GfxCount height = 500; static const int kSwapchainImageCount = 2; + const Format format = Format::R8G8B8A8_UNORM; void init(IDevice* device, UnitTestContext* context) { @@ -30,6 +53,33 @@ namespace gfx_test this->context = context; } + void createSwapchainFramebuffers() + { + framebuffers.clear(); + for (GfxIndex i = 0; i < kSwapchainImageCount; ++i) + { + ComPtr<ITextureResource> colorBuffer; + swapchain->getImage(i, colorBuffer.writeRef()); + + gfx::IResourceView::Desc colorBufferViewDesc; + memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); + colorBufferViewDesc.format = swapchain->getDesc().format; + colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; + colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; + auto rtv = device->createTextureView(colorBuffer.get(), colorBufferViewDesc); + + gfx::IFramebuffer::Desc framebufferDesc; + framebufferDesc.renderTargetCount = 1; + framebufferDesc.depthStencilView = nullptr; + framebufferDesc.renderTargetViews = rtv.readRef(); + framebufferDesc.layout = framebufferLayout; + ComPtr<IFramebuffer> framebuffer; + GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); + + framebuffers.add(framebuffer); + } + } + void createRequiredResources() { platform::Application::init(); @@ -52,15 +102,122 @@ namespace gfx_test swapchainDesc.imageCount = kSwapchainImageCount; swapchainDesc.queue = queue; WindowHandle windowHandle = window->getNativeHandle().convert<WindowHandle>(); - if (SLANG_FAILED(device->createSwapchain(swapchainDesc, windowHandle, swapchain.writeRef()))) + auto createSwapchainResult = device->createSwapchain(swapchainDesc, windowHandle, swapchain.writeRef()); + if (SLANG_FAILED(createSwapchainResult)) + { SLANG_IGNORE_TEST; + } + + VertexStreamDesc vertexStreams[] = { + { sizeof(Vertex), InputSlotClass::PerVertex, 0 }, + }; + + InputElementDesc inputElements[] = { + // Vertex buffer data + { "POSITIONA", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0 }, + }; + IInputLayout::Desc inputLayoutDesc = {}; + inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements); + inputLayoutDesc.inputElements = inputElements; + inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams); + inputLayoutDesc.vertexStreams = vertexStreams; + auto inputLayout = device->createInputLayout(inputLayoutDesc); + SLANG_CHECK_ABORT(inputLayout != nullptr); + + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); + vertexBufferDesc.defaultState = ResourceState::ShaderResource; + vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); + SLANG_CHECK_ABORT(vertexBuffer != nullptr); + + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096 * 1024; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadGraphicsProgram(device, shaderProgram, "swapchain-shader", "vertexMain", "fragmentMain", slangReflection)); + + IFramebufferLayout::TargetLayout targetLayout; + targetLayout.format = format; + targetLayout.sampleCount = 1; + + IFramebufferLayout::Desc framebufferLayoutDesc; + framebufferLayoutDesc.renderTargetCount = 1; + framebufferLayoutDesc.renderTargets = &targetLayout; + framebufferLayout = device->createFramebufferLayout(framebufferLayoutDesc); + SLANG_CHECK_ABORT(framebufferLayout != nullptr); + + GraphicsPipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + pipelineDesc.inputLayout = inputLayout; + pipelineDesc.framebufferLayout = framebufferLayout; + pipelineDesc.depthStencil.depthTestEnable = false; + pipelineDesc.depthStencil.depthWriteEnable = false; + GFX_CHECK_CALL_ABORT( + device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef())); + + IRenderPassLayout::Desc renderPassDesc = {}; + renderPassDesc.framebufferLayout = framebufferLayout; + renderPassDesc.renderTargetCount = 1; + IRenderPassLayout::TargetAccessDesc renderTargetAccess = {}; + renderTargetAccess.loadOp = IRenderPassLayout::TargetLoadOp::Clear; + renderTargetAccess.storeOp = IRenderPassLayout::TargetStoreOp::Store; + renderTargetAccess.initialState = ResourceState::Undefined; + renderTargetAccess.finalState = ResourceState::Present; + renderPassDesc.renderTargetAccess = &renderTargetAccess; + GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); + + createSwapchainFramebuffers(); + } + + void renderFrame(GfxIndex framebufferIndex) + { + auto commandBuffer = transientHeap->createCommandBuffer(); + + auto encoder = commandBuffer->encodeRenderCommands(renderPass, framebuffers[framebufferIndex]); + auto rootObject = encoder->bindPipeline(pipelineState); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)width; + viewport.extentY = (float)height; + encoder->setViewportAndScissor(viewport); + + encoder->setVertexBuffer(0, vertexBuffer); + encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + + encoder->draw(kVertexCount); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + swapchain->present(); } void run() { createRequiredResources(); - // TODO: Extend test by drawing for a few frames before and after resize to ensure swapchain remains usable + // Render for 5 frames then resize the swapchain and render for another 5 frames to ensure the + // swapchain remains usable after resizing. + for (GfxIndex i = 0; i < 5; ++i) + { + renderFrame(i % kSwapchainImageCount); + } + queue->waitOnHost(); + + framebuffers = decltype(framebuffers)(); GFX_CHECK_CALL(swapchain->resize(700, 700)); + createSwapchainFramebuffers(); + width = 700; + height = 700; + + for (GfxIndex i = 0; i < 5; ++i) + { + renderFrame(i % kSwapchainImageCount); + } + queue->waitOnHost(); } }; diff --git a/tools/gfx-unit-test/swapchain-shader.slang b/tools/gfx-unit-test/swapchain-shader.slang new file mode 100644 index 000000000..1a3ab1a3e --- /dev/null +++ b/tools/gfx-unit-test/swapchain-shader.slang @@ -0,0 +1,53 @@ +// swapchain-shader.slang + +// Per-vertex attributes to be assembled from bound vertex buffers. +struct AssembledVertex +{ + float3 positionA : POSITIONA; +}; + +// Output of the vertex shader, and input to the fragment shader. +struct CoarseVertex +{ + float3 color; +}; + +// Output of the fragment shader +struct Fragment +{ + float4 color; +}; + +// Vertex Shader + +struct VertexStageOutput +{ + CoarseVertex coarseVertex : CoarseVertex; + float4 sv_position : SV_Position; +}; + +[shader("vertex")] +VertexStageOutput vertexMain( + AssembledVertex assembledVertex) +{ + VertexStageOutput output; + + float3 position = assembledVertex.positionA; + float3 color = float3(0, 0, 1); + + output.coarseVertex.color = color; + output.sv_position = float4(position, 1.0); + + return output; +} + +// Fragment Shader + +[shader("fragment")] +float4 fragmentMain( + CoarseVertex coarseVertex : CoarseVertex) : SV_Target +{ + float3 color = coarseVertex.color; + + return float4(color, 1.0); +} |
