Implement initialization of multisampled textures

Metal needs RenderTarget usage to be added to the texture
allocation so the clear can be done using a render pass.

Already working for GL which does not have usage flags on
creation.
Also working on Vulkan which does not need a render pass.
We use vkCmdClearColorImage.
D3D12 also needs a render pass to clear multisampled textures,
but it already requires multisampled
textures to be created with RenderTarget flags.

To test the behavior, NonzeroTextureCreation tests are
expanded, and the ExpectSampledDepthData helper is factored
into a more general ExpectSampledFloatData helper.

Fixes: dawn:794
Change-Id: If0f9f26f3c58b4292c85265aa7ff330e9931ddae
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/55604
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Austin Eng
2021-06-24 02:01:46 +00:00
committed by Dawn LUCI CQ
parent 2a57db73cb
commit 75c5067ed1
8 changed files with 305 additions and 136 deletions

View File

@@ -471,6 +471,9 @@ namespace dawn_native { namespace d3d12 {
mDxgiKeyedMutex = std::move(dxgiKeyedMutex);
mSwapChainTexture = isSwapChainTexture;
D3D12_RESOURCE_DESC desc = d3d12Texture->GetDesc();
mD3D12ResourceFlags = desc.Flags;
AllocationInfo info;
info.mMethod = AllocationMethod::kExternal;
// When creating the ResourceHeapAllocation, the resource heap is set to nullptr because the
@@ -507,6 +510,7 @@ namespace dawn_native { namespace d3d12 {
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resourceDescriptor.Flags =
D3D12ResourceFlags(GetUsage(), GetFormat(), IsMultisampledTexture());
mD3D12ResourceFlags = resourceDescriptor.Flags;
DAWN_TRY_ASSIGN(mResourceAllocation,
ToBackend(GetDevice())
@@ -879,82 +883,80 @@ namespace dawn_native { namespace d3d12 {
uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1;
float fClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.f : 1.f;
if ((GetUsage() & wgpu::TextureUsage::RenderAttachment) != 0) {
if (GetFormat().HasDepthOrStencil()) {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE, range);
if ((mD3D12ResourceFlags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) != 0) {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE, range);
for (uint32_t level = range.baseMipLevel;
level < range.baseMipLevel + range.levelCount; ++level) {
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
// Iterate the aspects individually to determine which clear flags to use.
D3D12_CLEAR_FLAGS clearFlags = {};
for (Aspect aspect : IterateEnumMask(range.aspects)) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer, aspect))) {
// Skip lazy clears if already initialized.
continue;
}
switch (aspect) {
case Aspect::Depth:
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
break;
case Aspect::Stencil:
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
break;
default:
UNREACHABLE();
}
}
if (clearFlags == 0) {
continue;
}
CPUDescriptorHeapAllocation dsvHandle;
DAWN_TRY_ASSIGN(dsvHandle, device->GetDepthStencilViewAllocator()
->AllocateTransientCPUDescriptors());
const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor =
dsvHandle.GetBaseDescriptor();
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(level, layer, 1);
device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(),
&dsvDesc, baseDescriptor);
commandList->ClearDepthStencilView(baseDescriptor, clearFlags, fClearColor,
clearColor, 0, nullptr);
}
}
} else {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_RENDER_TARGET,
range);
const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor,
fClearColor};
ASSERT(range.aspects == Aspect::Color);
for (uint32_t level = range.baseMipLevel;
level < range.baseMipLevel + range.levelCount; ++level) {
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
++level) {
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
// Iterate the aspects individually to determine which clear flags to use.
D3D12_CLEAR_FLAGS clearFlags = {};
for (Aspect aspect : IterateEnumMask(range.aspects)) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
SubresourceRange::SingleMipAndLayer(level, layer, aspect))) {
// Skip lazy clears if already initialized.
continue;
}
CPUDescriptorHeapAllocation rtvHeap;
DAWN_TRY_ASSIGN(rtvHeap, device->GetRenderTargetViewAllocator()
->AllocateTransientCPUDescriptors());
const D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetBaseDescriptor();
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = GetRTVDescriptor(level, layer, 1);
device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(),
&rtvDesc, rtvHandle);
commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr);
switch (aspect) {
case Aspect::Depth:
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
break;
case Aspect::Stencil:
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
break;
default:
UNREACHABLE();
}
}
if (clearFlags == 0) {
continue;
}
CPUDescriptorHeapAllocation dsvHandle;
DAWN_TRY_ASSIGN(
dsvHandle,
device->GetDepthStencilViewAllocator()->AllocateTransientCPUDescriptors());
const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor =
dsvHandle.GetBaseDescriptor();
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(level, layer, 1);
device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(), &dsvDesc,
baseDescriptor);
commandList->ClearDepthStencilView(baseDescriptor, clearFlags, fClearColor,
clearColor, 0, nullptr);
}
}
} else if ((mD3D12ResourceFlags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) != 0) {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_RENDER_TARGET, range);
const float clearColorRGBA[4] = {fClearColor, fClearColor, fClearColor, fClearColor};
ASSERT(range.aspects == Aspect::Color);
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
++level) {
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer, Aspect::Color))) {
// Skip lazy clears if already initialized.
continue;
}
CPUDescriptorHeapAllocation rtvHeap;
DAWN_TRY_ASSIGN(
rtvHeap,
device->GetRenderTargetViewAllocator()->AllocateTransientCPUDescriptors());
const D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetBaseDescriptor();
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = GetRTVDescriptor(level, layer, 1);
device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(), &rtvDesc,
rtvHandle);
commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr);
}
}
} else {

View File

@@ -123,6 +123,7 @@ namespace dawn_native { namespace d3d12 {
ResourceHeapAllocation mResourceAllocation;
bool mSwapChainTexture = false;
D3D12_RESOURCE_FLAGS mD3D12ResourceFlags;
ExternalMutexSerial mAcquireMutexKey = ExternalMutexSerial(0);
ExternalMutexSerial mReleaseMutexKey = ExternalMutexSerial(0);

View File

@@ -63,6 +63,7 @@ namespace dawn_native { namespace metal {
TextureBase::ClearValue clearValue);
NSPRef<id<MTLTexture>> mMtlTexture;
MTLTextureUsage mMtlUsage;
};
class TextureView final : public TextureViewBase {

View File

@@ -34,7 +34,9 @@ namespace dawn_native { namespace metal {
return usage & kUsageNeedsTextureView;
}
MTLTextureUsage MetalTextureUsage(const Format& format, wgpu::TextureUsage usage) {
MTLTextureUsage MetalTextureUsage(const Format& format,
wgpu::TextureUsage usage,
uint32_t sampleCount) {
MTLTextureUsage result = MTLTextureUsageUnknown; // This is 0
if (usage & (wgpu::TextureUsage::Storage)) {
@@ -53,7 +55,8 @@ namespace dawn_native { namespace metal {
}
}
if (usage & (wgpu::TextureUsage::RenderAttachment)) {
// MTLTextureUsageRenderTarget is needed to clear multisample textures.
if (usage & (wgpu::TextureUsage::RenderAttachment) || sampleCount > 1) {
result |= MTLTextureUsageRenderTarget;
}
@@ -310,7 +313,7 @@ namespace dawn_native { namespace metal {
// TODO: add MTLTextureUsagePixelFormatView when needed when we support format
// reinterpretation.
mtlDesc.usage = MetalTextureUsage(device->GetValidInternalFormat(descriptor->format),
descriptor->usage);
descriptor->usage, descriptor->sampleCount);
mtlDesc.pixelFormat = MetalPixelFormat(descriptor->format);
mtlDesc.mipmapLevelCount = descriptor->mipLevelCount;
mtlDesc.storageMode = MTLStorageModePrivate;
@@ -357,6 +360,7 @@ namespace dawn_native { namespace metal {
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
mMtlTexture =
AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()]);
mMtlUsage = [*mtlDesc usage];
if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
device->ConsumedError(ClearTexture(device->GetPendingCommandContext(),
@@ -370,6 +374,8 @@ namespace dawn_native { namespace metal {
NSPRef<id<MTLTexture>> mtlTexture)
: TextureBase(device, descriptor, TextureState::OwnedInternal),
mMtlTexture(std::move(mtlTexture)) {
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
mMtlUsage = [*mtlDesc usage];
}
Texture::Texture(Device* device,
@@ -386,6 +392,7 @@ namespace dawn_native { namespace metal {
mMtlTexture = AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()
iosurface:ioSurface
plane:plane]);
mMtlUsage = [*mtlDesc usage];
SetIsSubresourceContentInitialized(descriptor->isInitialized, GetAllSubresources());
}
@@ -410,7 +417,7 @@ namespace dawn_native { namespace metal {
const uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1;
const double dClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.0 : 1.0;
if ((GetUsage() & wgpu::TextureUsage::RenderAttachment) != 0) {
if ((mMtlUsage & MTLTextureUsageRenderTarget) != 0) {
ASSERT(GetFormat().isRenderable);
// End the blit encoder if it is open.