dawn-cmake/src/utils/TestUtils.cpp
Austin Eng ddd0a0a856 Initialize padding on buffer allocations
Buffer allocations in Dawn may be padded. This padding
could be visible, depending on how the backend
implements robust vertex buffer access. This commit
updates buffer creation to clear all padding bytes
immediately after creation.
It is not counted as a lazy clear.
And, add a test which reads off the end of a padded
vertex buffer to check that the padding bytes are also
initialized.

Also: Update Metal buffers to always allocate enough
space for Tint's vertex pulling, and pass the full
allocated size to Tint. While writing the test in this
commit, a bug was found where Tint assumes there is at
least 4 bytes in the vertex pulling buffer. The WebGPU
API currently allows zero-sized bindings, so Dawn needs
to always allocate enough space for one element.

Also: Update Vulkan vertex/index buffers to allocate
at least one more byte than requested because
vkCmdSetVertexBuffers and vkCmdSetIndexBuffer disallow
the offset to be equal to the buffer size. We need
at least one more byte to make zero-sized bindings
as the end of the buffer valid.

Lastly: Update helper so that a T2B copy of a single
row that touches all bytes in a buffer updates the
buffer state to be fully initialized. This is a small
optimization that is necessary to write the test.

Bug: dawn:837
Change-Id: I829f4764509c4ec784c5aeaaf40b6dcbd4be6866
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/62161
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
2021-08-19 18:02:36 +00:00

181 lines
7.5 KiB
C++

// 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/TextureUtils.h"
#include "utils/WGPUHelpers.h"
#include <vector>
namespace utils {
uint32_t GetMinimumBytesPerRow(wgpu::TextureFormat format, uint32_t width) {
const uint32_t bytesPerBlock = utils::GetTexelBlockSizeInBytes(format);
const uint32_t blockWidth = utils::GetTextureFormatBlockWidth(format);
ASSERT(width % blockWidth == 0);
return Align(bytesPerBlock * (width / blockWidth), kTextureBytesPerRowAlignment);
}
TextureDataCopyLayout GetTextureDataCopyLayoutForTextureAtLevel(
wgpu::TextureFormat format,
wgpu::Extent3D textureSizeAtLevel0,
uint32_t mipmapLevel,
wgpu::TextureDimension dimension,
uint32_t rowsPerImage) {
// Compressed texture formats not supported in this function yet.
ASSERT(utils::GetTextureFormatBlockWidth(format) == 1);
TextureDataCopyLayout layout;
layout.mipSize = {std::max(textureSizeAtLevel0.width >> mipmapLevel, 1u),
std::max(textureSizeAtLevel0.height >> mipmapLevel, 1u),
textureSizeAtLevel0.depthOrArrayLayers};
if (dimension == wgpu::TextureDimension::e3D) {
layout.mipSize.depthOrArrayLayers =
std::max(textureSizeAtLevel0.depthOrArrayLayers >> mipmapLevel, 1u);
}
layout.bytesPerRow = GetMinimumBytesPerRow(format, layout.mipSize.width);
if (rowsPerImage == wgpu::kCopyStrideUndefined) {
rowsPerImage = layout.mipSize.height;
}
layout.rowsPerImage = rowsPerImage;
uint32_t appliedRowsPerImage = rowsPerImage > 0 ? rowsPerImage : layout.mipSize.height;
layout.bytesPerImage = layout.bytesPerRow * appliedRowsPerImage;
layout.byteLength =
RequiredBytesInCopy(layout.bytesPerRow, appliedRowsPerImage, layout.mipSize, format);
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) {
uint32_t blockSize = utils::GetTexelBlockSizeInBytes(textureFormat);
uint32_t blockWidth = utils::GetTextureFormatBlockWidth(textureFormat);
uint32_t blockHeight = utils::GetTextureFormatBlockHeight(textureFormat);
ASSERT(copyExtent.width % blockWidth == 0);
uint32_t widthInBlocks = copyExtent.width / blockWidth;
ASSERT(copyExtent.height % blockHeight == 0);
uint32_t heightInBlocks = copyExtent.height / blockHeight;
return RequiredBytesInCopy(bytesPerRow, rowsPerImage, widthInBlocks, heightInBlocks,
copyExtent.depthOrArrayLayers, blockSize);
}
uint64_t RequiredBytesInCopy(uint64_t bytesPerRow,
uint64_t rowsPerImage,
uint64_t widthInBlocks,
uint64_t heightInBlocks,
uint64_t depth,
uint64_t bytesPerBlock) {
if (depth == 0) {
return 0;
}
uint64_t bytesPerImage = bytesPerRow * rowsPerImage;
uint64_t requiredBytesInCopy = bytesPerImage * (depth - 1);
if (heightInBlocks != 0) {
uint64_t lastRowBytes = widthInBlocks * bytesPerBlock;
uint64_t lastImageBytes = bytesPerRow * (heightInBlocks - 1) + lastRowBytes;
requiredBytesInCopy += lastImageBytes;
}
return requiredBytesInCopy;
}
uint64_t GetTexelCountInCopyRegion(uint64_t bytesPerRow,
uint64_t rowsPerImage,
wgpu::Extent3D copyExtent,
wgpu::TextureFormat textureFormat) {
return RequiredBytesInCopy(bytesPerRow, rowsPerImage, copyExtent, textureFormat) /
utils::GetTexelBlockSizeInBytes(textureFormat);
}
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::ImageCopyTexture imageCopyTexture =
utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
wgpu::TextureDataLayout textureDataLayout =
utils::CreateTextureDataLayout(0, wgpu::kCopyStrideUndefined);
wgpu::Extent3D copyExtent = {1, 1, 1};
// WriteTexture with exactly 1 byte of data.
device.GetQueue().WriteTexture(&imageCopyTexture, data.data(), 1, &textureDataLayout,
&copyExtent);
}
uint32_t VertexFormatSize(wgpu::VertexFormat format) {
switch (format) {
case wgpu::VertexFormat::Uint8x2:
case wgpu::VertexFormat::Sint8x2:
case wgpu::VertexFormat::Unorm8x2:
case wgpu::VertexFormat::Snorm8x2:
return 2;
case wgpu::VertexFormat::Uint8x4:
case wgpu::VertexFormat::Sint8x4:
case wgpu::VertexFormat::Unorm8x4:
case wgpu::VertexFormat::Snorm8x4:
case wgpu::VertexFormat::Uint16x2:
case wgpu::VertexFormat::Sint16x2:
case wgpu::VertexFormat::Unorm16x2:
case wgpu::VertexFormat::Snorm16x2:
case wgpu::VertexFormat::Float16x2:
case wgpu::VertexFormat::Float32:
case wgpu::VertexFormat::Uint32:
case wgpu::VertexFormat::Sint32:
return 4;
case wgpu::VertexFormat::Uint16x4:
case wgpu::VertexFormat::Sint16x4:
case wgpu::VertexFormat::Unorm16x4:
case wgpu::VertexFormat::Snorm16x4:
case wgpu::VertexFormat::Float16x4:
case wgpu::VertexFormat::Float32x2:
case wgpu::VertexFormat::Uint32x2:
case wgpu::VertexFormat::Sint32x2:
return 8;
case wgpu::VertexFormat::Float32x3:
case wgpu::VertexFormat::Uint32x3:
case wgpu::VertexFormat::Sint32x3:
return 12;
case wgpu::VertexFormat::Float32x4:
case wgpu::VertexFormat::Uint32x4:
case wgpu::VertexFormat::Sint32x4:
return 16;
case wgpu::VertexFormat::Undefined:
UNREACHABLE();
}
}
} // namespace utils