D3D12: only lazy clear OutputAttachment textures with render target ops

Previously, lazy clearing always added DEPTH_STENCIL or RENDER_TARGET to
textures because we cleared using ClearDepthStencilView or
ClearRenderTargetView. Now, we're able to clear using copies.

This also allows textures to actually use the small resource heap
placement optimization. Doing so generates debug layer warnings when the
small alignment is first tried but rejected. This CL silences those
warnings.

Bug: dawn:145
Change-Id: Id385846536b337cddcfdadc5739561c7adc30c8c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/26840
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Austin Eng 2020-08-17 18:39:25 +00:00 committed by Commit Bot service account
parent 988f19e208
commit c0fd9d0945
6 changed files with 61 additions and 57 deletions

View File

@ -146,6 +146,11 @@ namespace dawn_native { namespace d3d12 {
// Remove after warning have been addressed
// https://crbug.com/dawn/421
D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_INCOMPATIBLE_RESOURCE_STATE,
// For small placed resource alignment, we first request the small alignment, which may
// get rejected and generate a debug error. Then, we request 0 to get the allowed
// allowed alignment.
D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDALIGNMENT,
};
// Create a retrieval filter with a deny list to suppress messages.

View File

@ -279,12 +279,15 @@ namespace dawn_native { namespace d3d12 {
resourceHeapKind, requestedResourceDescriptor.SampleDesc.Count,
requestedResourceDescriptor.Alignment);
// TODO(bryan.bernhart): Figure out how to compute the alignment without calling this
// twice.
D3D12_RESOURCE_ALLOCATION_INFO resourceInfo =
mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);
// If the requested resource alignment was rejected, let D3D tell us what the
// required alignment is for this resource.
if (resourceDescriptor.Alignment != resourceInfo.Alignment) {
if (resourceDescriptor.Alignment != 0 &&
resourceDescriptor.Alignment != resourceInfo.Alignment) {
resourceDescriptor.Alignment = 0;
resourceInfo =
mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);

View File

@ -79,13 +79,7 @@ namespace dawn_native { namespace d3d12 {
// 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
// Currently all textures are zero-initialized via the render-target path so always add
// the render target flag, except for compressed textures for which the render-target
// flag is invalid.
// TODO(natlee@microsoft.com, jiawei.shao@intel.com): do not require render target for
// lazy clearing.
if ((usage & wgpu::TextureUsage::OutputAttachment) || isMultisampledTexture ||
!format.isCompressed) {
if ((usage & wgpu::TextureUsage::OutputAttachment) != 0 || isMultisampledTexture) {
if (format.HasDepthOrStencil()) {
flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
} else {
@ -855,7 +849,7 @@ 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 (GetFormat().isRenderable) {
if ((GetUsage() & wgpu::TextureUsage::OutputAttachment) != 0) {
if (GetFormat().HasDepthOrStencil()) {
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_DEPTH_WRITE, range);
@ -935,60 +929,63 @@ namespace dawn_native { namespace d3d12 {
}
}
} else {
// TODO(natlee@microsoft.com): test compressed textures are cleared
// create temp buffer with clear color to copy to the texture image
uint32_t bytesPerRow =
Align((GetWidth() / GetFormat().blockWidth) * GetFormat().blockByteSize,
kTextureBytesPerRowAlignment);
uint64_t bufferSize64 = bytesPerRow * (GetHeight() / GetFormat().blockHeight);
if (bufferSize64 > std::numeric_limits<uint32_t>::max()) {
return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer.");
}
uint32_t bufferSize = static_cast<uint32_t>(bufferSize64);
DynamicUploader* uploader = device->GetDynamicUploader();
UploadHandle uploadHandle;
DAWN_TRY_ASSIGN(uploadHandle,
uploader->Allocate(bufferSize, device->GetPendingCommandSerial()));
memset(uploadHandle.mappedBuffer, clearColor, bufferSize);
TrackUsageAndTransitionNow(commandContext, D3D12_RESOURCE_STATE_COPY_DEST, range);
ASSERT(range.aspects == Aspect::Color);
for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
++level) {
// compute d3d12 texture copy locations for texture and buffer
Extent3D copySize = GetMipLevelVirtualSize(level);
for (Aspect aspect : IterateEnumMask(range.aspects)) {
const TexelBlockInfo& blockInfo = GetFormat().GetTexelBlockInfo(aspect);
uint32_t rowsPerImage = GetHeight();
Texture2DCopySplit copySplit =
ComputeTextureCopySplit({0, 0, 0}, copySize, GetFormat(),
uploadHandle.startOffset, bytesPerRow, rowsPerImage);
uint32_t bytesPerRow =
Align((GetWidth() / blockInfo.blockWidth) * blockInfo.blockByteSize,
kTextureBytesPerRowAlignment);
uint64_t bufferSize64 = bytesPerRow * (GetHeight() / blockInfo.blockHeight);
if (bufferSize64 > std::numeric_limits<uint32_t>::max()) {
return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer.");
}
uint32_t bufferSize = static_cast<uint32_t>(bufferSize64);
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;
}
DynamicUploader* uploader = device->GetDynamicUploader();
UploadHandle uploadHandle;
DAWN_TRY_ASSIGN(uploadHandle,
uploader->Allocate(bufferSize, device->GetPendingCommandSerial()));
memset(uploadHandle.mappedBuffer, clearColor, bufferSize);
D3D12_TEXTURE_COPY_LOCATION textureLocation =
ComputeTextureCopyLocationForTexture(this, level, layer, Aspect::Color);
for (uint32_t i = 0; i < copySplit.count; ++i) {
Texture2DCopySplit::CopyInfo& info = copySplit.copies[i];
for (uint32_t level = range.baseMipLevel;
level < range.baseMipLevel + range.levelCount; ++level) {
// compute d3d12 texture copy locations for texture and buffer
Extent3D copySize = GetMipLevelVirtualSize(level);
D3D12_TEXTURE_COPY_LOCATION bufferLocation =
ComputeBufferLocationForCopyTextureRegion(
this, ToBackend(uploadHandle.stagingBuffer)->GetResource(),
info.bufferSize, copySplit.offset, bytesPerRow, Aspect::Color);
D3D12_BOX sourceRegion =
ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize);
uint32_t rowsPerImage = GetHeight();
Texture2DCopySplit copySplit = ComputeTextureCopySplit(
{0, 0, 0}, copySize, blockInfo, uploadHandle.startOffset, bytesPerRow,
rowsPerImage);
// copy the buffer filled with clear color to the texture
commandList->CopyTextureRegion(&textureLocation, info.textureOffset.x,
info.textureOffset.y, info.textureOffset.z,
&bufferLocation, &sourceRegion);
for (uint32_t layer = range.baseArrayLayer;
layer < range.baseArrayLayer + range.layerCount; ++layer) {
if (clearValue == TextureBase::ClearValue::Zero &&
IsSubresourceContentInitialized(
SubresourceRange::SingleMipAndLayer(level, layer, aspect))) {
// Skip lazy clears if already initialized.
continue;
}
D3D12_TEXTURE_COPY_LOCATION textureLocation =
ComputeTextureCopyLocationForTexture(this, level, layer, aspect);
for (uint32_t i = 0; i < copySplit.count; ++i) {
Texture2DCopySplit::CopyInfo& info = copySplit.copies[i];
D3D12_TEXTURE_COPY_LOCATION bufferLocation =
ComputeBufferLocationForCopyTextureRegion(
this, ToBackend(uploadHandle.stagingBuffer)->GetResource(),
info.bufferSize, copySplit.offset, bytesPerRow, aspect);
D3D12_BOX sourceRegion =
ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize);
// copy the buffer filled with clear color to the texture
commandList->CopyTextureRegion(
&textureLocation, info.textureOffset.x, info.textureOffset.y,
info.textureOffset.z, &bufferLocation, &sourceRegion);
}
}
}
}

View File

@ -316,7 +316,6 @@ namespace dawn_native { namespace opengl {
} else {
ASSERT(range.aspects == Aspect::Color);
// TODO(natlee@microsoft.com): test compressed textures are cleared
// create temp buffer with clear color to copy to the texture image
ASSERT(kTextureBytesPerRowAlignment % GetFormat().blockByteSize == 0);
uint32_t bytesPerRow =

View File

@ -937,7 +937,6 @@ namespace dawn_native { namespace vulkan {
}
}
} else {
// TODO(natlee@microsoft.com): test compressed textures are cleared
// create temp buffer with clear color to copy to the texture image
uint32_t bytesPerRow =
Align((GetWidth() / GetFormat().blockWidth) * GetFormat().blockByteSize,

View File

@ -30,6 +30,7 @@
} \
} while (0)
// TODO(natlee@microsoft.com): test compressed textures are cleared
class TextureZeroInitTest : public DawnTest {
protected:
void SetUp() override {