Support BC5 formats on D3D12

This patch adds the support of BC5 formats on D3D12 backend. On D3D12,
the "rowPitch" refers to the number of bytes in a row of blocks (which
covers up to 4 scanlines at once) for the textures in BC formats.

This patch also adds the related end2end tests for four typical cases of
B2T and T2B copies on D3D12:
(1) copyBytesPerRowPitch + byteOffsetPerRowPitch <= rowPitch and
    texelOffset.y == 0
(2) copyBytesPerRowPitch + byteOffsetPerRowPitch <= rowPitch and
    texelOffset.y > 0
(3) copyBytesPerRowPitch + byteOffsetPerRowPitch > rowPitch
(4) texelOffset.z > 0

BUG=dawn:42
TEST=dawn_end2end_tests

Change-Id: If27ab3e56596e25c1c5be787ca021c0748021a46
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/8541
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Jiawei Shao
2019-07-05 08:06:30 +00:00
committed by Commit Bot service account
parent 3789858479
commit 3392b200c6
6 changed files with 236 additions and 66 deletions

View File

@@ -521,9 +521,8 @@ namespace dawn_native { namespace d3d12 {
texture->TransitionUsageNow(commandList, dawn::TextureUsageBit::TransferDst);
auto copySplit = ComputeTextureCopySplit(
copy->destination.origin, copy->copySize,
texture->GetFormat().blockByteSize, copy->source.offset,
copy->source.rowPitch, copy->source.imageHeight);
copy->destination.origin, copy->copySize, texture->GetFormat(),
copy->source.offset, copy->source.rowPitch, copy->source.imageHeight);
D3D12_TEXTURE_COPY_LOCATION textureLocation =
CreateTextureCopyLocationForTexture(*texture, copy->destination.level,
@@ -568,7 +567,7 @@ namespace dawn_native { namespace d3d12 {
buffer->TransitionUsageNow(commandList, dawn::BufferUsageBit::TransferDst);
auto copySplit = ComputeTextureCopySplit(
copy->source.origin, copy->copySize, texture->GetFormat().blockByteSize,
copy->source.origin, copy->copySize, texture->GetFormat(),
copy->destination.offset, copy->destination.rowPitch,
copy->destination.imageHeight);

View File

@@ -20,31 +20,29 @@
namespace dawn_native { namespace d3d12 {
namespace {
void ComputeTexelOffsets(uint32_t offset,
uint32_t rowPitch,
uint32_t slicePitch,
uint32_t texelSize,
Origin3D* texelOffset) {
Origin3D ComputeTexelOffsets(Format format,
uint32_t offset,
uint32_t rowPitch,
uint32_t slicePitch) {
uint32_t byteOffsetX = offset % rowPitch;
offset -= byteOffsetX;
uint32_t byteOffsetY = offset % slicePitch;
uint32_t byteOffsetZ = offset - byteOffsetY;
texelOffset->x = byteOffsetX / texelSize;
texelOffset->y = byteOffsetY / rowPitch;
texelOffset->z = byteOffsetZ / slicePitch;
return {byteOffsetX / format.blockByteSize * format.blockWidth,
byteOffsetY / rowPitch * format.blockHeight, byteOffsetZ / slicePitch};
}
} // namespace
TextureCopySplit ComputeTextureCopySplit(Origin3D origin,
Extent3D copySize,
uint32_t texelSize,
Format format,
uint64_t offset,
uint32_t rowPitch,
uint32_t imageHeight) {
TextureCopySplit copy;
ASSERT(rowPitch % texelSize == 0);
ASSERT(rowPitch % format.blockByteSize == 0);
uint64_t alignedOffset =
offset & ~static_cast<uint64_t>(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1);
@@ -70,13 +68,13 @@ namespace dawn_native { namespace d3d12 {
ASSERT(alignedOffset < offset);
ASSERT(offset - alignedOffset < D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
Origin3D texelOffset;
ComputeTexelOffsets(static_cast<uint32_t>(offset - alignedOffset), rowPitch,
rowPitch * imageHeight, texelSize, &texelOffset);
uint32_t slicePitch = rowPitch * (imageHeight / format.blockHeight);
Origin3D texelOffset = ComputeTexelOffsets(
format, static_cast<uint32_t>(offset - alignedOffset), rowPitch, slicePitch);
uint32_t rowPitchInTexels = rowPitch / texelSize;
if (copySize.width + texelOffset.x <= rowPitchInTexels) {
uint32_t copyBytesPerRowPitch = copySize.width / format.blockWidth * format.blockByteSize;
uint32_t byteOffsetInRowPitch = texelOffset.x / format.blockWidth * format.blockByteSize;
if (copyBytesPerRowPitch + byteOffsetInRowPitch <= rowPitch) {
// The region's rows fit inside the row pitch. In this case, extend the width of the
// PlacedFootprint and copy the buffer with an offset location
// |<--------------- row pitch --------------->|
@@ -152,13 +150,14 @@ namespace dawn_native { namespace d3d12 {
copy.copies[0].textureOffset = origin;
ASSERT(rowPitchInTexels > texelOffset.x);
copy.copies[0].copySize.width = rowPitchInTexels - texelOffset.x;
ASSERT(rowPitch > byteOffsetInRowPitch);
uint32_t texelsPerRow = rowPitch / format.blockByteSize * format.blockWidth;
copy.copies[0].copySize.width = texelsPerRow - texelOffset.x;
copy.copies[0].copySize.height = copySize.height;
copy.copies[0].copySize.depth = copySize.depth;
copy.copies[0].bufferOffset = texelOffset;
copy.copies[0].bufferSize.width = rowPitchInTexels;
copy.copies[0].bufferSize.width = texelsPerRow;
copy.copies[0].bufferSize.height = imageHeight + texelOffset.y;
copy.copies[0].bufferSize.depth = copySize.depth + texelOffset.z;
@@ -172,10 +171,10 @@ namespace dawn_native { namespace d3d12 {
copy.copies[1].copySize.depth = copySize.depth;
copy.copies[1].bufferOffset.x = 0;
copy.copies[1].bufferOffset.y = texelOffset.y + 1;
copy.copies[1].bufferOffset.y = texelOffset.y + format.blockHeight;
copy.copies[1].bufferOffset.z = texelOffset.z;
copy.copies[1].bufferSize.width = copy.copies[1].copySize.width;
copy.copies[1].bufferSize.height = imageHeight + texelOffset.y + 1;
copy.copies[1].bufferSize.height = imageHeight + texelOffset.y + format.blockHeight;
copy.copies[1].bufferSize.depth = copySize.depth + texelOffset.z;
return copy;

View File

@@ -15,6 +15,7 @@
#ifndef DAWNNATIVE_D3D12_TEXTURECOPYSPLITTER_H_
#define DAWNNATIVE_D3D12_TEXTURECOPYSPLITTER_H_
#include "dawn_native/Texture.h"
#include "dawn_native/dawn_platform.h"
#include <array>
@@ -39,7 +40,7 @@ namespace dawn_native { namespace d3d12 {
TextureCopySplit ComputeTextureCopySplit(Origin3D origin,
Extent3D copySize,
uint32_t texelSize,
Format format,
uint64_t offset,
uint32_t rowPitch,
uint32_t imageHeight);

View File

@@ -64,20 +64,19 @@ 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
if ((usage & dawn::TextureUsageBit::OutputAttachment) || isMultisampledTexture) {
// 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 & dawn::TextureUsageBit::OutputAttachment) || isMultisampledTexture ||
!format.isCompressed) {
if (format.HasDepthOrStencil()) {
flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
} else {
flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
}
} else if ((usage & dawn::TextureUsageBit::TransferDst) ||
(usage & dawn::TextureUsageBit::TransferSrc)) {
// if texture is used as copy source or destination, it may need to be
// cleared/initialized, which requires it to be a render target
// TODO(natlee@microsoft.com): optimize texture clearing without render target
flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
}
ASSERT(!(flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) ||
@@ -114,6 +113,13 @@ namespace dawn_native { namespace d3d12 {
return DXGI_FORMAT_B8G8R8A8_UNORM;
case dawn::TextureFormat::Depth24PlusStencil8:
return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
// TODO(jiawei.shao@intel.com): support all BC formats
case dawn::TextureFormat::BC5RGSnorm:
return DXGI_FORMAT_BC5_SNORM;
case dawn::TextureFormat::BC5RGUnorm:
return DXGI_FORMAT_BC5_UNORM;
default:
UNREACHABLE();
}
@@ -335,6 +341,13 @@ namespace dawn_native { namespace d3d12 {
uint32_t levelCount,
uint32_t baseArrayLayer,
uint32_t layerCount) {
// TODO(jiawei.shao@intel.com): initialize the textures in compressed formats with copies.
if (GetFormat().isCompressed) {
SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
layerCount);
return;
}
Device* device = ToBackend(GetDevice());
DescriptorHeapAllocator* descriptorHeapAllocator = device->GetDescriptorHeapAllocator();