From cbec3179ef87cf995bd2669da302d530c8c3d93b Mon Sep 17 00:00:00 2001 From: Natasha Lee Date: Mon, 10 Aug 2020 22:29:49 +0000 Subject: [PATCH] Implement Queue::WriteTexture in D3D12 Bug: dawn:483 Change-Id: I9e5f54abc6675acbb11a021a3d38aea7195017c5 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/26320 Commit-Queue: Natasha Lee Reviewed-by: Austin Eng --- src/dawn_native/Queue.cpp | 9 +- src/dawn_native/Queue.h | 7 +- src/dawn_native/d3d12/CommandBufferD3D12.cpp | 73 ++-------------- src/dawn_native/d3d12/DeviceD3D12.cpp | 28 +++++++ src/dawn_native/d3d12/DeviceD3D12.h | 6 ++ src/dawn_native/d3d12/QueueD3D12.cpp | 84 +++++++++++++++++++ src/dawn_native/d3d12/QueueD3D12.h | 4 + src/dawn_native/d3d12/UtilsD3D12.cpp | 79 ++++++++++++++++- src/dawn_native/d3d12/UtilsD3D12.h | 23 ++++- src/dawn_native/metal/DeviceMTL.h | 2 +- src/dawn_native/metal/DeviceMTL.mm | 12 +-- src/dawn_native/metal/QueueMTL.h | 7 +- src/dawn_native/metal/QueueMTL.mm | 61 +++++++------- src/dawn_native/vulkan/DeviceVk.cpp | 9 +- src/dawn_native/vulkan/DeviceVk.h | 2 +- src/dawn_native/vulkan/QueueVk.cpp | 62 +++++++------- src/dawn_native/vulkan/QueueVk.h | 7 +- .../end2end/CompressedTextureFormatTests.cpp | 5 +- src/tests/end2end/QueueTests.cpp | 2 +- src/tests/end2end/TextureZeroInitTests.cpp | 12 +-- 20 files changed, 324 insertions(+), 170 deletions(-) diff --git a/src/dawn_native/Queue.cpp b/src/dawn_native/Queue.cpp index 3afc18529f..403e022133 100644 --- a/src/dawn_native/Queue.cpp +++ b/src/dawn_native/Queue.cpp @@ -158,14 +158,13 @@ namespace dawn_native { return {}; } - return WriteTextureImpl(destination, data, dataSize, dataLayout, writeSize); + return WriteTextureImpl(*destination, data, *dataLayout, *writeSize); } - MaybeError QueueBase::WriteTextureImpl(const TextureCopyView* destination, + MaybeError QueueBase::WriteTextureImpl(const TextureCopyView& destination, const void* data, - size_t dataSize, - const TextureDataLayout* dataLayout, - const Extent3D* writeSize) { + const TextureDataLayout& dataLayout, + const Extent3D& writeSize) { // TODO(tommek@google.com): This should be implemented. return {}; } diff --git a/src/dawn_native/Queue.h b/src/dawn_native/Queue.h index aad5175334..441fa1b9b1 100644 --- a/src/dawn_native/Queue.h +++ b/src/dawn_native/Queue.h @@ -58,11 +58,10 @@ namespace dawn_native { uint64_t bufferOffset, const void* data, size_t size); - virtual MaybeError WriteTextureImpl(const TextureCopyView* destination, + virtual MaybeError WriteTextureImpl(const TextureCopyView& destination, const void* data, - size_t dataSize, - const TextureDataLayout* dataLayout, - const Extent3D* writeSize); + const TextureDataLayout& dataLayout, + const Extent3D& writeSize); MaybeError ValidateSubmit(uint32_t commandCount, CommandBufferBase* const* commands) const; MaybeError ValidateSignal(const Fence* fence, uint64_t signalValue) const; diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp index c58f150928..8fd4a5ad03 100644 --- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp +++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp @@ -95,39 +95,6 @@ namespace dawn_native { namespace d3d12 { copySize.depth == srcSize.depth; } - void RecordCopyBufferToTextureFromTextureCopySplit(ID3D12GraphicsCommandList* commandList, - const Texture2DCopySplit& baseCopySplit, - Buffer* buffer, - uint64_t baseOffset, - uint64_t bufferBytesPerRow, - Texture* texture, - uint32_t textureMiplevel, - uint32_t textureSlice, - Aspect aspect) { - const D3D12_TEXTURE_COPY_LOCATION textureLocation = - ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureSlice, - aspect); - - const uint64_t offset = baseCopySplit.offset + baseOffset; - - for (uint32_t i = 0; i < baseCopySplit.count; ++i) { - const Texture2DCopySplit::CopyInfo& info = baseCopySplit.copies[i]; - - // TODO(jiawei.shao@intel.com): pre-compute bufferLocation and sourceRegion as - // members in Texture2DCopySplit::CopyInfo. - const D3D12_TEXTURE_COPY_LOCATION bufferLocation = - ComputeBufferLocationForCopyTextureRegion(texture, buffer->GetD3D12Resource(), - info.bufferSize, offset, - bufferBytesPerRow); - const D3D12_BOX sourceRegion = - ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize); - - commandList->CopyTextureRegion(&textureLocation, info.textureOffset.x, - info.textureOffset.y, info.textureOffset.z, - &bufferLocation, &sourceRegion); - } - } - void RecordCopyTextureToBufferFromTextureCopySplit(ID3D12GraphicsCommandList* commandList, const Texture2DCopySplit& baseCopySplit, Buffer* buffer, @@ -713,41 +680,11 @@ namespace dawn_native { namespace d3d12 { texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopyDst, subresources); - // See comments in ComputeTextureCopySplits() for more details. - const TextureCopySplits copySplits = ComputeTextureCopySplits( - copy->destination.origin, copy->copySize, texture->GetFormat(), - copy->source.offset, copy->source.bytesPerRow, copy->source.rowsPerImage); - - const uint64_t bytesPerSlice = - copy->source.bytesPerRow * - (copy->source.rowsPerImage / texture->GetFormat().blockHeight); - - // copySplits.copies2D[1] is always calculated for the second copy slice with - // extra "bytesPerSlice" copy offset compared with the first copy slice. So - // here we use an array bufferOffsetsForNextSlice to record the extra offsets - // for each copy slice: bufferOffsetsForNextSlice[0] is the extra offset for - // the next copy slice that uses copySplits.copies2D[0], and - // bufferOffsetsForNextSlice[1] is the extra offset for the next copy slice - // that uses copySplits.copies2D[1]. - std::array - bufferOffsetsForNextSlice = {{0u, 0u}}; - for (uint32_t copySlice = 0; copySlice < copy->copySize.depth; ++copySlice) { - const uint32_t splitIndex = copySlice % copySplits.copies2D.size(); - - const Texture2DCopySplit& copySplitPerLayerBase = - copySplits.copies2D[splitIndex]; - const uint64_t bufferOffsetForNextSlice = - bufferOffsetsForNextSlice[splitIndex]; - const uint32_t copyTextureLayer = copySlice + copy->destination.origin.z; - - RecordCopyBufferToTextureFromTextureCopySplit( - commandList, copySplitPerLayerBase, buffer, bufferOffsetForNextSlice, - copy->source.bytesPerRow, texture, copy->destination.mipLevel, - copyTextureLayer, subresources.aspects); - - bufferOffsetsForNextSlice[splitIndex] += - bytesPerSlice * copySplits.copies2D.size(); - } + // compute the copySplits and record the CopyTextureRegion commands + CopyBufferToTextureWithCopySplit( + commandContext, copy->destination, copy->copySize, texture, + buffer->GetD3D12Resource(), copy->source.offset, copy->source.bytesPerRow, + copy->source.rowsPerImage, subresources.aspects); break; } diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp index 7b73ccfdb1..2e2e60e44a 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.cpp +++ b/src/dawn_native/d3d12/DeviceD3D12.cpp @@ -42,6 +42,7 @@ #include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h" #include "dawn_native/d3d12/SwapChainD3D12.h" #include "dawn_native/d3d12/TextureD3D12.h" +#include "dawn_native/d3d12/UtilsD3D12.h" #include @@ -364,6 +365,33 @@ namespace dawn_native { namespace d3d12 { sourceOffset, size); } + MaybeError Device::CopyFromStagingToTexture(const StagingBufferBase* source, + const TextureDataLayout& src, + TextureCopy* dst, + const Extent3D& copySizePixels) { + CommandRecordingContext* commandContext; + DAWN_TRY_ASSIGN(commandContext, GetPendingCommandContext()); + Texture* texture = ToBackend(dst->texture.Get()); + ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); + + SubresourceRange range = GetSubresourcesAffectedByCopy(*dst, copySizePixels); + + if (IsCompleteSubresourceCopiedTo(texture, copySizePixels, dst->mipLevel)) { + texture->SetIsSubresourceContentInitialized(true, range); + } else { + texture->EnsureSubresourceContentInitialized(commandContext, range); + } + + texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopyDst, range); + + // compute the copySplits and record the CopyTextureRegion commands + CopyBufferToTextureWithCopySplit(commandContext, *dst, copySizePixels, texture, + ToBackend(source)->GetResource(), src.offset, + src.bytesPerRow, src.rowsPerImage, range.aspects); + + return {}; + } + void Device::DeallocateMemory(ResourceHeapAllocation& allocation) { mResourceAllocatorManager->DeallocateMemory(allocation); } diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h index d4cb0819be..3ab03934ad 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.h +++ b/src/dawn_native/d3d12/DeviceD3D12.h @@ -20,6 +20,7 @@ #include "common/Constants.h" #include "common/SerialQueue.h" #include "dawn_native/BindingInfo.h" +#include "dawn_native/Commands.h" #include "dawn_native/Device.h" #include "dawn_native/d3d12/CommandRecordingContext.h" #include "dawn_native/d3d12/D3D12Info.h" @@ -99,6 +100,11 @@ namespace dawn_native { namespace d3d12 { uint64_t destinationOffset, uint64_t size); + MaybeError CopyFromStagingToTexture(const StagingBufferBase* source, + const TextureDataLayout& src, + TextureCopy* dst, + const Extent3D& copySizePixels); + ResultOrError AllocateMemory( D3D12_HEAP_TYPE heapType, const D3D12_RESOURCE_DESC& resourceDescriptor, diff --git a/src/dawn_native/d3d12/QueueD3D12.cpp b/src/dawn_native/d3d12/QueueD3D12.cpp index 710e41f052..c880892d64 100644 --- a/src/dawn_native/d3d12/QueueD3D12.cpp +++ b/src/dawn_native/d3d12/QueueD3D12.cpp @@ -14,6 +14,11 @@ #include "dawn_native/d3d12/QueueD3D12.h" +#include "common/Math.h" +#include "dawn_native/Buffer.h" +#include "dawn_native/CommandValidation.h" +#include "dawn_native/Commands.h" +#include "dawn_native/DynamicUploader.h" #include "dawn_native/d3d12/CommandBufferD3D12.h" #include "dawn_native/d3d12/D3D12Error.h" #include "dawn_native/d3d12/DeviceD3D12.h" @@ -22,6 +27,46 @@ namespace dawn_native { namespace d3d12 { + namespace { + ResultOrError UploadTextureDataAligningBytesPerRow( + DeviceBase* device, + const void* data, + uint32_t alignedBytesPerRow, + uint32_t optimallyAlignedBytesPerRow, + uint32_t alignedRowsPerImage, + const TextureDataLayout& dataLayout, + const Format& textureFormat, + const Extent3D& writeSizePixel) { + uint32_t newDataSizeBytes = ComputeRequiredBytesInCopy( + textureFormat, writeSizePixel, optimallyAlignedBytesPerRow, alignedRowsPerImage); + + UploadHandle uploadHandle; + DAWN_TRY_ASSIGN(uploadHandle, device->GetDynamicUploader()->Allocate( + newDataSizeBytes, device->GetPendingCommandSerial())); + ASSERT(uploadHandle.mappedBuffer != nullptr); + + uint8_t* dstPointer = static_cast(uploadHandle.mappedBuffer); + const uint8_t* srcPointer = static_cast(data); + srcPointer += dataLayout.offset; + + uint32_t alignedRowsPerImageInBlock = alignedRowsPerImage / textureFormat.blockHeight; + uint32_t dataRowsPerImageInBlock = dataLayout.rowsPerImage / textureFormat.blockHeight; + if (dataRowsPerImageInBlock == 0) { + dataRowsPerImageInBlock = writeSizePixel.height / textureFormat.blockHeight; + } + + ASSERT(dataRowsPerImageInBlock >= alignedRowsPerImageInBlock); + uint64_t imageAdditionalStride = + dataLayout.bytesPerRow * (dataRowsPerImageInBlock - alignedRowsPerImageInBlock); + + CopyTextureData(dstPointer, srcPointer, writeSizePixel.depth, + alignedRowsPerImageInBlock, imageAdditionalStride, alignedBytesPerRow, + optimallyAlignedBytesPerRow, dataLayout.bytesPerRow); + + return uploadHandle; + } + } // namespace + Queue::Queue(Device* device) : QueueBase(device) { } @@ -47,4 +92,43 @@ namespace dawn_native { namespace d3d12 { return {}; } + MaybeError Queue::WriteTextureImpl(const TextureCopyView& destination, + const void* data, + const TextureDataLayout& dataLayout, + const Extent3D& writeSizePixel) { + const TexelBlockInfo& blockInfo = + destination.texture->GetFormat().GetTexelBlockInfo(destination.aspect); + + // We are only copying the part of the data that will appear in the texture. + // Note that validating texture copy range ensures that writeSizePixel->width and + // writeSizePixel->height are multiples of blockWidth and blockHeight respectively. + uint32_t alignedBytesPerRow = + (writeSizePixel.width) / blockInfo.blockWidth * blockInfo.blockByteSize; + uint32_t alignedRowsPerImage = writeSizePixel.height; + uint32_t optimallyAlignedBytesPerRow = + Align(alignedBytesPerRow, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + + UploadHandle uploadHandle; + DAWN_TRY_ASSIGN( + uploadHandle, + UploadTextureDataAligningBytesPerRow( + GetDevice(), data, alignedBytesPerRow, optimallyAlignedBytesPerRow, + alignedRowsPerImage, dataLayout, destination.texture->GetFormat(), writeSizePixel)); + + TextureDataLayout passDataLayout = dataLayout; + passDataLayout.offset = uploadHandle.startOffset; + passDataLayout.bytesPerRow = optimallyAlignedBytesPerRow; + passDataLayout.rowsPerImage = alignedRowsPerImage; + + TextureCopy textureCopy; + textureCopy.texture = destination.texture; + textureCopy.mipLevel = destination.mipLevel; + textureCopy.origin = destination.origin; + textureCopy.aspect = ConvertAspect(destination.texture->GetFormat(), destination.aspect); + + return ToBackend(GetDevice()) + ->CopyFromStagingToTexture(uploadHandle.stagingBuffer, passDataLayout, &textureCopy, + writeSizePixel); + } + }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/QueueD3D12.h b/src/dawn_native/d3d12/QueueD3D12.h index f211d0bf58..6b23a4569e 100644 --- a/src/dawn_native/d3d12/QueueD3D12.h +++ b/src/dawn_native/d3d12/QueueD3D12.h @@ -31,6 +31,10 @@ namespace dawn_native { namespace d3d12 { private: MaybeError SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) override; + MaybeError WriteTextureImpl(const TextureCopyView& destination, + const void* data, + const TextureDataLayout& dataLayout, + const Extent3D& writeSizePixel) override; }; }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/UtilsD3D12.cpp b/src/dawn_native/d3d12/UtilsD3D12.cpp index 97de20403a..6a3b4bc66e 100644 --- a/src/dawn_native/d3d12/UtilsD3D12.cpp +++ b/src/dawn_native/d3d12/UtilsD3D12.cpp @@ -15,6 +15,9 @@ #include "dawn_native/d3d12/UtilsD3D12.h" #include "common/Assert.h" +#include "dawn_native/Format.h" +#include "dawn_native/d3d12/BufferD3D12.h" +#include "dawn_native/d3d12/CommandRecordingContext.h" #include @@ -65,7 +68,7 @@ namespace dawn_native { namespace d3d12 { D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture, uint32_t level, uint32_t slice, - Aspect aspect) { + const Aspect& aspect) { D3D12_TEXTURE_COPY_LOCATION copyLocation; copyLocation.pResource = texture->GetD3D12Resource(); copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; @@ -136,4 +139,78 @@ namespace dawn_native { namespace d3d12 { } } + void RecordCopyBufferToTextureFromTextureCopySplit(ID3D12GraphicsCommandList* commandList, + const Texture2DCopySplit& baseCopySplit, + ID3D12Resource* bufferResource, + uint64_t baseOffsetBytes, + uint64_t bufferBytesPerRow, + Texture* texture, + uint32_t textureMiplevel, + uint32_t textureSlice, + const Aspect& aspect) { + const D3D12_TEXTURE_COPY_LOCATION textureLocation = + ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureSlice, aspect); + + const uint64_t offsetBytes = baseCopySplit.offset + baseOffsetBytes; + + for (uint32_t i = 0; i < baseCopySplit.count; ++i) { + const Texture2DCopySplit::CopyInfo& info = baseCopySplit.copies[i]; + + // TODO(jiawei.shao@intel.com): pre-compute bufferLocation and sourceRegion as + // members in Texture2DCopySplit::CopyInfo. + const D3D12_TEXTURE_COPY_LOCATION bufferLocation = + ComputeBufferLocationForCopyTextureRegion(texture, bufferResource, info.bufferSize, + offsetBytes, bufferBytesPerRow); + const D3D12_BOX sourceRegion = + ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize); + + commandList->CopyTextureRegion(&textureLocation, info.textureOffset.x, + info.textureOffset.y, info.textureOffset.z, + &bufferLocation, &sourceRegion); + } + } + + void CopyBufferToTextureWithCopySplit(CommandRecordingContext* commandContext, + const TextureCopy& textureCopy, + const Extent3D& copySize, + Texture* texture, + ID3D12Resource* bufferResource, + const uint64_t offsetBytes, + const uint32_t bytesPerRow, + const uint32_t rowsPerImage, + const Aspect& aspects) { + // See comments in ComputeTextureCopySplits() for more details. + const TextureCopySplits copySplits = + ComputeTextureCopySplits(textureCopy.origin, copySize, texture->GetFormat(), + offsetBytes, bytesPerRow, rowsPerImage); + + const uint64_t bytesPerSlice = + bytesPerRow * (rowsPerImage / texture->GetFormat().blockHeight); + + // copySplits.copies2D[1] is always calculated for the second copy slice with + // extra "bytesPerSlice" copy offset compared with the first copy slice. So + // here we use an array bufferOffsetsForNextSlice to record the extra offsets + // for each copy slice: bufferOffsetsForNextSlice[0] is the extra offset for + // the next copy slice that uses copySplits.copies2D[0], and + // bufferOffsetsForNextSlice[1] is the extra offset for the next copy slice + // that uses copySplits.copies2D[1]. + std::array bufferOffsetsForNextSlice = { + {0u, 0u}}; + + for (uint32_t copySlice = 0; copySlice < copySize.depth; ++copySlice) { + const uint32_t splitIndex = copySlice % copySplits.copies2D.size(); + + const Texture2DCopySplit& copySplitPerLayerBase = copySplits.copies2D[splitIndex]; + const uint64_t bufferOffsetForNextSlice = bufferOffsetsForNextSlice[splitIndex]; + const uint32_t copyTextureLayer = copySlice + textureCopy.origin.z; + + RecordCopyBufferToTextureFromTextureCopySplit( + commandContext->GetCommandList(), copySplitPerLayerBase, bufferResource, + bufferOffsetForNextSlice, bytesPerRow, texture, textureCopy.mipLevel, + copyTextureLayer, aspects); + + bufferOffsetsForNextSlice[splitIndex] += bytesPerSlice * copySplits.copies2D.size(); + } + } + }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/UtilsD3D12.h b/src/dawn_native/d3d12/UtilsD3D12.h index 97bf74c3ad..ad47570664 100644 --- a/src/dawn_native/d3d12/UtilsD3D12.h +++ b/src/dawn_native/d3d12/UtilsD3D12.h @@ -15,6 +15,7 @@ #ifndef DAWNNATIVE_D3D12_UTILSD3D12_H_ #define DAWNNATIVE_D3D12_UTILSD3D12_H_ +#include "dawn_native/Commands.h" #include "dawn_native/d3d12/BufferD3D12.h" #include "dawn_native/d3d12/TextureCopySplitter.h" #include "dawn_native/d3d12/TextureD3D12.h" @@ -30,7 +31,7 @@ namespace dawn_native { namespace d3d12 { D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture, uint32_t level, uint32_t slice, - Aspect aspect); + const Aspect& aspect); D3D12_TEXTURE_COPY_LOCATION ComputeBufferLocationForCopyTextureRegion( const Texture* texture, @@ -42,6 +43,26 @@ namespace dawn_native { namespace d3d12 { bool IsTypeless(DXGI_FORMAT format); + void RecordCopyBufferToTextureFromTextureCopySplit(ID3D12GraphicsCommandList* commandList, + const Texture2DCopySplit& baseCopySplit, + Buffer* buffer, + uint64_t baseOffset, + uint64_t bufferBytesPerRow, + Texture* texture, + uint32_t textureMiplevel, + uint32_t textureSlice, + const Aspect& aspect); + + void CopyBufferToTextureWithCopySplit(CommandRecordingContext* commandContext, + const TextureCopy& textureCopy, + const Extent3D& copySize, + Texture* texture, + ID3D12Resource* bufferResource, + const uint64_t offset, + const uint32_t bytesPerRow, + const uint32_t rowsPerImage, + const Aspect& aspect); + }} // namespace dawn_native::d3d12 #endif // DAWNNATIVE_D3D12_UTILSD3D12_H_ diff --git a/src/dawn_native/metal/DeviceMTL.h b/src/dawn_native/metal/DeviceMTL.h index 87a697bce5..8c4bc49327 100644 --- a/src/dawn_native/metal/DeviceMTL.h +++ b/src/dawn_native/metal/DeviceMTL.h @@ -67,7 +67,7 @@ namespace dawn_native { namespace metal { MaybeError CopyFromStagingToTexture(StagingBufferBase* source, const TextureDataLayout& dataLayout, TextureCopy* dst, - const Extent3D copySize); + const Extent3D& copySizePixels); private: Device(AdapterBase* adapter, id mtlDevice, const DeviceDescriptor* descriptor); diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm index fb7fdc389c..79b4f812d7 100644 --- a/src/dawn_native/metal/DeviceMTL.mm +++ b/src/dawn_native/metal/DeviceMTL.mm @@ -271,7 +271,7 @@ namespace dawn_native { namespace metal { MaybeError Device::CopyFromStagingToTexture(StagingBufferBase* source, const TextureDataLayout& dataLayout, TextureCopy* dst, - const Extent3D copySize) { + const Extent3D& copySizePixels) { Texture* texture = ToBackend(dst->texture.Get()); // This function assumes data is perfectly aligned. Otherwise, it might be necessary @@ -280,19 +280,19 @@ namespace dawn_native { namespace metal { uint32_t blockSize = blockInfo.blockByteSize; uint32_t blockWidth = blockInfo.blockWidth; uint32_t blockHeight = blockInfo.blockHeight; - ASSERT(dataLayout.rowsPerImage == (copySize.height)); - ASSERT(dataLayout.bytesPerRow == (copySize.width) / blockWidth * blockSize); + ASSERT(dataLayout.rowsPerImage == (copySizePixels.height)); + ASSERT(dataLayout.bytesPerRow == (copySizePixels.width) / blockWidth * blockSize); - EnsureDestinationTextureInitialized(texture, *dst, copySize); + EnsureDestinationTextureInitialized(texture, *dst, copySizePixels); // Metal validation layer requires that if the texture's pixel format is a compressed // format, the sourceSize must be a multiple of the pixel format's block size or be // clamped to the edge of the texture if the block extends outside the bounds of a // texture. const Extent3D clampedSize = - texture->ClampToMipLevelVirtualSize(dst->mipLevel, dst->origin, copySize); + texture->ClampToMipLevelVirtualSize(dst->mipLevel, dst->origin, copySizePixels); const uint32_t copyBaseLayer = dst->origin.z; - const uint32_t copyLayerCount = copySize.depth; + const uint32_t copyLayerCount = copySizePixels.depth; const uint64_t bytesPerImage = dataLayout.rowsPerImage * dataLayout.bytesPerRow / blockHeight; diff --git a/src/dawn_native/metal/QueueMTL.h b/src/dawn_native/metal/QueueMTL.h index bda47eb853..55915c25b5 100644 --- a/src/dawn_native/metal/QueueMTL.h +++ b/src/dawn_native/metal/QueueMTL.h @@ -28,11 +28,10 @@ namespace dawn_native { namespace metal { private: MaybeError SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) override; - MaybeError WriteTextureImpl(const TextureCopyView* destination, + MaybeError WriteTextureImpl(const TextureCopyView& destination, const void* data, - size_t dataSize, - const TextureDataLayout* dataLayout, - const Extent3D* writeSize) override; + const TextureDataLayout& dataLayout, + const Extent3D& writeSizePixel) override; }; }} // namespace dawn_native::metal diff --git a/src/dawn_native/metal/QueueMTL.mm b/src/dawn_native/metal/QueueMTL.mm index 237750cbbe..44cbb0fbdf 100644 --- a/src/dawn_native/metal/QueueMTL.mm +++ b/src/dawn_native/metal/QueueMTL.mm @@ -29,37 +29,36 @@ namespace dawn_native { namespace metal { ResultOrError UploadTextureDataAligningBytesPerRow( DeviceBase* device, const void* data, - size_t dataSize, uint32_t alignedBytesPerRow, uint32_t alignedRowsPerImage, - const TextureDataLayout* dataLayout, + const TextureDataLayout& dataLayout, const TexelBlockInfo& blockInfo, - const Extent3D* writeSize) { - uint32_t newDataSize = ComputeRequiredBytesInCopy( - blockInfo, *writeSize, alignedBytesPerRow, alignedRowsPerImage); + const Extent3D& writeSizePixel) { + uint32_t newDataSizeBytes = ComputeRequiredBytesInCopy( + blockInfo, writeSizePixel, alignedBytesPerRow, alignedRowsPerImage); UploadHandle uploadHandle; DAWN_TRY_ASSIGN(uploadHandle, device->GetDynamicUploader()->Allocate( - newDataSize, device->GetPendingCommandSerial())); + newDataSizeBytes, device->GetPendingCommandSerial())); ASSERT(uploadHandle.mappedBuffer != nullptr); uint8_t* dstPointer = static_cast(uploadHandle.mappedBuffer); const uint8_t* srcPointer = static_cast(data); - srcPointer += dataLayout->offset; + srcPointer += dataLayout.offset; uint32_t alignedRowsPerImageInBlock = alignedRowsPerImage / blockInfo.blockHeight; - uint32_t dataRowsPerImageInBlock = dataLayout->rowsPerImage / blockInfo.blockHeight; + uint32_t dataRowsPerImageInBlock = dataLayout.rowsPerImage / blockInfo.blockHeight; if (dataRowsPerImageInBlock == 0) { - dataRowsPerImageInBlock = writeSize->height / blockInfo.blockHeight; + dataRowsPerImageInBlock = writeSizePixel.height / blockInfo.blockHeight; } ASSERT(dataRowsPerImageInBlock >= alignedRowsPerImageInBlock); uint64_t imageAdditionalStride = - dataLayout->bytesPerRow * (dataRowsPerImageInBlock - alignedRowsPerImageInBlock); + dataLayout.bytesPerRow * (dataRowsPerImageInBlock - alignedRowsPerImageInBlock); - CopyTextureData(dstPointer, srcPointer, writeSize->depth, alignedRowsPerImageInBlock, - imageAdditionalStride, alignedBytesPerRow, alignedBytesPerRow, - dataLayout->bytesPerRow); + CopyTextureData(dstPointer, srcPointer, writeSizePixel.depth, + alignedRowsPerImageInBlock, imageAdditionalStride, alignedBytesPerRow, + alignedBytesPerRow, dataLayout.bytesPerRow); return uploadHandle; } @@ -86,40 +85,40 @@ namespace dawn_native { namespace metal { // We don't write from the CPU to the texture directly which can be done in Metal using the // replaceRegion function, because the function requires a non-private storage mode and Dawn // sets the private storage mode by default for all textures except IOSurfaces on macOS. - MaybeError Queue::WriteTextureImpl(const TextureCopyView* destination, + MaybeError Queue::WriteTextureImpl(const TextureCopyView& destination, const void* data, - size_t dataSize, - const TextureDataLayout* dataLayout, - const Extent3D* writeSize) { + const TextureDataLayout& dataLayout, + const Extent3D& writeSizePixel) { const TexelBlockInfo& blockInfo = - destination->texture->GetFormat().GetTexelBlockInfo(destination->aspect); + destination.texture->GetFormat().GetTexelBlockInfo(destination.aspect); // We are only copying the part of the data that will appear in the texture. - // Note that validating texture copy range ensures that writeSize->width and - // writeSize->height are multiples of blockWidth and blockHeight respectively. + // Note that validating texture copy range ensures that writeSizePixel->width and + // writeSizePixel->height are multiples of blockWidth and blockHeight respectively. uint32_t alignedBytesPerRow = - (writeSize->width) / blockInfo.blockWidth * blockInfo.blockByteSize; - uint32_t alignedRowsPerImage = writeSize->height; + (writeSizePixel.width) / blockInfo.blockWidth * blockInfo.blockByteSize; + uint32_t alignedRowsPerImage = writeSizePixel.height; UploadHandle uploadHandle; - DAWN_TRY_ASSIGN(uploadHandle, UploadTextureDataAligningBytesPerRow( - GetDevice(), data, dataSize, alignedBytesPerRow, - alignedRowsPerImage, dataLayout, blockInfo, writeSize)); + DAWN_TRY_ASSIGN(uploadHandle, + UploadTextureDataAligningBytesPerRow(GetDevice(), data, alignedBytesPerRow, + alignedRowsPerImage, dataLayout, + blockInfo, writeSizePixel)); - TextureDataLayout passDataLayout = *dataLayout; + TextureDataLayout passDataLayout = dataLayout; passDataLayout.offset = uploadHandle.startOffset; passDataLayout.bytesPerRow = alignedBytesPerRow; passDataLayout.rowsPerImage = alignedRowsPerImage; TextureCopy textureCopy; - textureCopy.texture = destination->texture; - textureCopy.mipLevel = destination->mipLevel; - textureCopy.origin = destination->origin; - textureCopy.aspect = ConvertAspect(destination->texture->GetFormat(), destination->aspect); + textureCopy.texture = destination.texture; + textureCopy.mipLevel = destination.mipLevel; + textureCopy.origin = destination.origin; + textureCopy.aspect = ConvertAspect(destination.texture->GetFormat(), destination.aspect); return ToBackend(GetDevice()) ->CopyFromStagingToTexture(uploadHandle.stagingBuffer, passDataLayout, &textureCopy, - *writeSize); + writeSizePixel); } }} // namespace dawn_native::metal diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp index f6afcfdb49..1b5e197918 100644 --- a/src/dawn_native/vulkan/DeviceVk.cpp +++ b/src/dawn_native/vulkan/DeviceVk.cpp @@ -617,20 +617,21 @@ namespace dawn_native { namespace vulkan { MaybeError Device::CopyFromStagingToTexture(StagingBufferBase* source, const TextureDataLayout& src, TextureCopy* dst, - const Extent3D copySize) { + const Extent3D& copySizePixels) { // There is no need of a barrier to make host writes available and visible to the copy // operation for HOST_COHERENT memory. The Vulkan spec for vkQueueSubmit describes that it // does an implicit availability, visibility and domain operation. CommandRecordingContext* recordingContext = GetPendingRecordingContext(); - VkBufferImageCopy region = ComputeBufferImageCopyRegion(src, *dst, copySize); + VkBufferImageCopy region = ComputeBufferImageCopyRegion(src, *dst, copySizePixels); VkImageSubresourceLayers subresource = region.imageSubresource; ASSERT(dst->texture->GetDimension() == wgpu::TextureDimension::e2D); - SubresourceRange range = GetSubresourcesAffectedByCopy(*dst, copySize); + SubresourceRange range = GetSubresourcesAffectedByCopy(*dst, copySizePixels); - if (IsCompleteSubresourceCopiedTo(dst->texture.Get(), copySize, subresource.mipLevel)) { + if (IsCompleteSubresourceCopiedTo(dst->texture.Get(), copySizePixels, + subresource.mipLevel)) { // Since texture has been overwritten, it has been "initialized" dst->texture->SetIsSubresourceContentInitialized(true, range); } else { diff --git a/src/dawn_native/vulkan/DeviceVk.h b/src/dawn_native/vulkan/DeviceVk.h index 851a1e723e..89ec1ea8e8 100644 --- a/src/dawn_native/vulkan/DeviceVk.h +++ b/src/dawn_native/vulkan/DeviceVk.h @@ -91,7 +91,7 @@ namespace dawn_native { namespace vulkan { MaybeError CopyFromStagingToTexture(StagingBufferBase* source, const TextureDataLayout& src, TextureCopy* dst, - const Extent3D copySize); + const Extent3D& copySizePixels); ResultOrError AllocateMemory(VkMemoryRequirements requirements, bool mappable); diff --git a/src/dawn_native/vulkan/QueueVk.cpp b/src/dawn_native/vulkan/QueueVk.cpp index 227ccb4593..3842652e72 100644 --- a/src/dawn_native/vulkan/QueueVk.cpp +++ b/src/dawn_native/vulkan/QueueVk.cpp @@ -31,15 +31,14 @@ namespace dawn_native { namespace vulkan { ResultOrError UploadTextureDataAligningBytesPerRow( DeviceBase* device, const void* data, - size_t dataSize, uint32_t alignedBytesPerRow, uint32_t optimallyAlignedBytesPerRow, uint32_t alignedRowsPerImage, - const TextureDataLayout* dataLayout, + const TextureDataLayout& dataLayout, const TexelBlockInfo& blockInfo, - const Extent3D* writeSize) { - uint32_t newDataSize = ComputeRequiredBytesInCopy( - blockInfo, *writeSize, optimallyAlignedBytesPerRow, alignedRowsPerImage); + const Extent3D& writeSizePixel) { + uint32_t newDataSizeBytes = ComputeRequiredBytesInCopy( + blockInfo, writeSizePixel, optimallyAlignedBytesPerRow, alignedRowsPerImage); uint64_t optimalOffsetAlignment = ToBackend(device) @@ -48,18 +47,18 @@ namespace dawn_native { namespace vulkan { UploadHandle uploadHandle; DAWN_TRY_ASSIGN(uploadHandle, device->GetDynamicUploader()->Allocate( - newDataSize + optimalOffsetAlignment - 1, + newDataSizeBytes + optimalOffsetAlignment - 1, device->GetPendingCommandSerial())); ASSERT(uploadHandle.mappedBuffer != nullptr); uint8_t* dstPointer = static_cast(uploadHandle.mappedBuffer); const uint8_t* srcPointer = static_cast(data); - srcPointer += dataLayout->offset; + srcPointer += dataLayout.offset; uint32_t alignedRowsPerImageInBlock = alignedRowsPerImage / blockInfo.blockHeight; - uint32_t dataRowsPerImageInBlock = dataLayout->rowsPerImage / blockInfo.blockHeight; + uint32_t dataRowsPerImageInBlock = dataLayout.rowsPerImage / blockInfo.blockHeight; if (dataRowsPerImageInBlock == 0) { - dataRowsPerImageInBlock = writeSize->height / blockInfo.blockHeight; + dataRowsPerImageInBlock = writeSizePixel.height / blockInfo.blockHeight; } uint64_t additionalOffset = @@ -69,11 +68,11 @@ namespace dawn_native { namespace vulkan { ASSERT(dataRowsPerImageInBlock >= alignedRowsPerImageInBlock); uint64_t imageAdditionalStride = - dataLayout->bytesPerRow * (dataRowsPerImageInBlock - alignedRowsPerImageInBlock); + dataLayout.bytesPerRow * (dataRowsPerImageInBlock - alignedRowsPerImageInBlock); - CopyTextureData(dstPointer, srcPointer, writeSize->depth, alignedRowsPerImageInBlock, - imageAdditionalStride, alignedBytesPerRow, optimallyAlignedBytesPerRow, - dataLayout->bytesPerRow); + CopyTextureData(dstPointer, srcPointer, writeSizePixel.depth, + alignedRowsPerImageInBlock, imageAdditionalStride, alignedBytesPerRow, + optimallyAlignedBytesPerRow, dataLayout.bytesPerRow); return uploadHandle; } @@ -105,20 +104,19 @@ namespace dawn_native { namespace vulkan { return {}; } - MaybeError Queue::WriteTextureImpl(const TextureCopyView* destination, + MaybeError Queue::WriteTextureImpl(const TextureCopyView& destination, const void* data, - size_t dataSize, - const TextureDataLayout* dataLayout, - const Extent3D* writeSize) { + const TextureDataLayout& dataLayout, + const Extent3D& writeSizePixel) { const TexelBlockInfo& blockInfo = - destination->texture->GetFormat().GetTexelBlockInfo(destination->aspect); + destination.texture->GetFormat().GetTexelBlockInfo(destination.aspect); // We are only copying the part of the data that will appear in the texture. - // Note that validating texture copy range ensures that writeSize->width and - // writeSize->height are multiples of blockWidth and blockHeight respectively. + // Note that validating texture copy range ensures that writeSizePixel->width and + // writeSizePixel->height are multiples of blockWidth and blockHeight respectively. uint32_t alignedBytesPerRow = - (writeSize->width) / blockInfo.blockWidth * blockInfo.blockByteSize; - uint32_t alignedRowsPerImage = writeSize->height; + (writeSizePixel.width) / blockInfo.blockWidth * blockInfo.blockByteSize; + uint32_t alignedRowsPerImage = writeSizePixel.height; uint32_t optimalBytesPerRowAlignment = ToBackend(GetDevice()) @@ -128,24 +126,24 @@ namespace dawn_native { namespace vulkan { Align(alignedBytesPerRow, optimalBytesPerRowAlignment); UploadHandle uploadHandle; - DAWN_TRY_ASSIGN(uploadHandle, UploadTextureDataAligningBytesPerRow( - GetDevice(), data, dataSize, alignedBytesPerRow, - optimallyAlignedBytesPerRow, alignedRowsPerImage, - dataLayout, blockInfo, writeSize)); + DAWN_TRY_ASSIGN(uploadHandle, + UploadTextureDataAligningBytesPerRow( + GetDevice(), data, alignedBytesPerRow, optimallyAlignedBytesPerRow, + alignedRowsPerImage, dataLayout, blockInfo, writeSizePixel)); - TextureDataLayout passDataLayout = *dataLayout; + TextureDataLayout passDataLayout = dataLayout; passDataLayout.offset = uploadHandle.startOffset; passDataLayout.bytesPerRow = optimallyAlignedBytesPerRow; passDataLayout.rowsPerImage = alignedRowsPerImage; TextureCopy textureCopy; - textureCopy.texture = destination->texture; - textureCopy.mipLevel = destination->mipLevel; - textureCopy.origin = destination->origin; - textureCopy.aspect = ConvertAspect(destination->texture->GetFormat(), destination->aspect); + textureCopy.texture = destination.texture; + textureCopy.mipLevel = destination.mipLevel; + textureCopy.origin = destination.origin; + textureCopy.aspect = ConvertAspect(destination.texture->GetFormat(), destination.aspect); return ToBackend(GetDevice()) ->CopyFromStagingToTexture(uploadHandle.stagingBuffer, passDataLayout, &textureCopy, - *writeSize); + writeSizePixel); } }} // namespace dawn_native::vulkan diff --git a/src/dawn_native/vulkan/QueueVk.h b/src/dawn_native/vulkan/QueueVk.h index bcfdbda062..34a0e6a579 100644 --- a/src/dawn_native/vulkan/QueueVk.h +++ b/src/dawn_native/vulkan/QueueVk.h @@ -31,11 +31,10 @@ namespace dawn_native { namespace vulkan { using QueueBase::QueueBase; MaybeError SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) override; - MaybeError WriteTextureImpl(const TextureCopyView* destination, + MaybeError WriteTextureImpl(const TextureCopyView& destination, const void* data, - size_t dataSize, - const TextureDataLayout* dataLayout, - const Extent3D* writeSize) override; + const TextureDataLayout& dataLayout, + const Extent3D& writeSizePixel) override; }; }} // namespace dawn_native::vulkan diff --git a/src/tests/end2end/CompressedTextureFormatTests.cpp b/src/tests/end2end/CompressedTextureFormatTests.cpp index 2054dfaa90..a6ae4195d4 100644 --- a/src/tests/end2end/CompressedTextureFormatTests.cpp +++ b/src/tests/end2end/CompressedTextureFormatTests.cpp @@ -1179,4 +1179,7 @@ TEST_P(CompressedTextureWriteTextureTest, } } -DAWN_INSTANTIATE_TEST(CompressedTextureWriteTextureTest, MetalBackend(), VulkanBackend()); \ No newline at end of file +DAWN_INSTANTIATE_TEST(CompressedTextureWriteTextureTest, + MetalBackend(), + VulkanBackend(), + D3D12Backend()); \ No newline at end of file diff --git a/src/tests/end2end/QueueTests.cpp b/src/tests/end2end/QueueTests.cpp index edf9ccf980..2ac7c8c153 100644 --- a/src/tests/end2end/QueueTests.cpp +++ b/src/tests/end2end/QueueTests.cpp @@ -522,4 +522,4 @@ TEST_P(QueueWriteTextureTests, VaryingArrayBytesPerRow) { } } -DAWN_INSTANTIATE_TEST(QueueWriteTextureTests, MetalBackend(), VulkanBackend()); +DAWN_INSTANTIATE_TEST(QueueWriteTextureTests, MetalBackend(), VulkanBackend(), D3D12Backend()); diff --git a/src/tests/end2end/TextureZeroInitTests.cpp b/src/tests/end2end/TextureZeroInitTests.cpp index b4646f52cf..7289757ca3 100644 --- a/src/tests/end2end/TextureZeroInitTests.cpp +++ b/src/tests/end2end/TextureZeroInitTests.cpp @@ -1382,7 +1382,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToBufferNonRenderableUnaligned) { // In this test WriteTexture fully overwrites a texture TEST_P(TextureZeroInitTest, WriteWholeTexture) { // TODO(dawn:483): Remove this condition after implementing WriteTexture in those backends. - DAWN_SKIP_TEST_IF(IsOpenGL() || IsD3D12()); + DAWN_SKIP_TEST_IF(IsOpenGL()); wgpu::TextureDescriptor descriptor = CreateTextureDescriptor( 1, 1, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc, kColorFormat); @@ -1417,7 +1417,7 @@ TEST_P(TextureZeroInitTest, WriteWholeTexture) { // half. TEST_P(TextureZeroInitTest, WriteTextureHalf) { // TODO(dawn:483): Remove this condition after implementing WriteTexture in those backends. - DAWN_SKIP_TEST_IF(IsOpenGL() || IsD3D12()); + DAWN_SKIP_TEST_IF(IsOpenGL()); wgpu::TextureDescriptor descriptor = CreateTextureDescriptor( 4, 1, @@ -1457,7 +1457,7 @@ TEST_P(TextureZeroInitTest, WriteTextureHalf) { // is needed for neither the subresources involved in the write nor the other subresources. TEST_P(TextureZeroInitTest, WriteWholeTextureArray) { // TODO(dawn:483): Remove this condition after implementing WriteTexture in those backends. - DAWN_SKIP_TEST_IF(IsOpenGL() || IsD3D12()); + DAWN_SKIP_TEST_IF(IsOpenGL()); wgpu::TextureDescriptor descriptor = CreateTextureDescriptor( 1, 6, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc, kColorFormat); @@ -1500,7 +1500,7 @@ TEST_P(TextureZeroInitTest, WriteWholeTextureArray) { // half. TEST_P(TextureZeroInitTest, WriteTextureArrayHalf) { // TODO(dawn:483): Remove this condition after implementing WriteTexture in those backends. - DAWN_SKIP_TEST_IF(IsOpenGL() || IsD3D12()); + DAWN_SKIP_TEST_IF(IsOpenGL()); wgpu::TextureDescriptor descriptor = CreateTextureDescriptor( 4, 6, @@ -1547,7 +1547,7 @@ TEST_P(TextureZeroInitTest, WriteTextureArrayHalf) { // In this test WriteTexture fully overwrites a texture at mip level. TEST_P(TextureZeroInitTest, WriteWholeTextureAtMipLevel) { // TODO(dawn:483): Remove this condition after implementing WriteTexture in those backends. - DAWN_SKIP_TEST_IF(IsOpenGL() || IsD3D12()); + DAWN_SKIP_TEST_IF(IsOpenGL()); wgpu::TextureDescriptor descriptor = CreateTextureDescriptor( 4, 1, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc, kColorFormat); @@ -1586,7 +1586,7 @@ TEST_P(TextureZeroInitTest, WriteWholeTextureAtMipLevel) { // other half. TEST_P(TextureZeroInitTest, WriteTextureHalfAtMipLevel) { // TODO(dawn:483): Remove this condition after implementing WriteTexture in those backends. - DAWN_SKIP_TEST_IF(IsOpenGL() || IsD3D12()); + DAWN_SKIP_TEST_IF(IsOpenGL()); wgpu::TextureDescriptor descriptor = CreateTextureDescriptor( 4, 1,