mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-17 21:01:37 +00:00
This patch fixes a Dawn crash issue when using textures in error state in the copy commands of CommandEncoder. In Dawn's copy commands (copyBufferToTexture and CopyTextureToBuffer), we should check if the texture is in error state or not, or the assert ASSERT(!IsError()) in texture->GetFormat() will fail and a crash will occur. In current Dawn code the validations on the buffer and texture objects in the copy commands are executed in CommandEncoder::Finish(), which is too late for textures according to the previous investigation. This patch moves all these validations to the call of copy commands. The checks on buffers are also moved away to keep the consistency of the ones on textures. BUG=chromium:937628 TEST=dawn_unittests Change-Id: I0bc44e76262fba5927df20c6a7551b107bad5ca1 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/5240 Reviewed-by: Kai Ninomiya <kainino@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
741 lines
33 KiB
C++
741 lines
33 KiB
C++
// Copyright 2017 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 "common/Constants.h"
|
|
#include "common/Math.h"
|
|
#include "tests/unittests/validation/ValidationTest.h"
|
|
#include "utils/DawnHelpers.h"
|
|
|
|
class CopyCommandTest : public ValidationTest {
|
|
protected:
|
|
dawn::Buffer CreateBuffer(uint32_t size, dawn::BufferUsageBit usage) {
|
|
dawn::BufferDescriptor descriptor;
|
|
descriptor.size = size;
|
|
descriptor.usage = usage;
|
|
|
|
return device.CreateBuffer(&descriptor);
|
|
}
|
|
|
|
dawn::Texture Create2DTexture(uint32_t width, uint32_t height, uint32_t mipLevelCount,
|
|
uint32_t arrayLayerCount, dawn::TextureFormat format,
|
|
dawn::TextureUsageBit usage, uint32_t sampleCount = 1) {
|
|
dawn::TextureDescriptor descriptor;
|
|
descriptor.dimension = dawn::TextureDimension::e2D;
|
|
descriptor.size.width = width;
|
|
descriptor.size.height = height;
|
|
descriptor.size.depth = 1;
|
|
descriptor.arrayLayerCount = arrayLayerCount;
|
|
descriptor.sampleCount = sampleCount;
|
|
descriptor.format = format;
|
|
descriptor.mipLevelCount = mipLevelCount;
|
|
descriptor.usage = usage;
|
|
dawn::Texture tex = device.CreateTexture(&descriptor);
|
|
return tex;
|
|
}
|
|
|
|
uint32_t BufferSizeForTextureCopy(uint32_t width, uint32_t height, uint32_t depth) {
|
|
uint32_t rowPitch = Align(width * 4, kTextureRowPitchAlignment);
|
|
return (rowPitch * (height - 1) + width) * depth;
|
|
}
|
|
|
|
void TestB2TCopy(utils::Expectation expectation,
|
|
dawn::Buffer srcBuffer,
|
|
uint32_t srcOffset,
|
|
uint32_t srcRowPitch,
|
|
uint32_t srcImageHeight,
|
|
dawn::Texture destTexture,
|
|
uint32_t destLevel,
|
|
uint32_t destSlice,
|
|
dawn::Origin3D destOrigin,
|
|
dawn::Extent3D extent3D) {
|
|
dawn::BufferCopyView bufferCopyView =
|
|
utils::CreateBufferCopyView(srcBuffer, srcOffset, srcRowPitch, srcImageHeight);
|
|
dawn::TextureCopyView textureCopyView =
|
|
utils::CreateTextureCopyView(destTexture, destLevel, destSlice, destOrigin);
|
|
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &extent3D);
|
|
|
|
if (expectation == utils::Expectation::Success) {
|
|
encoder.Finish();
|
|
} else {
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
}
|
|
|
|
void TestT2BCopy(utils::Expectation expectation,
|
|
dawn::Texture srcTexture,
|
|
uint32_t srcLevel,
|
|
uint32_t srcSlice,
|
|
dawn::Origin3D srcOrigin,
|
|
dawn::Buffer destBuffer,
|
|
uint32_t destOffset,
|
|
uint32_t destRowPitch,
|
|
uint32_t destImageHeight,
|
|
dawn::Extent3D extent3D) {
|
|
dawn::BufferCopyView bufferCopyView =
|
|
utils::CreateBufferCopyView(destBuffer, destOffset, destRowPitch, destImageHeight);
|
|
dawn::TextureCopyView textureCopyView =
|
|
utils::CreateTextureCopyView(srcTexture, srcLevel, srcSlice, srcOrigin);
|
|
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &extent3D);
|
|
|
|
if (expectation == utils::Expectation::Success) {
|
|
encoder.Finish();
|
|
} else {
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
}
|
|
};
|
|
|
|
class CopyCommandTest_B2B : public CopyCommandTest {
|
|
};
|
|
|
|
// TODO(cwallez@chromium.org): Test that copies are forbidden inside renderpasses
|
|
|
|
// Test a successfull B2B copy
|
|
TEST_F(CopyCommandTest_B2B, Success) {
|
|
dawn::Buffer source = CreateBuffer(16, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(16, dawn::BufferUsageBit::TransferDst);
|
|
|
|
// Copy different copies, including some that touch the OOB condition
|
|
{
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(source, 0, destination, 0, 16);
|
|
encoder.CopyBufferToBuffer(source, 8, destination, 0, 8);
|
|
encoder.CopyBufferToBuffer(source, 0, destination, 8, 8);
|
|
encoder.Finish();
|
|
}
|
|
|
|
// Empty copies are valid
|
|
{
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(source, 0, destination, 0, 0);
|
|
encoder.CopyBufferToBuffer(source, 0, destination, 16, 0);
|
|
encoder.CopyBufferToBuffer(source, 16, destination, 0, 0);
|
|
encoder.Finish();
|
|
}
|
|
}
|
|
|
|
// Test B2B copies with OOB
|
|
TEST_F(CopyCommandTest_B2B, OutOfBounds) {
|
|
dawn::Buffer source = CreateBuffer(16, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(16, dawn::BufferUsageBit::TransferDst);
|
|
|
|
// OOB on the source
|
|
{
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(source, 8, destination, 0, 12);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
|
|
// OOB on the destination
|
|
{
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(source, 0, destination, 8, 12);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
}
|
|
|
|
// Test B2B copies with incorrect buffer usage
|
|
TEST_F(CopyCommandTest_B2B, BadUsage) {
|
|
dawn::Buffer source = CreateBuffer(16, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(16, dawn::BufferUsageBit::TransferDst);
|
|
dawn::Buffer vertex = CreateBuffer(16, dawn::BufferUsageBit::Vertex);
|
|
|
|
// Source with incorrect usage
|
|
{
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(vertex, 0, destination, 0, 16);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
|
|
// Destination with incorrect usage
|
|
{
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(source, 0, vertex, 0, 16);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
}
|
|
|
|
// Test B2B copies with unaligned data size
|
|
TEST_F(CopyCommandTest_B2B, UnalignedSize) {
|
|
dawn::Buffer source = CreateBuffer(16, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(16, dawn::BufferUsageBit::TransferDst);
|
|
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(source, 8, destination, 0, sizeof(uint8_t));
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
|
|
// Test B2B copies with unaligned offset
|
|
TEST_F(CopyCommandTest_B2B, UnalignedOffset) {
|
|
dawn::Buffer source = CreateBuffer(16, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(16, dawn::BufferUsageBit::TransferDst);
|
|
|
|
// Unaligned source offset
|
|
{
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(source, 9, destination, 0, 4);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
|
|
// Unaligned destination offset
|
|
{
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(source, 8, destination, 1, 4);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
}
|
|
|
|
// Test B2B copies with buffers in error state cause errors.
|
|
TEST_F(CopyCommandTest_B2B, BuffersInErrorState) {
|
|
dawn::BufferDescriptor errorBufferDescriptor;
|
|
errorBufferDescriptor.size = 4;
|
|
errorBufferDescriptor.usage = dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::TransferSrc;
|
|
ASSERT_DEVICE_ERROR(dawn::Buffer errorBuffer = device.CreateBuffer(&errorBufferDescriptor));
|
|
|
|
constexpr uint32_t bufferSize = 4;
|
|
dawn::Buffer validBuffer = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
|
|
{
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(errorBuffer, 0, validBuffer, 0, 4);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
|
|
{
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToBuffer(validBuffer, 0, errorBuffer, 0, 4);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
}
|
|
|
|
class CopyCommandTest_B2T : public CopyCommandTest {
|
|
};
|
|
|
|
// Test a successfull B2T copy
|
|
TEST_F(CopyCommandTest_B2T, Success) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
|
|
// Different copies, including some that touch the OOB condition
|
|
{
|
|
// Copy 4x4 block in corner of first mip.
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, 0, {0, 0, 0},
|
|
{4, 4, 1});
|
|
// Copy 4x4 block in opposite corner of first mip.
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, 0, {12, 12, 0},
|
|
{4, 4, 1});
|
|
// Copy 4x4 block in the 4x4 mip.
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 2, 0, {0, 0, 0},
|
|
{4, 4, 1});
|
|
// Copy with a buffer offset
|
|
TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, 0, destination, 0, 0,
|
|
{0, 0, 0}, {1, 1, 1});
|
|
}
|
|
|
|
// Copies with a 256-byte aligned row pitch but unaligned texture region
|
|
{
|
|
// Unaligned region
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, 0, {0, 0, 0},
|
|
{3, 4, 1});
|
|
// Unaligned region with texture offset
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, 0, {5, 7, 0},
|
|
{2, 3, 1});
|
|
// Unaligned region, with buffer offset
|
|
TestB2TCopy(utils::Expectation::Success, source, 31 * 4, 256, 0, destination, 0, 0,
|
|
{0, 0, 0}, {3, 3, 1});
|
|
}
|
|
|
|
// Empty copies are valid
|
|
{
|
|
// An empty copy
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, 0, {0, 0, 0},
|
|
{0, 0, 1});
|
|
// An empty copy touching the end of the buffer
|
|
TestB2TCopy(utils::Expectation::Success, source, bufferSize, 0, 0, destination, 0, 0,
|
|
{0, 0, 0}, {0, 0, 1});
|
|
// An empty copy touching the side of the texture
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, 0, {16, 16, 0},
|
|
{0, 0, 1});
|
|
}
|
|
}
|
|
|
|
// Test OOB conditions on the buffer
|
|
TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
|
|
// OOB on the buffer because we copy too many pixels
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, 0, {0, 0, 0},
|
|
{4, 5, 1});
|
|
|
|
// OOB on the buffer because of the offset
|
|
TestB2TCopy(utils::Expectation::Failure, source, 4, 256, 0, destination, 0, 0, {0, 0, 0},
|
|
{4, 4, 1});
|
|
|
|
// OOB on the buffer because (row pitch * (height - 1) + width) * depth overflows
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 512, 0, destination, 0, 0, {0, 0, 0},
|
|
{4, 3, 1});
|
|
|
|
// Not OOB on the buffer although row pitch * height overflows
|
|
// but (row pitch * (height - 1) + width) * depth does not overlow
|
|
{
|
|
uint32_t sourceBufferSize = BufferSizeForTextureCopy(7, 3, 1);
|
|
ASSERT_TRUE(256 * 3 > sourceBufferSize) << "row pitch * height should overflow buffer";
|
|
dawn::Buffer sourceBuffer = CreateBuffer(sourceBufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, 0, {0, 0, 0},
|
|
{7, 3, 1});
|
|
}
|
|
}
|
|
|
|
// Test OOB conditions on the texture
|
|
TEST_F(CopyCommandTest_B2T, OutOfBoundsOnTexture) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Texture destination = Create2DTexture(16, 16, 5, 2, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
|
|
// OOB on the texture because x + width overflows
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, 0, {13, 12, 0},
|
|
{4, 4, 1});
|
|
|
|
// OOB on the texture because y + width overflows
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, 0, {12, 13, 0},
|
|
{4, 4, 1});
|
|
|
|
// OOB on the texture because we overflow a non-zero mip
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 2, 0, {1, 0, 0},
|
|
{4, 4, 1});
|
|
|
|
// OOB on the texture even on an empty copy when we copy to a non-existent mip.
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 0, destination, 5, 0, {0, 0, 0},
|
|
{0, 0, 1});
|
|
|
|
// OOB on the texture because slice overflows
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 0, destination, 0, 2, {0, 0, 0},
|
|
{0, 0, 1});
|
|
}
|
|
|
|
// Test that we force Z=0 and Depth=1 on copies to 2D textures
|
|
TEST_F(CopyCommandTest_B2T, ZDepthConstraintFor2DTextures) {
|
|
dawn::Buffer source = CreateBuffer(16 * 4, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
|
|
// Z=1 on an empty copy still errors
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 0, destination, 0, 0, {0, 0, 1},
|
|
{0, 0, 1});
|
|
|
|
// Depth=0 on an empty copy still errors
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 0, destination, 0, 0, {0, 0, 0},
|
|
{0, 0, 0});
|
|
}
|
|
|
|
// Test B2T copies with incorrect buffer usage
|
|
TEST_F(CopyCommandTest_B2T, IncorrectUsage) {
|
|
dawn::Buffer source = CreateBuffer(16 * 4, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Buffer vertex = CreateBuffer(16 * 4, dawn::BufferUsageBit::Vertex);
|
|
dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
dawn::Texture sampled = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::Sampled);
|
|
|
|
// Incorrect source usage
|
|
TestB2TCopy(utils::Expectation::Failure, vertex, 0, 256, 0, destination, 0, 0, {0, 0, 0},
|
|
{4, 4, 1});
|
|
|
|
// Incorrect destination usage
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, sampled, 0, 0, {0, 0, 0},
|
|
{4, 4, 1});
|
|
}
|
|
|
|
TEST_F(CopyCommandTest_B2T, IncorrectRowPitch) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
|
|
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Texture destination = Create2DTexture(128, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
|
|
// Default row pitch is not 256-byte aligned
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 0, destination, 0, 0, {0, 0, 0},
|
|
{3, 4, 1});
|
|
|
|
// Row pitch is not 256-byte aligned
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 128, 0, destination, 0, 0, {0, 0, 0},
|
|
{4, 4, 1});
|
|
|
|
// Row pitch is less than width * bytesPerPixel
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, 0, {0, 0, 0},
|
|
{65, 1, 1});
|
|
}
|
|
|
|
TEST_F(CopyCommandTest_B2T, ImageHeightConstraint) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(5, 5, 1);
|
|
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Texture destination = Create2DTexture(16, 16, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
|
|
// Image height is zero (Valid)
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, 0, {0, 0, 0},
|
|
{4, 4, 1});
|
|
|
|
// Image height is equal to copy height (Valid)
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, 0, {0, 0, 0},
|
|
{4, 4, 1});
|
|
|
|
// Image height is larger than copy height (Valid)
|
|
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, 0, {0, 0, 0},
|
|
{4, 4, 1});
|
|
|
|
// Image height is less than copy height (Invalid)
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 3, destination, 0, 0, {0, 0, 0},
|
|
{4, 4, 1});
|
|
}
|
|
|
|
// Test B2T copies with incorrect buffer offset usage
|
|
TEST_F(CopyCommandTest_B2T, IncorrectBufferOffset) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
|
|
// Correct usage
|
|
TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, 0, destination, 0, 0,
|
|
{0, 0, 0}, {1, 1, 1});
|
|
|
|
// Incorrect usages
|
|
{
|
|
TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 5, 256, 0, destination, 0, 0,
|
|
{0, 0, 0}, {1, 1, 1});
|
|
TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 6, 256, 0, destination, 0, 0,
|
|
{0, 0, 0}, {1, 1, 1});
|
|
TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 7, 256, 0, destination, 0, 0,
|
|
{0, 0, 0}, {1, 1, 1});
|
|
}
|
|
}
|
|
|
|
// Test multisampled textures cannot be used in B2T copies.
|
|
TEST_F(CopyCommandTest_B2T, CopyToMultisampledTexture) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(16, 16, 1);
|
|
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
dawn::Texture destination = Create2DTexture(2, 2, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst, 4);
|
|
|
|
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, 0, {0, 0, 0},
|
|
{2, 2, 1});
|
|
}
|
|
|
|
// Test B2T copies with buffer or texture in error state causes errors.
|
|
TEST_F(CopyCommandTest_B2T, BufferOrTextureInErrorState) {
|
|
dawn::BufferDescriptor errorBufferDescriptor;
|
|
errorBufferDescriptor.size = 4;
|
|
errorBufferDescriptor.usage = dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::TransferSrc;
|
|
ASSERT_DEVICE_ERROR(dawn::Buffer errorBuffer = device.CreateBuffer(&errorBufferDescriptor));
|
|
|
|
dawn::TextureDescriptor errorTextureDescriptor;
|
|
errorTextureDescriptor.arrayLayerCount = 0;
|
|
ASSERT_DEVICE_ERROR(dawn::Texture errorTexture = device.CreateTexture(&errorTextureDescriptor));
|
|
|
|
dawn::BufferCopyView errorBufferCopyView = utils::CreateBufferCopyView(errorBuffer, 0, 0, 0);
|
|
dawn::TextureCopyView errorTextureCopyView =
|
|
utils::CreateTextureCopyView(errorTexture, 0, 0, {1, 1, 1});
|
|
|
|
dawn::Extent3D extent3D = {1, 1, 1};
|
|
|
|
{
|
|
dawn::Texture destination =
|
|
Create2DTexture(16, 16, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
dawn::TextureCopyView textureCopyView =
|
|
utils::CreateTextureCopyView(destination, 0, 0, {1, 1, 1});
|
|
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToTexture(&errorBufferCopyView, &textureCopyView, &extent3D);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
|
|
{
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
|
|
dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(source, 0, 0, 0);
|
|
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToTexture(&bufferCopyView, &errorTextureCopyView, &extent3D);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
}
|
|
|
|
class CopyCommandTest_T2B : public CopyCommandTest {
|
|
};
|
|
|
|
// Test a successfull T2B copy
|
|
TEST_F(CopyCommandTest_T2B, Success) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
|
|
|
|
// Different copies, including some that touch the OOB condition
|
|
{
|
|
// Copy from 4x4 block in corner of first mip.
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destination, 0, 256, 0,
|
|
{4, 4, 1});
|
|
// Copy from 4x4 block in opposite corner of first mip.
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {12, 12, 0}, destination, 0, 256, 0,
|
|
{4, 4, 1});
|
|
// Copy from 4x4 block in the 4x4 mip.
|
|
TestT2BCopy(utils::Expectation::Success, source, 2, 0, {0, 0, 0}, destination, 0, 256, 0,
|
|
{4, 4, 1});
|
|
// Copy with a buffer offset
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destination,
|
|
bufferSize - 4, 256, 0, {1, 1, 1});
|
|
}
|
|
|
|
// Copies with a 256-byte aligned row pitch but unaligned texture region
|
|
{
|
|
// Unaligned region
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destination, 0, 256, 0,
|
|
{3, 4, 1});
|
|
// Unaligned region with texture offset
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {5, 7, 0}, destination, 0, 256, 0,
|
|
{2, 3, 1});
|
|
// Unaligned region, with buffer offset
|
|
TestT2BCopy(utils::Expectation::Success, source, 2, 0, {0, 0, 0}, destination, 31 * 4, 256,
|
|
0, {3, 3, 1});
|
|
}
|
|
|
|
// Empty copies are valid
|
|
{
|
|
// An empty copy
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destination, 0, 0, 0,
|
|
{0, 0, 1});
|
|
// An empty copy touching the end of the buffer
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destination, bufferSize,
|
|
0, 0, {0, 0, 1});
|
|
// An empty copy touching the side of the texture
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {16, 16, 0}, destination, 0, 0, 0,
|
|
{0, 0, 1});
|
|
}
|
|
}
|
|
|
|
// Test OOB conditions on the texture
|
|
TEST_F(CopyCommandTest_T2B, OutOfBoundsOnTexture) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
|
|
|
|
// OOB on the texture because x + width overflows
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {13, 12, 0}, destination, 0, 256, 0,
|
|
{4, 4, 1});
|
|
|
|
// OOB on the texture because y + width overflows
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {12, 13, 0}, destination, 0, 256, 0,
|
|
{4, 4, 1});
|
|
|
|
// OOB on the texture because we overflow a non-zero mip
|
|
TestT2BCopy(utils::Expectation::Failure, source, 2, 0, {1, 0, 0}, destination, 0, 256, 0,
|
|
{4, 4, 1});
|
|
|
|
// OOB on the texture even on an empty copy when we copy from a non-existent mip.
|
|
TestT2BCopy(utils::Expectation::Failure, source, 5, 0, {0, 0, 0}, destination, 0, 0, 0,
|
|
{0, 0, 1});
|
|
}
|
|
|
|
// Test OOB conditions on the buffer
|
|
TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
|
|
|
|
// OOB on the buffer because we copy too many pixels
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 256, 0,
|
|
{4, 5, 1});
|
|
|
|
// OOB on the buffer because of the offset
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 4, 256, 0,
|
|
{4, 4, 1});
|
|
|
|
// OOB on the buffer because (row pitch * (height - 1) + width) * depth overflows
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 512, 0,
|
|
{4, 3, 1});
|
|
|
|
// Not OOB on the buffer although row pitch * height overflows
|
|
// but (row pitch * (height - 1) + width) * depth does not overlow
|
|
{
|
|
uint32_t destinationBufferSize = BufferSizeForTextureCopy(7, 3, 1);
|
|
ASSERT_TRUE(256 * 3 > destinationBufferSize) << "row pitch * height should overflow buffer";
|
|
dawn::Buffer destinationBuffer = CreateBuffer(destinationBufferSize, dawn::BufferUsageBit::TransferDst);
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destinationBuffer, 0, 256,
|
|
0, {7, 3, 1});
|
|
}
|
|
}
|
|
|
|
// Test that we force Z=0 and Depth=1 on copies from to 2D textures
|
|
TEST_F(CopyCommandTest_T2B, ZDepthConstraintFor2DTextures) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
|
|
|
|
// Z=1 on an empty copy still errors
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 1}, destination, 0, 0, 0,
|
|
{0, 0, 1});
|
|
|
|
// Depth=0 on an empty copy still errors
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 0, 0,
|
|
{0, 0, 0});
|
|
}
|
|
|
|
// Test T2B copies with incorrect buffer usage
|
|
TEST_F(CopyCommandTest_T2B, IncorrectUsage) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferSrc);
|
|
dawn::Texture sampled = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::Sampled);
|
|
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
|
|
dawn::Buffer vertex = CreateBuffer(bufferSize, dawn::BufferUsageBit::Vertex);
|
|
|
|
// Incorrect source usage
|
|
TestT2BCopy(utils::Expectation::Failure, sampled, 0, 0, {0, 0, 0}, destination, 0, 256, 0,
|
|
{4, 4, 1});
|
|
|
|
// Incorrect destination usage
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, vertex, 0, 256, 0, {4, 4, 1});
|
|
}
|
|
|
|
TEST_F(CopyCommandTest_T2B, IncorrectRowPitch) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
|
|
dawn::Texture source = Create2DTexture(128, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
|
|
// Default row pitch is not 256-byte aligned
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 256, 0,
|
|
{3, 4, 1});
|
|
|
|
// Row pitch is not 256-byte aligned
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 257, 0,
|
|
{4, 4, 1});
|
|
|
|
// Row pitch is less than width * bytesPerPixel
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 256, 0,
|
|
{65, 1, 1});
|
|
}
|
|
|
|
TEST_F(CopyCommandTest_T2B, ImageHeightConstraint) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(5, 5, 1);
|
|
dawn::Texture source = Create2DTexture(16, 16, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
|
|
|
|
// Image height is zero (Valid)
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destination, 0, 256, 0,
|
|
{4, 4, 1});
|
|
|
|
// Image height is equal to copy height (Valid)
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destination, 0, 256, 4,
|
|
{4, 4, 1});
|
|
|
|
// Image height exceeds copy height (Valid)
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destination, 0, 256, 5,
|
|
{4, 4, 1});
|
|
|
|
// Image height is less than copy height (Invalid)
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 256, 3,
|
|
{4, 4, 1});
|
|
}
|
|
|
|
// Test T2B copies with incorrect buffer offset usage
|
|
TEST_F(CopyCommandTest_T2B, IncorrectBufferOffset) {
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
|
|
dawn::Texture source = Create2DTexture(128, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferSrc);
|
|
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
|
|
|
|
// Correct usage
|
|
TestT2BCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destination, bufferSize - 4,
|
|
256, 0, {1, 1, 1});
|
|
|
|
// Incorrect usages
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, bufferSize - 5,
|
|
256, 0, {1, 1, 1});
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, bufferSize - 6,
|
|
256, 0, {1, 1, 1});
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, bufferSize - 7,
|
|
256, 0, {1, 1, 1});
|
|
}
|
|
|
|
// Test multisampled textures cannot be used in T2B copies.
|
|
TEST_F(CopyCommandTest_T2B, CopyFromMultisampledTexture) {
|
|
dawn::Texture source = Create2DTexture(2, 2, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferSrc, 4);
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(16, 16, 1);
|
|
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
|
|
|
|
TestT2BCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 256, 0,
|
|
{2, 2, 1});
|
|
}
|
|
|
|
// Test T2B copies with buffer or texture in error state cause errors.
|
|
TEST_F(CopyCommandTest_T2B, BufferOrTextureInErrorState) {
|
|
dawn::BufferDescriptor errorBufferDescriptor;
|
|
errorBufferDescriptor.size = 4;
|
|
errorBufferDescriptor.usage = dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::TransferSrc;
|
|
ASSERT_DEVICE_ERROR(dawn::Buffer errorBuffer = device.CreateBuffer(&errorBufferDescriptor));
|
|
|
|
dawn::TextureDescriptor errorTextureDescriptor;
|
|
errorTextureDescriptor.arrayLayerCount = 0;
|
|
ASSERT_DEVICE_ERROR(dawn::Texture errorTexture = device.CreateTexture(&errorTextureDescriptor));
|
|
|
|
dawn::BufferCopyView errorBufferCopyView = utils::CreateBufferCopyView(errorBuffer, 0, 0, 0);
|
|
dawn::TextureCopyView errorTextureCopyView =
|
|
utils::CreateTextureCopyView(errorTexture, 0, 0, {1, 1, 1});
|
|
|
|
dawn::Extent3D extent3D = {1, 1, 1};
|
|
|
|
{
|
|
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
|
|
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
|
|
|
|
dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(source, 0, 0, 0);
|
|
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyTextureToBuffer(&errorTextureCopyView, &bufferCopyView, &extent3D);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
|
|
{
|
|
dawn::Texture destination =
|
|
Create2DTexture(16, 16, 1, 1, dawn::TextureFormat::R8G8B8A8Unorm,
|
|
dawn::TextureUsageBit::TransferDst);
|
|
dawn::TextureCopyView textureCopyView =
|
|
utils::CreateTextureCopyView(destination, 0, 0, {1, 1, 1});
|
|
|
|
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyTextureToBuffer(&textureCopyView, &errorBufferCopyView, &extent3D);
|
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
|
}
|
|
}
|