mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-07 05:36:04 +00:00
Fixing offset alignments when using DynamicUploader
When using a dynamic uploader we didn't align the offset that the allocated memory might have already had. That fixes WriteTexture, WriteBuffer, ClearTexture and on D3D12 ClearBuffer. Bug: dawn:512 Change-Id: I64c7511ad6b0d3d6a28a494e1324a10ad4d38091 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/27020 Commit-Queue: Tomek Ponitka <tommek@google.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
parent
eff9ef0f22
commit
7f265d1d40
@ -64,4 +64,8 @@ static constexpr uint32_t kMaxTexture2DMipLevels = 14u;
|
||||
static_assert(1 << (kMaxTexture2DMipLevels - 1) == kMaxTextureSize,
|
||||
"kMaxTexture2DMipLevels and kMaxTextureSize size mismatch");
|
||||
|
||||
// Offset alignment for CopyB2B. Strictly speaking this alignment is required only
|
||||
// on macOS, but we decide to do it on all platforms.
|
||||
static constexpr uint64_t kCopyBufferToBufferOffsetAlignment = 4u;
|
||||
|
||||
#endif // COMMON_CONSTANTS_H_
|
||||
|
@ -28,7 +28,8 @@ namespace dawn_native {
|
||||
mDevice->GetPendingCommandSerial());
|
||||
}
|
||||
|
||||
ResultOrError<UploadHandle> DynamicUploader::Allocate(uint64_t allocationSize, Serial serial) {
|
||||
ResultOrError<UploadHandle> DynamicUploader::AllocateInternal(uint64_t allocationSize,
|
||||
Serial serial) {
|
||||
// Disable further sub-allocation should the request be too large.
|
||||
if (allocationSize > kRingBufferSize) {
|
||||
std::unique_ptr<StagingBufferBase> stagingBuffer;
|
||||
@ -108,4 +109,21 @@ namespace dawn_native {
|
||||
}
|
||||
mReleasedStagingBuffers.ClearUpTo(lastCompletedSerial);
|
||||
}
|
||||
|
||||
// TODO(dawn:512): Optimize this function so that it doesn't allocate additional memory
|
||||
// when it's not necessary.
|
||||
ResultOrError<UploadHandle> DynamicUploader::Allocate(uint64_t allocationSize,
|
||||
Serial serial,
|
||||
uint64_t offsetAlignment) {
|
||||
ASSERT(offsetAlignment > 0);
|
||||
UploadHandle uploadHandle;
|
||||
DAWN_TRY_ASSIGN(uploadHandle,
|
||||
AllocateInternal(allocationSize + offsetAlignment - 1, serial));
|
||||
uint64_t additionalOffset =
|
||||
Align(uploadHandle.startOffset, offsetAlignment) - uploadHandle.startOffset;
|
||||
uploadHandle.mappedBuffer =
|
||||
static_cast<uint8_t*>(uploadHandle.mappedBuffer) + additionalOffset;
|
||||
uploadHandle.startOffset += additionalOffset;
|
||||
return uploadHandle;
|
||||
}
|
||||
} // namespace dawn_native
|
||||
|
@ -40,7 +40,9 @@ namespace dawn_native {
|
||||
// implemented.
|
||||
void ReleaseStagingBuffer(std::unique_ptr<StagingBufferBase> stagingBuffer);
|
||||
|
||||
ResultOrError<UploadHandle> Allocate(uint64_t allocationSize, Serial serial);
|
||||
ResultOrError<UploadHandle> Allocate(uint64_t allocationSize,
|
||||
Serial serial,
|
||||
uint64_t offsetAlignment);
|
||||
void Deallocate(Serial lastCompletedSerial);
|
||||
|
||||
private:
|
||||
@ -51,6 +53,8 @@ namespace dawn_native {
|
||||
RingBufferAllocator mAllocator;
|
||||
};
|
||||
|
||||
ResultOrError<UploadHandle> AllocateInternal(uint64_t allocationSize, Serial serial);
|
||||
|
||||
std::vector<std::unique_ptr<RingBuffer>> mRingBuffers;
|
||||
SerialQueue<std::unique_ptr<StagingBufferBase>> mReleasedStagingBuffers;
|
||||
DeviceBase* mDevice;
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "dawn_native/Queue.h"
|
||||
|
||||
#include "common/Constants.h"
|
||||
#include "dawn_native/Buffer.h"
|
||||
#include "dawn_native/CommandBuffer.h"
|
||||
#include "dawn_native/CommandValidation.h"
|
||||
@ -110,7 +111,8 @@ namespace dawn_native {
|
||||
|
||||
UploadHandle uploadHandle;
|
||||
DAWN_TRY_ASSIGN(uploadHandle, device->GetDynamicUploader()->Allocate(
|
||||
size, device->GetPendingCommandSerial()));
|
||||
size, device->GetPendingCommandSerial(),
|
||||
kCopyBufferToBufferOffsetAlignment));
|
||||
ASSERT(uploadHandle.mappedBuffer != nullptr);
|
||||
|
||||
memcpy(uploadHandle.mappedBuffer, data, size);
|
||||
|
@ -425,7 +425,8 @@ namespace dawn_native { namespace d3d12 {
|
||||
DynamicUploader* uploader = device->GetDynamicUploader();
|
||||
UploadHandle uploadHandle;
|
||||
DAWN_TRY_ASSIGN(uploadHandle,
|
||||
uploader->Allocate(GetSize(), device->GetPendingCommandSerial()));
|
||||
uploader->Allocate(GetSize(), device->GetPendingCommandSerial(),
|
||||
kCopyBufferToBufferOffsetAlignment));
|
||||
|
||||
memset(uploadHandle.mappedBuffer, clearValue, GetSize());
|
||||
|
||||
|
@ -44,7 +44,8 @@ namespace dawn_native { namespace d3d12 {
|
||||
|
||||
UploadHandle uploadHandle;
|
||||
DAWN_TRY_ASSIGN(uploadHandle, device->GetDynamicUploader()->Allocate(
|
||||
newDataSizeBytes, device->GetPendingCommandSerial()));
|
||||
newDataSizeBytes, device->GetPendingCommandSerial(),
|
||||
textureFormat.blockByteSize));
|
||||
ASSERT(uploadHandle.mappedBuffer != nullptr);
|
||||
|
||||
uint8_t* dstPointer = static_cast<uint8_t*>(uploadHandle.mappedBuffer);
|
||||
|
@ -951,7 +951,8 @@ namespace dawn_native { namespace d3d12 {
|
||||
DynamicUploader* uploader = device->GetDynamicUploader();
|
||||
UploadHandle uploadHandle;
|
||||
DAWN_TRY_ASSIGN(uploadHandle,
|
||||
uploader->Allocate(bufferSize, device->GetPendingCommandSerial()));
|
||||
uploader->Allocate(bufferSize, device->GetPendingCommandSerial(),
|
||||
GetFormat().blockByteSize));
|
||||
memset(uploadHandle.mappedBuffer, clearColor, bufferSize);
|
||||
|
||||
for (uint32_t level = range.baseMipLevel;
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "dawn_native/metal/DeviceMTL.h"
|
||||
|
||||
#include "common/Platform.h"
|
||||
#include "dawn_native/BackendConnection.h"
|
||||
#include "dawn_native/BindGroupLayout.h"
|
||||
#include "dawn_native/Commands.h"
|
||||
@ -75,8 +76,10 @@ namespace dawn_native { namespace metal {
|
||||
{
|
||||
bool haveStoreAndMSAAResolve = false;
|
||||
#if defined(DAWN_PLATFORM_MACOS)
|
||||
haveStoreAndMSAAResolve =
|
||||
[mMtlDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v2];
|
||||
if (@available(macOS 10.12, *)) {
|
||||
haveStoreAndMSAAResolve =
|
||||
[mMtlDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v2];
|
||||
}
|
||||
#elif defined(DAWN_PLATFORM_IOS)
|
||||
haveStoreAndMSAAResolve =
|
||||
[mMtlDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v2];
|
||||
|
@ -41,7 +41,8 @@ namespace dawn_native { namespace metal {
|
||||
|
||||
UploadHandle uploadHandle;
|
||||
DAWN_TRY_ASSIGN(uploadHandle, device->GetDynamicUploader()->Allocate(
|
||||
newDataSizeBytes, device->GetPendingCommandSerial()));
|
||||
newDataSizeBytes, device->GetPendingCommandSerial(),
|
||||
blockInfo.blockByteSize));
|
||||
ASSERT(uploadHandle.mappedBuffer != nullptr);
|
||||
|
||||
uint8_t* dstPointer = static_cast<uint8_t*>(uploadHandle.mappedBuffer);
|
||||
|
@ -510,7 +510,8 @@ namespace dawn_native { namespace metal {
|
||||
DynamicUploader* uploader = device->GetDynamicUploader();
|
||||
UploadHandle uploadHandle;
|
||||
DAWN_TRY_ASSIGN(uploadHandle,
|
||||
uploader->Allocate(bufferSize, device->GetPendingCommandSerial()));
|
||||
uploader->Allocate(bufferSize, device->GetPendingCommandSerial(),
|
||||
GetFormat().blockByteSize));
|
||||
memset(uploadHandle.mappedBuffer, clearColor, bufferSize);
|
||||
|
||||
id<MTLBlitCommandEncoder> encoder = commandContext->EnsureBlit();
|
||||
|
@ -47,11 +47,17 @@ namespace dawn_native { namespace vulkan {
|
||||
ToBackend(device)
|
||||
->GetDeviceInfo()
|
||||
.properties.limits.optimalBufferCopyOffsetAlignment;
|
||||
ASSERT(IsPowerOfTwo(optimalOffsetAlignment));
|
||||
ASSERT(IsPowerOfTwo(blockInfo.blockByteSize));
|
||||
// We need the offset to be aligned to both optimalOffsetAlignment and blockByteSize,
|
||||
// since both of them are powers of two, we only need to align to the max value.
|
||||
uint64_t offsetAlignment =
|
||||
std::max(optimalOffsetAlignment, uint64_t(blockInfo.blockByteSize));
|
||||
|
||||
UploadHandle uploadHandle;
|
||||
DAWN_TRY_ASSIGN(uploadHandle, device->GetDynamicUploader()->Allocate(
|
||||
newDataSizeBytes + optimalOffsetAlignment - 1,
|
||||
device->GetPendingCommandSerial()));
|
||||
newDataSizeBytes, device->GetPendingCommandSerial(),
|
||||
offsetAlignment));
|
||||
ASSERT(uploadHandle.mappedBuffer != nullptr);
|
||||
|
||||
uint8_t* dstPointer = static_cast<uint8_t*>(uploadHandle.mappedBuffer);
|
||||
@ -64,11 +70,6 @@ namespace dawn_native { namespace vulkan {
|
||||
dataRowsPerImageInBlock = writeSizePixel.height / blockInfo.blockHeight;
|
||||
}
|
||||
|
||||
uint64_t additionalOffset =
|
||||
Align(uploadHandle.startOffset, optimalOffsetAlignment) - uploadHandle.startOffset;
|
||||
uploadHandle.startOffset += additionalOffset;
|
||||
dstPointer += additionalOffset;
|
||||
|
||||
ASSERT(dataRowsPerImageInBlock >= alignedRowsPerImageInBlock);
|
||||
uint64_t imageAdditionalStride =
|
||||
dataLayout.bytesPerRow * (dataRowsPerImageInBlock - alignedRowsPerImageInBlock);
|
||||
|
@ -951,7 +951,8 @@ namespace dawn_native { namespace vulkan {
|
||||
DynamicUploader* uploader = device->GetDynamicUploader();
|
||||
UploadHandle uploadHandle;
|
||||
DAWN_TRY_ASSIGN(uploadHandle,
|
||||
uploader->Allocate(bufferSize, device->GetPendingCommandSerial()));
|
||||
uploader->Allocate(bufferSize, device->GetPendingCommandSerial(),
|
||||
GetFormat().blockByteSize));
|
||||
memset(uploadHandle.mappedBuffer, clearColor, bufferSize);
|
||||
|
||||
// compute the buffer image copy to set the clear region of entire texture
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "tests/DawnTest.h"
|
||||
|
||||
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||
#include "utils/TestUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
#define EXPECT_LAZY_CLEAR(N, statement) \
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "common/Constants.h"
|
||||
#include "common/Math.h"
|
||||
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||
#include "utils/TestUtils.h"
|
||||
#include "utils/TextureFormatUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
@ -1066,6 +1067,35 @@ TEST_P(CompressedTextureBCFormatTest, CopyMultiple2DArrayLayers) {
|
||||
}
|
||||
}
|
||||
|
||||
// Testing a special code path: clearing a non-renderable texture when DynamicUploader
|
||||
// is unaligned doesn't throw validation errors.
|
||||
TEST_P(CompressedTextureBCFormatTest, UnalignedDynamicUploader) {
|
||||
// CopyT2B for compressed texture formats is unimplemented on OpenGL.
|
||||
DAWN_SKIP_TEST_IF(IsOpenGL());
|
||||
|
||||
utils::UnalignDynamicUploader(device);
|
||||
|
||||
wgpu::TextureDescriptor textureDescriptor = {};
|
||||
textureDescriptor.size = {4, 4, 1};
|
||||
textureDescriptor.format = wgpu::TextureFormat::BC1RGBAUnorm;
|
||||
textureDescriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
|
||||
|
||||
wgpu::BufferDescriptor bufferDescriptor;
|
||||
bufferDescriptor.size = 8;
|
||||
bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
|
||||
wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
|
||||
|
||||
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
|
||||
wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(buffer, 0, 256, 0);
|
||||
wgpu::Extent3D copyExtent = {4, 4, 1};
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, ©Extent);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
}
|
||||
|
||||
// TODO(jiawei.shao@intel.com): support BC formats on OpenGL backend
|
||||
DAWN_INSTANTIATE_TEST(CompressedTextureBCFormatTest,
|
||||
D3D12Backend(),
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <array>
|
||||
#include "common/Constants.h"
|
||||
#include "common/Math.h"
|
||||
#include "utils/TestUtils.h"
|
||||
#include "utils/TextureFormatUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "tests/DawnTest.h"
|
||||
|
||||
#include "common/Math.h"
|
||||
#include "utils/TestUtils.h"
|
||||
#include "utils/TextureFormatUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
@ -170,6 +171,22 @@ TEST_P(QueueWriteBufferTests, SuperLargeWriteBuffer) {
|
||||
EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), buffer, 0, kElements);
|
||||
}
|
||||
|
||||
// Test a special code path: writing when dynamic uploader already contatins some unaligned
|
||||
// data, it might be necessary to use a ring buffer with properly aligned offset.
|
||||
TEST_P(QueueWriteBufferTests, UnalignedDynamicUploader) {
|
||||
utils::UnalignDynamicUploader(device);
|
||||
|
||||
wgpu::BufferDescriptor descriptor;
|
||||
descriptor.size = 4;
|
||||
descriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
|
||||
wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
|
||||
|
||||
uint32_t value = 0x01020304;
|
||||
queue.WriteBuffer(buffer, 0, &value, sizeof(value));
|
||||
|
||||
EXPECT_BUFFER_U32_EQ(value, buffer, 0);
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(QueueWriteBufferTests,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
@ -522,4 +539,19 @@ TEST_P(QueueWriteTextureTests, VaryingArrayBytesPerRow) {
|
||||
}
|
||||
}
|
||||
|
||||
// Testing a special code path: writing when dynamic uploader already contatins some unaligned
|
||||
// data, it might be necessary to use a ring buffer with properly aligned offset.
|
||||
TEST_P(QueueWriteTextureTests, UnalignedDynamicUploader) {
|
||||
utils::UnalignDynamicUploader(device);
|
||||
|
||||
constexpr wgpu::Extent3D size = {10, 10, 1};
|
||||
|
||||
TextureSpec textureSpec;
|
||||
textureSpec.textureSize = size;
|
||||
textureSpec.copyOrigin = {0, 0, 0};
|
||||
textureSpec.level = 0;
|
||||
|
||||
DoTest(textureSpec, MinimumDataSpec(size), size);
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(QueueWriteTextureTests, D3D12Backend(), MetalBackend(), VulkanBackend());
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "common/Math.h"
|
||||
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||
#include "utils/TestUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
#define EXPECT_LAZY_CLEAR(N, statement) \
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "common/Constants.h"
|
||||
#include "common/Math.h"
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
#include "utils/TestUtils.h"
|
||||
#include "utils/TextureFormatUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
|
||||
#include "common/Math.h"
|
||||
#include "utils/TestUtils.h"
|
||||
#include "utils/TextureFormatUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
|
@ -75,6 +75,8 @@ static_library("dawn_utils") {
|
||||
"SystemUtils.h",
|
||||
"TerribleCommandBuffer.cpp",
|
||||
"TerribleCommandBuffer.h",
|
||||
"TestUtils.cpp",
|
||||
"TestUtils.h",
|
||||
"TextureFormatUtils.cpp",
|
||||
"TextureFormatUtils.h",
|
||||
"Timer.h",
|
||||
|
@ -27,6 +27,8 @@ target_sources(dawn_utils PRIVATE
|
||||
"SystemUtils.h"
|
||||
"TerribleCommandBuffer.cpp"
|
||||
"TerribleCommandBuffer.h"
|
||||
"TestUtils.cpp"
|
||||
"TestUtils.h"
|
||||
"TextureFormatUtils.cpp"
|
||||
"TextureFormatUtils.h"
|
||||
"Timer.h"
|
||||
|
107
src/utils/TestUtils.cpp
Normal file
107
src/utils/TestUtils.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright 2020 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "utils/TestUtils.h"
|
||||
|
||||
#include "common/Assert.h"
|
||||
#include "common/Constants.h"
|
||||
#include "common/Math.h"
|
||||
#include "utils/TextureFormatUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace utils {
|
||||
|
||||
uint32_t GetMinimumBytesPerRow(wgpu::TextureFormat format, uint32_t width) {
|
||||
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format);
|
||||
return Align(bytesPerTexel * width, kTextureBytesPerRowAlignment);
|
||||
}
|
||||
|
||||
uint32_t GetBytesInBufferTextureCopy(wgpu::TextureFormat format,
|
||||
uint32_t width,
|
||||
uint32_t bytesPerRow,
|
||||
uint32_t rowsPerImage,
|
||||
uint32_t copyArrayLayerCount) {
|
||||
ASSERT(rowsPerImage > 0);
|
||||
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format);
|
||||
const uint32_t bytesAtLastImage = bytesPerRow * (rowsPerImage - 1) + bytesPerTexel * width;
|
||||
return bytesPerRow * rowsPerImage * (copyArrayLayerCount - 1) + bytesAtLastImage;
|
||||
}
|
||||
|
||||
// TODO(jiawei.shao@intel.com): support compressed texture formats
|
||||
TextureDataCopyLayout GetTextureDataCopyLayoutForTexture2DAtLevel(
|
||||
wgpu::TextureFormat format,
|
||||
wgpu::Extent3D textureSizeAtLevel0,
|
||||
uint32_t mipmapLevel,
|
||||
uint32_t rowsPerImage) {
|
||||
TextureDataCopyLayout layout;
|
||||
|
||||
layout.mipSize = {textureSizeAtLevel0.width >> mipmapLevel,
|
||||
textureSizeAtLevel0.height >> mipmapLevel, textureSizeAtLevel0.depth};
|
||||
|
||||
layout.bytesPerRow = GetMinimumBytesPerRow(format, layout.mipSize.width);
|
||||
|
||||
uint32_t appliedRowsPerImage = rowsPerImage > 0 ? rowsPerImage : layout.mipSize.height;
|
||||
layout.bytesPerImage = layout.bytesPerRow * appliedRowsPerImage;
|
||||
|
||||
layout.byteLength =
|
||||
GetBytesInBufferTextureCopy(format, layout.mipSize.width, layout.bytesPerRow,
|
||||
appliedRowsPerImage, textureSizeAtLevel0.depth);
|
||||
|
||||
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format);
|
||||
layout.texelBlocksPerRow = layout.bytesPerRow / bytesPerTexel;
|
||||
layout.texelBlocksPerImage = layout.bytesPerImage / bytesPerTexel;
|
||||
layout.texelBlockCount = layout.byteLength / bytesPerTexel;
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
uint64_t RequiredBytesInCopy(uint64_t bytesPerRow,
|
||||
uint64_t rowsPerImage,
|
||||
wgpu::Extent3D copyExtent,
|
||||
wgpu::TextureFormat textureFormat) {
|
||||
if (copyExtent.width == 0 || copyExtent.height == 0 || copyExtent.depth == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
uint32_t blockSize = utils::GetTexelBlockSizeInBytes(textureFormat);
|
||||
uint32_t blockWidth = utils::GetTextureFormatBlockWidth(textureFormat);
|
||||
uint32_t blockHeight = utils::GetTextureFormatBlockHeight(textureFormat);
|
||||
|
||||
uint64_t texelBlockRowsPerImage = rowsPerImage / blockHeight;
|
||||
uint64_t bytesPerImage = bytesPerRow * texelBlockRowsPerImage;
|
||||
uint64_t bytesInLastSlice = bytesPerRow * (copyExtent.height / blockHeight - 1) +
|
||||
(copyExtent.width / blockWidth * blockSize);
|
||||
return bytesPerImage * (copyExtent.depth - 1) + bytesInLastSlice;
|
||||
}
|
||||
}
|
||||
|
||||
void UnalignDynamicUploader(wgpu::Device device) {
|
||||
std::vector<uint8_t> data = {1};
|
||||
|
||||
wgpu::TextureDescriptor descriptor = {};
|
||||
descriptor.size = {1, 1, 1};
|
||||
descriptor.format = wgpu::TextureFormat::R8Unorm;
|
||||
descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc;
|
||||
wgpu::Texture texture = device.CreateTexture(&descriptor);
|
||||
|
||||
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
|
||||
wgpu::TextureDataLayout textureDataLayout = utils::CreateTextureDataLayout(0, 0, 0);
|
||||
wgpu::Extent3D copyExtent = {1, 1, 1};
|
||||
|
||||
// WriteTexture with exactly 1 byte of data.
|
||||
device.GetDefaultQueue().WriteTexture(&textureCopyView, data.data(), 1, &textureDataLayout,
|
||||
©Extent);
|
||||
}
|
||||
} // namespace utils
|
57
src/utils/TestUtils.h
Normal file
57
src/utils/TestUtils.h
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2020 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef UTILS_TESTHELPERS_H_
|
||||
#define UTILS_TESTHELPERS_H_
|
||||
|
||||
#include <dawn/webgpu_cpp.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
struct TextureDataCopyLayout {
|
||||
uint64_t byteLength;
|
||||
uint64_t texelBlockCount;
|
||||
uint32_t bytesPerRow;
|
||||
uint32_t texelBlocksPerRow;
|
||||
uint32_t bytesPerImage;
|
||||
uint32_t texelBlocksPerImage;
|
||||
wgpu::Extent3D mipSize;
|
||||
};
|
||||
|
||||
uint32_t GetMinimumBytesPerRow(wgpu::TextureFormat format, uint32_t width);
|
||||
uint32_t GetBytesInBufferTextureCopy(wgpu::TextureFormat format,
|
||||
uint32_t width,
|
||||
uint32_t bytesPerRow,
|
||||
uint32_t rowsPerImage,
|
||||
uint32_t copyArrayLayerCount);
|
||||
TextureDataCopyLayout GetTextureDataCopyLayoutForTexture2DAtLevel(
|
||||
wgpu::TextureFormat format,
|
||||
wgpu::Extent3D textureSizeAtLevel0,
|
||||
uint32_t mipmapLevel,
|
||||
uint32_t rowsPerImage);
|
||||
|
||||
uint64_t RequiredBytesInCopy(uint64_t bytesPerRow,
|
||||
uint64_t rowsPerImage,
|
||||
wgpu::Extent3D copyExtent,
|
||||
wgpu::TextureFormat textureFormat);
|
||||
|
||||
// A helper function used for testing DynamicUploader offset alignment.
|
||||
// A call of this function will do a Queue::WriteTexture with 1 byte of data,
|
||||
// so that assuming that WriteTexture uses DynamicUploader, the first RingBuffer
|
||||
// in it will contain 1 byte of data.
|
||||
void UnalignDynamicUploader(wgpu::Device device);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // UTILS_TESTHELPERS_H_
|
@ -78,6 +78,15 @@ namespace utils {
|
||||
wgpu::TextureFormat::BC7RGBAUnormSrgb,
|
||||
};
|
||||
|
||||
static constexpr std::array<wgpu::TextureFormat, 14> kBCFormats = {
|
||||
wgpu::TextureFormat::BC1RGBAUnorm, wgpu::TextureFormat::BC1RGBAUnormSrgb,
|
||||
wgpu::TextureFormat::BC2RGBAUnorm, wgpu::TextureFormat::BC2RGBAUnormSrgb,
|
||||
wgpu::TextureFormat::BC3RGBAUnorm, wgpu::TextureFormat::BC3RGBAUnormSrgb,
|
||||
wgpu::TextureFormat::BC4RUnorm, wgpu::TextureFormat::BC4RSnorm,
|
||||
wgpu::TextureFormat::BC5RGUnorm, wgpu::TextureFormat::BC5RGSnorm,
|
||||
wgpu::TextureFormat::BC6HRGBUfloat, wgpu::TextureFormat::BC6HRGBSfloat,
|
||||
wgpu::TextureFormat::BC7RGBAUnorm, wgpu::TextureFormat::BC7RGBAUnormSrgb};
|
||||
|
||||
const char* GetColorTextureComponentTypePrefix(wgpu::TextureFormat textureFormat);
|
||||
bool TextureFormatSupportsStorageTexture(wgpu::TextureFormat format);
|
||||
|
||||
|
@ -14,11 +14,8 @@
|
||||
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
#include "common/Assert.h"
|
||||
#include "common/Constants.h"
|
||||
#include "common/Log.h"
|
||||
#include "common/Math.h"
|
||||
#include "utils/TextureFormatUtils.h"
|
||||
|
||||
#include <shaderc/shaderc.hpp>
|
||||
|
||||
@ -393,76 +390,4 @@ namespace utils {
|
||||
return device.CreateBindGroup(&descriptor);
|
||||
}
|
||||
|
||||
uint32_t GetMinimumBytesPerRow(wgpu::TextureFormat format, uint32_t width) {
|
||||
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format);
|
||||
return Align(bytesPerTexel * width, kTextureBytesPerRowAlignment);
|
||||
}
|
||||
|
||||
uint32_t GetBytesInBufferTextureCopy(wgpu::TextureFormat format,
|
||||
uint32_t width,
|
||||
uint32_t bytesPerRow,
|
||||
uint32_t rowsPerImage,
|
||||
uint32_t copyArrayLayerCount) {
|
||||
ASSERT(rowsPerImage > 0);
|
||||
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format);
|
||||
const uint32_t bytesAtLastImage = bytesPerRow * (rowsPerImage - 1) + bytesPerTexel * width;
|
||||
return bytesPerRow * rowsPerImage * (copyArrayLayerCount - 1) + bytesAtLastImage;
|
||||
}
|
||||
|
||||
// TODO(jiawei.shao@intel.com): support compressed texture formats
|
||||
TextureDataCopyLayout GetTextureDataCopyLayoutForTexture2DAtLevel(
|
||||
wgpu::TextureFormat format,
|
||||
wgpu::Extent3D textureSizeAtLevel0,
|
||||
uint32_t mipmapLevel,
|
||||
uint32_t rowsPerImage) {
|
||||
TextureDataCopyLayout layout;
|
||||
|
||||
layout.mipSize = {textureSizeAtLevel0.width >> mipmapLevel,
|
||||
textureSizeAtLevel0.height >> mipmapLevel, textureSizeAtLevel0.depth};
|
||||
|
||||
layout.bytesPerRow = GetMinimumBytesPerRow(format, layout.mipSize.width);
|
||||
|
||||
uint32_t appliedRowsPerImage = rowsPerImage > 0 ? rowsPerImage : layout.mipSize.height;
|
||||
layout.bytesPerImage = layout.bytesPerRow * appliedRowsPerImage;
|
||||
|
||||
layout.byteLength =
|
||||
GetBytesInBufferTextureCopy(format, layout.mipSize.width, layout.bytesPerRow,
|
||||
appliedRowsPerImage, textureSizeAtLevel0.depth);
|
||||
|
||||
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format);
|
||||
layout.texelBlocksPerRow = layout.bytesPerRow / bytesPerTexel;
|
||||
layout.texelBlocksPerImage = layout.bytesPerImage / bytesPerTexel;
|
||||
layout.texelBlockCount = layout.byteLength / bytesPerTexel;
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
const std::array<wgpu::TextureFormat, 14> kBCFormats = {
|
||||
wgpu::TextureFormat::BC1RGBAUnorm, wgpu::TextureFormat::BC1RGBAUnormSrgb,
|
||||
wgpu::TextureFormat::BC2RGBAUnorm, wgpu::TextureFormat::BC2RGBAUnormSrgb,
|
||||
wgpu::TextureFormat::BC3RGBAUnorm, wgpu::TextureFormat::BC3RGBAUnormSrgb,
|
||||
wgpu::TextureFormat::BC4RUnorm, wgpu::TextureFormat::BC4RSnorm,
|
||||
wgpu::TextureFormat::BC5RGUnorm, wgpu::TextureFormat::BC5RGSnorm,
|
||||
wgpu::TextureFormat::BC6HRGBUfloat, wgpu::TextureFormat::BC6HRGBSfloat,
|
||||
wgpu::TextureFormat::BC7RGBAUnorm, wgpu::TextureFormat::BC7RGBAUnormSrgb};
|
||||
|
||||
uint64_t RequiredBytesInCopy(uint64_t bytesPerRow,
|
||||
uint64_t rowsPerImage,
|
||||
wgpu::Extent3D copyExtent,
|
||||
wgpu::TextureFormat textureFormat) {
|
||||
if (copyExtent.width == 0 || copyExtent.height == 0 || copyExtent.depth == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
uint32_t blockSize = utils::GetTexelBlockSizeInBytes(textureFormat);
|
||||
uint32_t blockWidth = utils::GetTextureFormatBlockWidth(textureFormat);
|
||||
uint32_t blockHeight = utils::GetTextureFormatBlockHeight(textureFormat);
|
||||
|
||||
uint64_t texelBlockRowsPerImage = rowsPerImage / blockHeight;
|
||||
uint64_t bytesPerImage = bytesPerRow * texelBlockRowsPerImage;
|
||||
uint64_t bytesInLastSlice = bytesPerRow * (copyExtent.height / blockHeight - 1) +
|
||||
(copyExtent.width / blockWidth * blockSize);
|
||||
return bytesPerImage * (copyExtent.depth - 1) + bytesInLastSlice;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
@ -137,35 +137,6 @@ namespace utils {
|
||||
const wgpu::BindGroupLayout& layout,
|
||||
std::initializer_list<BindingInitializationHelper> entriesInitializer);
|
||||
|
||||
struct TextureDataCopyLayout {
|
||||
uint64_t byteLength;
|
||||
uint64_t texelBlockCount;
|
||||
uint32_t bytesPerRow;
|
||||
uint32_t texelBlocksPerRow;
|
||||
uint32_t bytesPerImage;
|
||||
uint32_t texelBlocksPerImage;
|
||||
wgpu::Extent3D mipSize;
|
||||
};
|
||||
|
||||
uint32_t GetMinimumBytesPerRow(wgpu::TextureFormat format, uint32_t width);
|
||||
uint32_t GetBytesInBufferTextureCopy(wgpu::TextureFormat format,
|
||||
uint32_t width,
|
||||
uint32_t bytesPerRow,
|
||||
uint32_t rowsPerImage,
|
||||
uint32_t copyArrayLayerCount);
|
||||
TextureDataCopyLayout GetTextureDataCopyLayoutForTexture2DAtLevel(
|
||||
wgpu::TextureFormat format,
|
||||
wgpu::Extent3D textureSizeAtLevel0,
|
||||
uint32_t mipmapLevel,
|
||||
uint32_t rowsPerImage);
|
||||
|
||||
extern const std::array<wgpu::TextureFormat, 14> kBCFormats;
|
||||
|
||||
uint64_t RequiredBytesInCopy(uint64_t bytesPerRow,
|
||||
uint64_t rowsPerImage,
|
||||
wgpu::Extent3D copyExtent,
|
||||
wgpu::TextureFormat textureFormat);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // UTILS_DAWNHELPERS_H_
|
||||
|
Loading…
x
Reference in New Issue
Block a user