diff options
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj | 2 | ||||
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters | 6 | ||||
| -rw-r--r-- | slang-gfx.h | 2 | ||||
| -rw-r--r-- | tools/gfx-unit-test/gfx-test-util.h | 2 | ||||
| -rw-r--r-- | tools/gfx-unit-test/resolve-resource-shader.slang | 54 | ||||
| -rw-r--r-- | tools/gfx-unit-test/resolve-resource-tests.cpp | 355 | ||||
| -rw-r--r-- | tools/gfx/cuda/render-cuda.cpp | 4 | ||||
| -rw-r--r-- | tools/gfx/d3d12/render-d3d12.cpp | 39 | ||||
| -rw-r--r-- | tools/gfx/debug-layer.cpp | 4 | ||||
| -rw-r--r-- | tools/gfx/debug-layer.h | 2 | ||||
| -rw-r--r-- | tools/gfx/immediate-renderer-base.cpp | 4 | ||||
| -rw-r--r-- | tools/gfx/vulkan/render-vk.cpp | 57 | ||||
| -rw-r--r-- | tools/gfx/vulkan/vk-api.h | 1 |
13 files changed, 516 insertions, 16 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 f43d6150e..59103d30e 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 @@ -286,6 +286,7 @@ <ClCompile Include="..\..\..\tools\gfx-unit-test\instanced-draw-tests.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\nested-parameter-block.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\resolve-resource-tests.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\root-mutable-shader-object.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\shared-buffers-tests.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\shared-textures-tests.cpp" />
@@ -299,6 +300,7 @@ <None Include="..\..\..\tools\gfx-unit-test\graphics-smoke.slang" />
<None Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.slang" />
<None Include="..\..\..\tools\gfx-unit-test\nested-parameter-block.slang" />
+ <None Include="..\..\..\tools\gfx-unit-test\resolve-resource-shader.slang" />
<None Include="..\..\..\tools\gfx-unit-test\trivial-copy.slang" />
</ItemGroup>
<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 ff873deb9..aec553af8 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 @@ -71,6 +71,9 @@ <ClCompile Include="..\..\..\tools\unit-test\slang-unit-test.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\resolve-resource-tests.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\tools\gfx-unit-test\buffer-barrier-test.slang">
@@ -97,5 +100,8 @@ <None Include="..\..\..\tools\gfx-unit-test\trivial-copy.slang">
<Filter>Source Files</Filter>
</None>
+ <None Include="..\..\..\tools\gfx-unit-test\resolve-resource-shader.slang">
+ <Filter>Source Files</Filter>
+ </None>
</ItemGroup>
</Project>
\ No newline at end of file diff --git a/slang-gfx.h b/slang-gfx.h index 5949e5463..dcd78fc5b 100644 --- a/slang-gfx.h +++ b/slang-gfx.h @@ -1629,8 +1629,10 @@ public: IResourceView* view, ClearValue* clearValue, ClearResourceViewFlags::Enum flags) = 0; virtual SLANG_NO_THROW void SLANG_MCALL resolveResource( ITextureResource* source, + ResourceState sourceState, SubresourceRange sourceRange, ITextureResource* dest, + ResourceState destState, SubresourceRange destRange) = 0; }; diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h index 3be47bc82..67660d4f5 100644 --- a/tools/gfx-unit-test/gfx-test-util.h +++ b/tools/gfx-unit-test/gfx-test-util.h @@ -34,7 +34,7 @@ namespace gfx_test const void* expectedResult, size_t expectedBufferSize); - /// Reads back the content of `buffer` and compares it against `expectedResult`. + /// Reads back the content of `texture` and compares it against `expectedResult`. void compareComputeResult( gfx::IDevice* device, gfx::ITextureResource* texture, diff --git a/tools/gfx-unit-test/resolve-resource-shader.slang b/tools/gfx-unit-test/resolve-resource-shader.slang new file mode 100644 index 000000000..f8f3319c2 --- /dev/null +++ b/tools/gfx-unit-test/resolve-resource-shader.slang @@ -0,0 +1,54 @@ +// resolve-resource-shader.slang + +// Per-vertex attributes to be assembled from bound vertex buffers. +struct AssembledVertex +{ + float3 position : POSITION; + float3 color : COLOR; +}; + +// 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.position; + float3 color = assembledVertex.color; + + 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); +} diff --git a/tools/gfx-unit-test/resolve-resource-tests.cpp b/tools/gfx-unit-test/resolve-resource-tests.cpp new file mode 100644 index 000000000..2876be880 --- /dev/null +++ b/tools/gfx-unit-test/resolve-resource-tests.cpp @@ -0,0 +1,355 @@ +#include "tools/unit-test/slang-unit-test.h" + +#include "slang-gfx.h" +#include "gfx-test-util.h" +#include "tools/gfx-util/shader-cursor.h" +#include "source/core/slang-basic.h" + +#if SLANG_WINDOWS_FAMILY +#include <d3d12.h> +#endif + +#if 0 +#include <stdlib.h> +#include <stdio.h> + +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "external/stb/stb_image_write.h" +#endif + +using namespace Slang; +using namespace gfx; + +namespace +{ + using namespace gfx_test; + +#if 0 + Slang::Result writeImage( + const char* filename, + ISlangBlob* pixels, + uint32_t width, + uint32_t height) + { + int stbResult = + stbi_write_hdr(filename, width, height, 4, (float*)pixels->getBufferPointer()); + + return stbResult ? SLANG_OK : SLANG_FAIL; + } +#endif + + struct Vertex + { + float position[3]; + float color[3]; + }; + + static const int kVertexCount = 12; + static const Vertex kVertexData[kVertexCount] = + { + // Triangle 1 + { { 0, 0, 0.5 }, { 1, 0, 0 } }, + { { 1, 1, 0.5 }, { 1, 0, 0 } }, + { { -1, 1, 0.5 }, { 1, 0, 0 } }, + + // Triangle 2 + { { -1, 1, 0.5 }, { 0, 1, 0 } }, + { { 0, 0, 0.5 }, { 0, 1, 0 } }, + { { -1, -1, 0.5 }, { 0, 1, 0 } }, + + // Triangle 3 + { { -1, -1, 0.5 }, { 0, 0, 1 } }, + { { 0, 0, 0.5 }, { 0, 0, 1 } }, + { { 1, -1, 0.5 }, { 0, 0, 1 } }, + + // Triangle 4 + { { 1, -1, 0.5 }, { 0, 0, 0 } }, + { { 0, 0, 0.5 }, { 0, 0, 0 } }, + { { 1, 1, 0.5 }, { 0, 0, 0 } }, + }; + + const int kWidth = 256; + const int kHeight = 256; + Format format = Format::R32G32B32A32_FLOAT; + + ComPtr<IBufferResource> createVertexBuffer(IDevice* device) + { + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); + vertexBufferDesc.defaultState = ResourceState::VertexBuffer; + vertexBufferDesc.allowedStates = ResourceState::VertexBuffer; + ComPtr<IBufferResource> vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); + SLANG_CHECK_ABORT(vertexBuffer != nullptr); + return vertexBuffer; + } + + struct BaseResolveResourceTest + { + IDevice* device; + UnitTestContext* context; + + ComPtr<ITextureResource> msaaTexture; + ComPtr<ITextureResource> dstTexture; + + ComPtr<ITransientResourceHeap> transientHeap; + ComPtr<IPipelineState> pipelineState; + ComPtr<IRenderPassLayout> renderPass; + ComPtr<IFramebuffer> framebuffer; + + ComPtr<IBufferResource> vertexBuffer; + + struct TextureInfo + { + ITextureResource::Size extent; + int numMipLevels; + int arraySize; + ITextureResource::SubresourceData const* initData; + }; + + void init(IDevice* device, UnitTestContext* context) + { + this->device = device; + this->context = context; + } + + void createRequiredResources(TextureInfo msaaTextureInfo, TextureInfo dstTextureInfo, Format format) + { + VertexStreamDesc vertexStreams[] = { + { sizeof(Vertex), InputSlotClass::PerVertex, 0 }, + }; + + InputElementDesc inputElements[] = { + // Vertex buffer data + { "POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0 }, + { "COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color), 0 }, + }; + + ITextureResource::Desc msaaTexDesc = {}; + msaaTexDesc.type = IResource::Type::Texture2D; + msaaTexDesc.numMipLevels = dstTextureInfo.numMipLevels; + msaaTexDesc.arraySize = dstTextureInfo.arraySize; + msaaTexDesc.size = dstTextureInfo.extent; + msaaTexDesc.defaultState = ResourceState::RenderTarget; + msaaTexDesc.allowedStates = ResourceStateSet( + ResourceState::RenderTarget, + ResourceState::ResolveSource); + msaaTexDesc.format = format; + msaaTexDesc.sampleDesc.numSamples = 4; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + msaaTexDesc, + msaaTextureInfo.initData, + msaaTexture.writeRef())); + + ITextureResource::Desc dstTexDesc = {}; + dstTexDesc.type = IResource::Type::Texture2D; + dstTexDesc.numMipLevels = dstTextureInfo.numMipLevels; + dstTexDesc.arraySize = dstTextureInfo.arraySize; + dstTexDesc.size = dstTextureInfo.extent; + dstTexDesc.defaultState = ResourceState::ResolveDestination; + dstTexDesc.allowedStates = ResourceStateSet( + ResourceState::ResolveDestination, + ResourceState::CopySource); + dstTexDesc.format = format; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + dstTexDesc, + dstTextureInfo.initData, + dstTexture.writeRef())); + + 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); + + vertexBuffer = createVertexBuffer(device); + + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadGraphicsProgram(device, shaderProgram, "resolve-resource-shader", "vertexMain", "fragmentMain", slangReflection)); + + IFramebufferLayout::AttachmentLayout attachmentLayout; + attachmentLayout.format = format; + attachmentLayout.sampleCount = 4; + + IFramebufferLayout::Desc framebufferLayoutDesc; + framebufferLayoutDesc.renderTargetCount = 1; + framebufferLayoutDesc.renderTargets = &attachmentLayout; + ComPtr<gfx::IFramebufferLayout> 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::AttachmentAccessDesc renderTargetAccess = {}; + renderTargetAccess.loadOp = IRenderPassLayout::AttachmentLoadOp::Clear; + renderTargetAccess.storeOp = IRenderPassLayout::AttachmentStoreOp::Store; + renderTargetAccess.initialState = ResourceState::RenderTarget; + renderTargetAccess.finalState = ResourceState::ResolveSource; + renderPassDesc.renderTargetAccess = &renderTargetAccess; + GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef())); + + gfx::IResourceView::Desc colorBufferViewDesc; + memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc)); + colorBufferViewDesc.format = format; + colorBufferViewDesc.renderTarget.shape = gfx::IResource::Type::Texture2D; + colorBufferViewDesc.type = gfx::IResourceView::Type::RenderTarget; + auto rtv = device->createTextureView(msaaTexture, colorBufferViewDesc); + + gfx::IFramebuffer::Desc framebufferDesc; + framebufferDesc.renderTargetCount = 1; + framebufferDesc.depthStencilView = nullptr; + framebufferDesc.renderTargetViews = rtv.readRef(); + framebufferDesc.layout = framebufferLayout; + GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef())); + } + + void submitGPUWork(SubresourceRange msaaSubresource, SubresourceRange dstSubresource, ITextureResource::Size extent) + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto renderEncoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer); + auto rootObject = renderEncoder->bindPipeline(pipelineState); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = kWidth; + viewport.extentY = kHeight; + renderEncoder->setViewportAndScissor(viewport); + + renderEncoder->setVertexBuffer(0, vertexBuffer); + renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + renderEncoder->draw(kVertexCount, 0); + renderEncoder->endEncoding(); + + auto resourceEncoder = commandBuffer->encodeResourceCommands(); + + resourceEncoder->resolveResource(msaaTexture, ResourceState::ResolveSource, msaaSubresource, dstTexture, ResourceState::ResolveDestination, dstSubresource); + resourceEncoder->textureSubresourceBarrier(dstTexture, dstSubresource, ResourceState::ResolveDestination, ResourceState::CopySource); + resourceEncoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } + + void checkTestResults(int pixelCount, int channelCount, const int* testXCoords, const int* testYCoords, float* testResults) + { + // Read texture values back from four specific pixels located within the triangles + // and compare against expected values (because testing every single pixel will be too long and tedious + // and requires maintaining reference images). + ComPtr<ISlangBlob> resultBlob; + size_t rowPitch = 0; + size_t pixelSize = 0; + GFX_CHECK_CALL_ABORT(device->readTextureResource( + dstTexture, ResourceState::CopySource, resultBlob.writeRef(), &rowPitch, &pixelSize)); + auto result = (float*)resultBlob->getBufferPointer(); + + int cursor = 0; + for (int i = 0; i < pixelCount; ++i) + { + auto x = testXCoords[i]; + auto y = testYCoords[i]; + auto pixelPtr = result + x * channelCount + y * rowPitch / sizeof(float); + for (int j = 0; j < channelCount; ++j) + { + testResults[cursor] = pixelPtr[j]; + cursor++; + } + } + + float expectedResult[] = { 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f, + 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f }; + SLANG_CHECK(memcmp(testResults, expectedResult, 128) == 0); + } + }; + + // TODO: Add more tests? + + struct ResolveResourceSimple : BaseResolveResourceTest + { + void run() + { + ITextureResource::Size extent = {}; + extent.width = kWidth; + extent.height = kHeight; + extent.depth = 1; + + TextureInfo msaaTextureInfo = { extent, 1, 1, nullptr }; + TextureInfo dstTextureInfo = { extent, 1, 1, nullptr }; + + createRequiredResources(msaaTextureInfo, dstTextureInfo, format); + + SubresourceRange msaaSubresource = {}; + msaaSubresource.aspectMask = TextureAspect::Color; + msaaSubresource.mipLevel = 0; + msaaSubresource.mipLevelCount = 1; + msaaSubresource.baseArrayLayer = 0; + msaaSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = TextureAspect::Color; + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + submitGPUWork(msaaSubresource, dstSubresource, extent); + + const int kPixelCount = 8; + const int kChannelCount = 4; + int testXCoords[kPixelCount] = { 64, 127, 191, 64, 191, 64, 127, 191 }; + int testYCoords[kPixelCount] = { 64, 64, 64, 127, 127, 191, 191, 191 }; + float testResults[kPixelCount * kChannelCount]; + + checkTestResults(kPixelCount, kChannelCount, testXCoords, testYCoords, testResults); + } + }; + + template<typename T> + void resolveResourceTestImpl(IDevice* device, UnitTestContext* context) + { + T test; + test.init(device, context); + test.run(); + } +} + +namespace gfx_test +{ + SLANG_UNIT_TEST(resolveResourceSimpleD3D12) + { + runTestImpl(resolveResourceTestImpl<ResolveResourceSimple>, unitTestContext, Slang::RenderApiFlag::D3D12); + } + + SLANG_UNIT_TEST(resolveResourceSimpleVulkan) + { + runTestImpl(resolveResourceTestImpl<ResolveResourceSimple>, unitTestContext, Slang::RenderApiFlag::Vulkan); + } +} diff --git a/tools/gfx/cuda/render-cuda.cpp b/tools/gfx/cuda/render-cuda.cpp index 3e55242f0..0446dc055 100644 --- a/tools/gfx/cuda/render-cuda.cpp +++ b/tools/gfx/cuda/render-cuda.cpp @@ -1111,13 +1111,17 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL resolveResource( ITextureResource* source, + ResourceState sourceState, SubresourceRange sourceRange, ITextureResource* dest, + ResourceState destState, SubresourceRange destRange) override { SLANG_UNUSED(source); + SLANG_UNUSED(sourceState); SLANG_UNUSED(sourceRange); SLANG_UNUSED(dest); + SLANG_UNUSED(destState); SLANG_UNUSED(destRange); SLANG_UNIMPLEMENTED_X("resolveResource"); } diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp index e0c324d34..1b146bc4e 100644 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ b/tools/gfx/d3d12/render-d3d12.cpp @@ -4314,15 +4314,44 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL resolveResource( ITextureResource* source, + ResourceState sourceState, SubresourceRange sourceRange, ITextureResource* dest, + ResourceState destState, SubresourceRange destRange) override { - SLANG_UNUSED(source); - SLANG_UNUSED(sourceRange); - SLANG_UNUSED(dest); - SLANG_UNUSED(destRange); - SLANG_UNIMPLEMENTED_X("resolveResource"); + auto srcTexture = static_cast<TextureResourceImpl*>(source); + auto srcDesc = srcTexture->getDesc(); + auto dstTexture = static_cast<TextureResourceImpl*>(dest); + auto dstDesc = dstTexture->getDesc(); + + for (uint32_t layer = 0; layer < sourceRange.layerCount; ++layer) + { + for (uint32_t mip = 0; mip < sourceRange.mipLevelCount; ++mip) + { + auto srcSubresourceIndex = D3DUtil::getSubresourceIndex( + mip + sourceRange.mipLevel, + layer + sourceRange.baseArrayLayer, + 0, + srcDesc->numMipLevels, + srcDesc->arraySize); + auto dstSubresourceIndex = D3DUtil::getSubresourceIndex( + mip + destRange.mipLevel, + layer + destRange.baseArrayLayer, + 0, + dstDesc->numMipLevels, + dstDesc->arraySize); + + DXGI_FORMAT format = D3DUtil::getMapFormat(srcDesc->format); + + m_commandBuffer->m_cmdList->ResolveSubresource( + dstTexture->m_resource.getResource(), + dstSubresourceIndex, + srcTexture->m_resource.getResource(), + srcSubresourceIndex, + format); + } + } } virtual SLANG_NO_THROW void SLANG_MCALL copyTextureToBuffer( diff --git a/tools/gfx/debug-layer.cpp b/tools/gfx/debug-layer.cpp index 53deec385..f34a77556 100644 --- a/tools/gfx/debug-layer.cpp +++ b/tools/gfx/debug-layer.cpp @@ -1343,12 +1343,14 @@ void DebugResourceCommandEncoder::clearResourceView( void DebugResourceCommandEncoder::resolveResource( ITextureResource* source, + ResourceState sourceState, SubresourceRange sourceRange, ITextureResource* dest, + ResourceState destState, SubresourceRange destRange) { SLANG_GFX_API_FUNC; - baseObject->resolveResource(getInnerObj(source), sourceRange, getInnerObj(dest), destRange); + baseObject->resolveResource(getInnerObj(source), sourceState, sourceRange, getInnerObj(dest), destState, destRange); } void DebugResourceCommandEncoder::copyTextureToBuffer( diff --git a/tools/gfx/debug-layer.h b/tools/gfx/debug-layer.h index a2de7eb31..94f3e3f14 100644 --- a/tools/gfx/debug-layer.h +++ b/tools/gfx/debug-layer.h @@ -463,8 +463,10 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL resolveResource( ITextureResource* source, + ResourceState sourceState, SubresourceRange sourceRange, ITextureResource* dest, + ResourceState destState, SubresourceRange destRange) override; virtual SLANG_NO_THROW void SLANG_MCALL copyTextureToBuffer( diff --git a/tools/gfx/immediate-renderer-base.cpp b/tools/gfx/immediate-renderer-base.cpp index ab2a51275..91b89c8cf 100644 --- a/tools/gfx/immediate-renderer-base.cpp +++ b/tools/gfx/immediate-renderer-base.cpp @@ -385,13 +385,17 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL resolveResource( ITextureResource* source, + ResourceState sourceState, SubresourceRange sourceRange, ITextureResource* dest, + ResourceState destState, SubresourceRange destRange) override { SLANG_UNUSED(source); + SLANG_UNUSED(sourceState); SLANG_UNUSED(sourceRange); SLANG_UNUSED(dest); + SLANG_UNUSED(destState); SLANG_UNUSED(destRange); SLANG_UNIMPLEMENTED_X("resolveResource"); } diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp index f31195cc8..517580c08 100644 --- a/tools/gfx/vulkan/render-vk.cpp +++ b/tools/gfx/vulkan/render-vk.cpp @@ -561,6 +561,7 @@ public: VkAttachmentReference m_depthReference; bool m_hasDepthStencilAttachment; uint32_t m_renderTargetCount; + VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT; public: ~FramebufferLayoutImpl() @@ -601,6 +602,8 @@ public: dst.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; dst.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; dst.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + sampleCount = Math::Max(dst.samples, sampleCount); } if (desc.depthStencil) @@ -615,6 +618,8 @@ public: dst.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; dst.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; dst.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + sampleCount = Math::Max(dst.samples, sampleCount); } Array<VkAttachmentReference, kMaxRenderTargets>& colorReferences = m_colorReferences; @@ -4780,15 +4785,43 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL resolveResource( ITextureResource* source, + ResourceState sourceState, SubresourceRange sourceRange, ITextureResource* dest, + ResourceState destState, SubresourceRange destRange) override { - SLANG_UNUSED(source); - SLANG_UNUSED(sourceRange); - SLANG_UNUSED(dest); - SLANG_UNUSED(destRange); - SLANG_UNIMPLEMENTED_X("resolveResource"); + auto srcTexture = static_cast<TextureResourceImpl*>(source); + auto srcExtent = srcTexture->getDesc()->size; + auto dstTexture = static_cast<TextureResourceImpl*>(dest); + + auto srcImage = srcTexture->m_image; + auto dstImage = dstTexture->m_image; + + auto srcImageLayout = VulkanUtil::getImageLayoutFromState(sourceState); + auto dstImageLayout = VulkanUtil::getImageLayoutFromState(destState); + + for (uint32_t layer = 0; layer < sourceRange.layerCount; ++layer) + { + for (uint32_t mip = 0; mip < sourceRange.mipLevelCount; ++mip) + { + VkImageResolve region = {}; + region.srcSubresource.aspectMask = getAspectMask(sourceRange.aspectMask); + region.srcSubresource.baseArrayLayer = layer + sourceRange.baseArrayLayer; + region.srcSubresource.layerCount = 1; + region.srcSubresource.mipLevel = mip + sourceRange.mipLevel; + region.srcOffset = { 0, 0, 0 }; + region.dstSubresource.aspectMask = getAspectMask(destRange.aspectMask); + region.dstSubresource.baseArrayLayer = layer + destRange.baseArrayLayer; + region.dstSubresource.layerCount = 1; + region.dstSubresource.mipLevel = mip + destRange.mipLevel; + region.dstOffset = { 0, 0, 0 }; + region.extent = { (uint32_t)srcExtent.width, (uint32_t)srcExtent.height, (uint32_t)srcExtent.depth }; + + auto& vkApi = m_commandBuffer->m_renderer->m_api; + vkApi.vkCmdResolveImage(m_commandBuffer->m_commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, 1, ®ion); + } + } } virtual SLANG_NO_THROW void SLANG_MCALL copyTextureToBuffer( @@ -7092,6 +7125,10 @@ static VkImageUsageFlagBits _calcImageUsageFlags(ResourceState state) return VK_IMAGE_USAGE_TRANSFER_SRC_BIT; case ResourceState::CopyDestination: return VK_IMAGE_USAGE_TRANSFER_DST_BIT; + case ResourceState::ResolveSource: + return VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + case ResourceState::ResolveDestination: + return VK_IMAGE_USAGE_TRANSFER_DST_BIT; default: { assert(!"Unsupported"); @@ -7323,7 +7360,7 @@ Result VKDevice::getTextureAllocationInfo( imageInfo.usage = _calcImageUsageFlags(desc.allowedStates, desc.memoryType, nullptr); imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.samples = (VkSampleCountFlagBits)desc.sampleDesc.numSamples; VkImage image; SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateImage(m_device, &imageInfo, nullptr, &image)); @@ -7402,7 +7439,7 @@ Result VKDevice::createTextureResource(const ITextureResource::Desc& descIn, con imageInfo.usage = _calcImageUsageFlags(desc.allowedStates, desc.memoryType, initData); imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.samples = (VkSampleCountFlagBits)desc.sampleDesc.numSamples; VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = { VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO }; #if SLANG_WINDOWS_FAMILY @@ -8278,10 +8315,12 @@ Result VKDevice::createGraphicsPipelineState(const GraphicsPipelineStateDesc& in rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; rasterizer.depthBiasEnable = VK_FALSE; + auto framebufferLayoutImpl = static_cast<FramebufferLayoutImpl*>(desc.framebufferLayout); + VkPipelineMultisampleStateCreateInfo multisampling = {}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.rasterizationSamples = framebufferLayoutImpl->sampleCount; VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; @@ -8332,7 +8371,7 @@ Result VKDevice::createGraphicsPipelineState(const GraphicsPipelineStateDesc& in pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDepthStencilState = &depthStencilStateInfo; pipelineInfo.layout = programImpl->m_rootObjectLayout->m_pipelineLayout; - pipelineInfo.renderPass = static_cast<FramebufferLayoutImpl*>(desc.framebufferLayout)->m_renderPass; + pipelineInfo.renderPass = framebufferLayoutImpl->m_renderPass; pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; pipelineInfo.pDynamicState = &dynamicStateInfo; diff --git a/tools/gfx/vulkan/vk-api.h b/tools/gfx/vulkan/vk-api.h index 72a6e73c8..7df51668f 100644 --- a/tools/gfx/vulkan/vk-api.h +++ b/tools/gfx/vulkan/vk-api.h @@ -98,6 +98,7 @@ namespace gfx { x(vkCmdCopyBufferToImage)\ x(vkCmdCopyImage) \ x(vkCmdCopyImageToBuffer) \ + x(vkCmdResolveImage) \ x(vkCmdPushConstants) \ x(vkCmdSetStencilReference) \ x(vkCmdWriteTimestamp) \ |
