From 8e50ba19ba2eba83cbe89a945388ec40393001e1 Mon Sep 17 00:00:00 2001 From: Jiawei Shao Date: Tue, 2 Apr 2019 07:42:09 +0000 Subject: [PATCH] Support multisampled rendering on D3D12 This patch adds the basic support of multisampled rendering on D3D12 backends and enables the related end2end test on D3D12 backends. D3D12 render pass is not used in this patch. We plan to make use of it in the future. BUG=dawn:56 TEST=dawn_end2end_tests Change-Id: I63759431654ec0abe9d21157f679d4c971cd92a8 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/6200 Reviewed-by: Corentin Wallez Reviewed-by: Kai Ninomiya Commit-Queue: Jiawei Shao --- src/dawn_native/d3d12/CommandBufferD3D12.cpp | 39 +++++++++- src/dawn_native/d3d12/RenderPipelineD3D12.cpp | 5 +- src/dawn_native/d3d12/TextureD3D12.cpp | 78 +++++++++++++------ src/dawn_native/d3d12/TextureD3D12.h | 6 +- .../end2end/MultisampledRenderingTests.cpp | 2 +- 5 files changed, 102 insertions(+), 28 deletions(-) diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp index 95090493de..25437cd4f6 100644 --- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp +++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp @@ -50,7 +50,7 @@ namespace dawn_native { namespace d3d12 { D3D12_TEXTURE_COPY_LOCATION copyLocation; copyLocation.pResource = texture.GetD3D12Resource(); copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - copyLocation.SubresourceIndex = texture.GetNumMipLevels() * slice + level; + copyLocation.SubresourceIndex = texture.GetSubresourceIndex(level, slice); return copyLocation; } @@ -346,6 +346,37 @@ namespace dawn_native { namespace d3d12 { } } + void ResolveMultisampledRenderPass(ComPtr commandList, + BeginRenderPassCmd* renderPass) { + ASSERT(renderPass != nullptr); + + for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) { + TextureViewBase* resolveTarget = + renderPass->colorAttachments[i].resolveTarget.Get(); + if (resolveTarget == nullptr) { + continue; + } + + Texture* colorTexture = + ToBackend(renderPass->colorAttachments[i].view->GetTexture()); + Texture* resolveTexture = ToBackend(resolveTarget->GetTexture()); + + // Transition the usages of the color attachment and resolve target. + colorTexture->TransitionUsageNow(commandList, D3D12_RESOURCE_STATE_RESOLVE_SOURCE); + resolveTexture->TransitionUsageNow(commandList, D3D12_RESOURCE_STATE_RESOLVE_DEST); + + // Do MSAA resolve with ResolveSubResource(). + ID3D12Resource* colorTextureHandle = colorTexture->GetD3D12Resource(); + ID3D12Resource* resolveTextureHandle = resolveTexture->GetD3D12Resource(); + const uint32_t resolveTextureSubresourceIndex = resolveTexture->GetSubresourceIndex( + resolveTarget->GetBaseMipLevel(), resolveTarget->GetBaseArrayLayer()); + constexpr uint32_t kColorTextureSubresourceIndex = 0; + commandList->ResolveSubresource( + resolveTextureHandle, resolveTextureSubresourceIndex, colorTextureHandle, + kColorTextureSubresourceIndex, colorTexture->GetD3D12Format()); + } + } + } // anonymous namespace CommandBuffer::CommandBuffer(Device* device, CommandEncoderBase* encoder) @@ -734,6 +765,12 @@ namespace dawn_native { namespace d3d12 { switch (type) { case Command::EndRenderPass: { mCommands.NextCommand(); + + // TODO(brandon1.jones@intel.com): avoid calling this function and enable MSAA + // resolve in D3D12 render pass on the platforms that support this feature. + if (renderPass->sampleCount > 1) { + ResolveMultisampledRenderPass(commandList, renderPass); + } return; } break; diff --git a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp index 0b0aa06f9a..2cc719bfa1 100644 --- a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp +++ b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp @@ -351,7 +351,7 @@ namespace dawn_native { namespace d3d12 { descriptorD3D12.RasterizerState.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; descriptorD3D12.RasterizerState.DepthClipEnable = TRUE; - descriptorD3D12.RasterizerState.MultisampleEnable = FALSE; + descriptorD3D12.RasterizerState.MultisampleEnable = (GetSampleCount() > 1) ? TRUE : FALSE; descriptorD3D12.RasterizerState.AntialiasedLineEnable = FALSE; descriptorD3D12.RasterizerState.ForcedSampleCount = 0; descriptorD3D12.RasterizerState.ConservativeRaster = @@ -376,7 +376,8 @@ namespace dawn_native { namespace d3d12 { descriptorD3D12.SampleMask = UINT_MAX; descriptorD3D12.PrimitiveTopologyType = D3D12PrimitiveTopologyType(GetPrimitiveTopology()); - descriptorD3D12.SampleDesc.Count = 1; + descriptorD3D12.SampleDesc.Count = GetSampleCount(); + descriptorD3D12.SampleDesc.Quality = 0; ASSERT_SUCCESS(device->GetD3D12Device()->CreateGraphicsPipelineState( &descriptorD3D12, IID_PPV_ARGS(&mPipelineState))); diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp index 63a0533d97..5e9a63b765 100644 --- a/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/src/dawn_native/d3d12/TextureD3D12.cpp @@ -54,13 +54,19 @@ namespace dawn_native { namespace d3d12 { } D3D12_RESOURCE_FLAGS D3D12ResourceFlags(dawn::TextureUsageBit usage, - dawn::TextureFormat format) { + dawn::TextureFormat format, + bool isMultisampledTexture) { D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE; if (usage & dawn::TextureUsageBit::Storage) { flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } - if (usage & dawn::TextureUsageBit::OutputAttachment) { + + // A multisampled resource must have either D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET or + // D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL set in D3D12_RESOURCE_DESC::Flags. + // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_resource + // _desc + if ((usage & dawn::TextureUsageBit::OutputAttachment) || isMultisampledTexture) { if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) { flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; } else { @@ -120,10 +126,12 @@ namespace dawn_native { namespace d3d12 { resourceDescriptor.DepthOrArraySize = GetDepthOrArraySize(); resourceDescriptor.MipLevels = static_cast(GetNumMipLevels()); resourceDescriptor.Format = D3D12TextureFormat(GetFormat()); - resourceDescriptor.SampleDesc.Count = 1; + resourceDescriptor.SampleDesc.Count = descriptor->sampleCount; + // TODO(bryan.bernhart@intel.com): investigate how to specify standard MSAA sample pattern. resourceDescriptor.SampleDesc.Quality = 0; resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - resourceDescriptor.Flags = D3D12ResourceFlags(GetUsage(), GetFormat()); + resourceDescriptor.Flags = + D3D12ResourceFlags(GetUsage(), GetFormat(), IsMultisampledTexture()); mResource = ToBackend(GetDevice()) ->GetResourceAllocator() @@ -169,26 +177,32 @@ namespace dawn_native { namespace d3d12 { void Texture::TransitionUsageNow(ComPtr commandList, dawn::TextureUsageBit usage) { + TransitionUsageNow(commandList, D3D12TextureUsage(usage, GetFormat())); + } + + void Texture::TransitionUsageNow(ComPtr commandList, + D3D12_RESOURCE_STATES newState) { // Avoid transitioning the texture when it isn't needed. // TODO(cwallez@chromium.org): Need some form of UAV barriers at some point. - if (usage == mLastUsage) { + if (mLastState == newState) { return; } - D3D12_RESOURCE_STATES lastState = D3D12TextureUsage(mLastUsage, GetFormat()); - D3D12_RESOURCE_STATES newState = D3D12TextureUsage(usage, GetFormat()); - D3D12_RESOURCE_BARRIER barrier; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = mResourcePtr; - barrier.Transition.StateBefore = lastState; + barrier.Transition.StateBefore = mLastState; barrier.Transition.StateAfter = newState; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; commandList->ResourceBarrier(1, &barrier); - mLastUsage = usage; + mLastState = newState; + } + + uint32_t Texture::GetSubresourceIndex(uint32_t mipmapLevel, uint32_t arraySlice) const { + return GetNumMipLevels() * arraySlice + mipmapLevel; } TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor) @@ -202,6 +216,7 @@ namespace dawn_native { namespace d3d12 { // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_srv // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array_srv // TODO(jiawei.shao@intel.com): support more texture view dimensions. + // TODO(jiawei.shao@intel.com): support creating SRV on multisampled textures. switch (descriptor->dimension) { case dawn::TextureViewDimension::e2D: case dawn::TextureViewDimension::e2DArray: @@ -242,26 +257,43 @@ namespace dawn_native { namespace d3d12 { ASSERT(GetTexture()->GetDimension() == dawn::TextureDimension::e2D); D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = GetD3D12Format(); - // Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base array layer - // and layer count in D3D12_TEX2D_RTV. For 2D texture views, we treat them as 1-layer 2D - // array textures. (Just like how we treat SRVs) - // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_rtv - // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array_rtv - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.FirstArraySlice = GetBaseArrayLayer(); - rtvDesc.Texture2DArray.ArraySize = GetLayerCount(); - rtvDesc.Texture2DArray.MipSlice = GetBaseMipLevel(); - rtvDesc.Texture2DArray.PlaneSlice = 0; + if (GetTexture()->IsMultisampledTexture()) { + ASSERT(GetTexture()->GetArrayLayers() == 1 && GetTexture()->GetNumMipLevels() == 1 && + GetBaseArrayLayer() == 0 && GetBaseMipLevel() == 0); + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; + } else { + // Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base array + // layer and layer count in D3D12_TEX2D_RTV. For 2D texture views, we treat them as + // 1-layer 2D array textures. (Just like how we treat SRVs) + // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_rtv + // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array + // _rtv + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.FirstArraySlice = GetBaseArrayLayer(); + rtvDesc.Texture2DArray.ArraySize = GetLayerCount(); + rtvDesc.Texture2DArray.MipSlice = GetBaseMipLevel(); + rtvDesc.Texture2DArray.PlaneSlice = 0; + } + return rtvDesc; } - // TODO(jiawei.shao@intel.com): support rendering into a layer of a texture. D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor() const { D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; dsvDesc.Format = ToBackend(GetTexture())->GetD3D12Format(); - dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = 0; dsvDesc.Flags = D3D12_DSV_FLAG_NONE; + + // TODO(jiawei.shao@intel.com): support rendering into a layer of a texture. + ASSERT(GetTexture()->GetArrayLayers() == 1 && GetTexture()->GetNumMipLevels() == 1 && + GetBaseArrayLayer() == 0 && GetBaseMipLevel() == 0); + + if (GetTexture()->IsMultisampledTexture()) { + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS; + } else { + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = 0; + } + return dsvDesc; } diff --git a/src/dawn_native/d3d12/TextureD3D12.h b/src/dawn_native/d3d12/TextureD3D12.h index 51676126a5..33b6be35bd 100644 --- a/src/dawn_native/d3d12/TextureD3D12.h +++ b/src/dawn_native/d3d12/TextureD3D12.h @@ -36,6 +36,10 @@ namespace dawn_native { namespace d3d12 { void TransitionUsageNow(ComPtr commandList, dawn::TextureUsageBit usage); + void TransitionUsageNow(ComPtr commandList, + D3D12_RESOURCE_STATES newState); + + uint32_t GetSubresourceIndex(uint32_t mipmapLevel, uint32_t arraySlice) const; private: // Dawn API @@ -45,7 +49,7 @@ namespace dawn_native { namespace d3d12 { ComPtr mResource = {}; ID3D12Resource* mResourcePtr = nullptr; - dawn::TextureUsageBit mLastUsage = dawn::TextureUsageBit::None; + D3D12_RESOURCE_STATES mLastState = D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_COMMON; }; class TextureView : public TextureViewBase { diff --git a/src/tests/end2end/MultisampledRenderingTests.cpp b/src/tests/end2end/MultisampledRenderingTests.cpp index e22b561176..e1ceb83c79 100644 --- a/src/tests/end2end/MultisampledRenderingTests.cpp +++ b/src/tests/end2end/MultisampledRenderingTests.cpp @@ -466,4 +466,4 @@ TEST_P(MultisampledRenderingTest, ResolveInto2DArrayTexture) { } // TODO(jiawei.shao@intel.com): enable multisampled rendering on all Dawn backends. -DAWN_INSTANTIATE_TEST(MultisampledRenderingTest, OpenGLBackend); +DAWN_INSTANTIATE_TEST(MultisampledRenderingTest, D3D12Backend, OpenGLBackend);