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 <cwallez@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
parent
941a04cd43
commit
8e50ba19ba
|
@ -50,7 +50,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
D3D12_TEXTURE_COPY_LOCATION copyLocation;
|
D3D12_TEXTURE_COPY_LOCATION copyLocation;
|
||||||
copyLocation.pResource = texture.GetD3D12Resource();
|
copyLocation.pResource = texture.GetD3D12Resource();
|
||||||
copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||||
copyLocation.SubresourceIndex = texture.GetNumMipLevels() * slice + level;
|
copyLocation.SubresourceIndex = texture.GetSubresourceIndex(level, slice);
|
||||||
|
|
||||||
return copyLocation;
|
return copyLocation;
|
||||||
}
|
}
|
||||||
|
@ -346,6 +346,37 @@ namespace dawn_native { namespace d3d12 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResolveMultisampledRenderPass(ComPtr<ID3D12GraphicsCommandList> 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
|
} // anonymous namespace
|
||||||
|
|
||||||
CommandBuffer::CommandBuffer(Device* device, CommandEncoderBase* encoder)
|
CommandBuffer::CommandBuffer(Device* device, CommandEncoderBase* encoder)
|
||||||
|
@ -734,6 +765,12 @@ namespace dawn_native { namespace d3d12 {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::EndRenderPass: {
|
case Command::EndRenderPass: {
|
||||||
mCommands.NextCommand<EndRenderPassCmd>();
|
mCommands.NextCommand<EndRenderPassCmd>();
|
||||||
|
|
||||||
|
// 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;
|
return;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -351,7 +351,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
descriptorD3D12.RasterizerState.SlopeScaledDepthBias =
|
descriptorD3D12.RasterizerState.SlopeScaledDepthBias =
|
||||||
D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
|
D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
|
||||||
descriptorD3D12.RasterizerState.DepthClipEnable = TRUE;
|
descriptorD3D12.RasterizerState.DepthClipEnable = TRUE;
|
||||||
descriptorD3D12.RasterizerState.MultisampleEnable = FALSE;
|
descriptorD3D12.RasterizerState.MultisampleEnable = (GetSampleCount() > 1) ? TRUE : FALSE;
|
||||||
descriptorD3D12.RasterizerState.AntialiasedLineEnable = FALSE;
|
descriptorD3D12.RasterizerState.AntialiasedLineEnable = FALSE;
|
||||||
descriptorD3D12.RasterizerState.ForcedSampleCount = 0;
|
descriptorD3D12.RasterizerState.ForcedSampleCount = 0;
|
||||||
descriptorD3D12.RasterizerState.ConservativeRaster =
|
descriptorD3D12.RasterizerState.ConservativeRaster =
|
||||||
|
@ -376,7 +376,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
descriptorD3D12.SampleMask = UINT_MAX;
|
descriptorD3D12.SampleMask = UINT_MAX;
|
||||||
descriptorD3D12.PrimitiveTopologyType = D3D12PrimitiveTopologyType(GetPrimitiveTopology());
|
descriptorD3D12.PrimitiveTopologyType = D3D12PrimitiveTopologyType(GetPrimitiveTopology());
|
||||||
descriptorD3D12.SampleDesc.Count = 1;
|
descriptorD3D12.SampleDesc.Count = GetSampleCount();
|
||||||
|
descriptorD3D12.SampleDesc.Quality = 0;
|
||||||
|
|
||||||
ASSERT_SUCCESS(device->GetD3D12Device()->CreateGraphicsPipelineState(
|
ASSERT_SUCCESS(device->GetD3D12Device()->CreateGraphicsPipelineState(
|
||||||
&descriptorD3D12, IID_PPV_ARGS(&mPipelineState)));
|
&descriptorD3D12, IID_PPV_ARGS(&mPipelineState)));
|
||||||
|
|
|
@ -54,13 +54,19 @@ namespace dawn_native { namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_RESOURCE_FLAGS D3D12ResourceFlags(dawn::TextureUsageBit usage,
|
D3D12_RESOURCE_FLAGS D3D12ResourceFlags(dawn::TextureUsageBit usage,
|
||||||
dawn::TextureFormat format) {
|
dawn::TextureFormat format,
|
||||||
|
bool isMultisampledTexture) {
|
||||||
D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE;
|
D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
if (usage & dawn::TextureUsageBit::Storage) {
|
if (usage & dawn::TextureUsageBit::Storage) {
|
||||||
flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
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)) {
|
if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) {
|
||||||
flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -120,10 +126,12 @@ namespace dawn_native { namespace d3d12 {
|
||||||
resourceDescriptor.DepthOrArraySize = GetDepthOrArraySize();
|
resourceDescriptor.DepthOrArraySize = GetDepthOrArraySize();
|
||||||
resourceDescriptor.MipLevels = static_cast<UINT16>(GetNumMipLevels());
|
resourceDescriptor.MipLevels = static_cast<UINT16>(GetNumMipLevels());
|
||||||
resourceDescriptor.Format = D3D12TextureFormat(GetFormat());
|
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.SampleDesc.Quality = 0;
|
||||||
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||||
resourceDescriptor.Flags = D3D12ResourceFlags(GetUsage(), GetFormat());
|
resourceDescriptor.Flags =
|
||||||
|
D3D12ResourceFlags(GetUsage(), GetFormat(), IsMultisampledTexture());
|
||||||
|
|
||||||
mResource = ToBackend(GetDevice())
|
mResource = ToBackend(GetDevice())
|
||||||
->GetResourceAllocator()
|
->GetResourceAllocator()
|
||||||
|
@ -169,26 +177,32 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
dawn::TextureUsageBit usage) {
|
dawn::TextureUsageBit usage) {
|
||||||
|
TransitionUsageNow(commandList, D3D12TextureUsage(usage, GetFormat()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
|
D3D12_RESOURCE_STATES newState) {
|
||||||
// Avoid transitioning the texture when it isn't needed.
|
// Avoid transitioning the texture when it isn't needed.
|
||||||
// TODO(cwallez@chromium.org): Need some form of UAV barriers at some point.
|
// TODO(cwallez@chromium.org): Need some form of UAV barriers at some point.
|
||||||
if (usage == mLastUsage) {
|
if (mLastState == newState) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_RESOURCE_STATES lastState = D3D12TextureUsage(mLastUsage, GetFormat());
|
|
||||||
D3D12_RESOURCE_STATES newState = D3D12TextureUsage(usage, GetFormat());
|
|
||||||
|
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
D3D12_RESOURCE_BARRIER barrier;
|
||||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
barrier.Transition.pResource = mResourcePtr;
|
barrier.Transition.pResource = mResourcePtr;
|
||||||
barrier.Transition.StateBefore = lastState;
|
barrier.Transition.StateBefore = mLastState;
|
||||||
barrier.Transition.StateAfter = newState;
|
barrier.Transition.StateAfter = newState;
|
||||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
|
||||||
commandList->ResourceBarrier(1, &barrier);
|
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)
|
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_srv
|
||||||
// https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array_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 more texture view dimensions.
|
||||||
|
// TODO(jiawei.shao@intel.com): support creating SRV on multisampled textures.
|
||||||
switch (descriptor->dimension) {
|
switch (descriptor->dimension) {
|
||||||
case dawn::TextureViewDimension::e2D:
|
case dawn::TextureViewDimension::e2D:
|
||||||
case dawn::TextureViewDimension::e2DArray:
|
case dawn::TextureViewDimension::e2DArray:
|
||||||
|
@ -242,26 +257,43 @@ namespace dawn_native { namespace d3d12 {
|
||||||
ASSERT(GetTexture()->GetDimension() == dawn::TextureDimension::e2D);
|
ASSERT(GetTexture()->GetDimension() == dawn::TextureDimension::e2D);
|
||||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
|
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
|
||||||
rtvDesc.Format = GetD3D12Format();
|
rtvDesc.Format = GetD3D12Format();
|
||||||
// Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base array layer
|
if (GetTexture()->IsMultisampledTexture()) {
|
||||||
// and layer count in D3D12_TEX2D_RTV. For 2D texture views, we treat them as 1-layer 2D
|
ASSERT(GetTexture()->GetArrayLayers() == 1 && GetTexture()->GetNumMipLevels() == 1 &&
|
||||||
// array textures. (Just like how we treat SRVs)
|
GetBaseArrayLayer() == 0 && GetBaseMipLevel() == 0);
|
||||||
// https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_rtv
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
|
||||||
// https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_array_rtv
|
} else {
|
||||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
// Currently we always use D3D12_TEX2D_ARRAY_RTV because we cannot specify base array
|
||||||
rtvDesc.Texture2DArray.FirstArraySlice = GetBaseArrayLayer();
|
// layer and layer count in D3D12_TEX2D_RTV. For 2D texture views, we treat them as
|
||||||
rtvDesc.Texture2DArray.ArraySize = GetLayerCount();
|
// 1-layer 2D array textures. (Just like how we treat SRVs)
|
||||||
rtvDesc.Texture2DArray.MipSlice = GetBaseMipLevel();
|
// https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_tex2d_rtv
|
||||||
rtvDesc.Texture2DArray.PlaneSlice = 0;
|
// 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;
|
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 TextureView::GetDSVDescriptor() const {
|
||||||
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
|
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
|
||||||
dsvDesc.Format = ToBackend(GetTexture())->GetD3D12Format();
|
dsvDesc.Format = ToBackend(GetTexture())->GetD3D12Format();
|
||||||
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
|
|
||||||
dsvDesc.Texture2D.MipSlice = 0;
|
|
||||||
dsvDesc.Flags = D3D12_DSV_FLAG_NONE;
|
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;
|
return dsvDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,10 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
dawn::TextureUsageBit usage);
|
dawn::TextureUsageBit usage);
|
||||||
|
void TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||||
|
D3D12_RESOURCE_STATES newState);
|
||||||
|
|
||||||
|
uint32_t GetSubresourceIndex(uint32_t mipmapLevel, uint32_t arraySlice) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Dawn API
|
// Dawn API
|
||||||
|
@ -45,7 +49,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
ComPtr<ID3D12Resource> mResource = {};
|
ComPtr<ID3D12Resource> mResource = {};
|
||||||
ID3D12Resource* mResourcePtr = nullptr;
|
ID3D12Resource* mResourcePtr = nullptr;
|
||||||
dawn::TextureUsageBit mLastUsage = dawn::TextureUsageBit::None;
|
D3D12_RESOURCE_STATES mLastState = D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_COMMON;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextureView : public TextureViewBase {
|
class TextureView : public TextureViewBase {
|
||||||
|
|
|
@ -466,4 +466,4 @@ TEST_P(MultisampledRenderingTest, ResolveInto2DArrayTexture) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jiawei.shao@intel.com): enable multisampled rendering on all Dawn backends.
|
// TODO(jiawei.shao@intel.com): enable multisampled rendering on all Dawn backends.
|
||||||
DAWN_INSTANTIATE_TEST(MultisampledRenderingTest, OpenGLBackend);
|
DAWN_INSTANTIATE_TEST(MultisampledRenderingTest, D3D12Backend, OpenGLBackend);
|
||||||
|
|
Loading…
Reference in New Issue