Add texture copy tests
This commit is contained in:
parent
e5bd3e0ece
commit
b343e8d920
|
@ -60,6 +60,7 @@ add_executable(nxt_end2end_tests
|
|||
${END2END_TESTS_DIR}/BasicTests.cpp
|
||||
${END2END_TESTS_DIR}/BufferTests.cpp
|
||||
${END2END_TESTS_DIR}/InputStateTests.cpp
|
||||
${END2END_TESTS_DIR}/CopyTests.cpp
|
||||
${TESTS_DIR}/End2EndTestsMain.cpp
|
||||
${TESTS_DIR}/NXTTest.cpp
|
||||
${TESTS_DIR}/NXTTest.h
|
||||
|
|
|
@ -34,66 +34,4 @@ TEST_P(BasicTests, BufferSetSubData) {
|
|||
EXPECT_BUFFER_U32_EQ(value, buffer, 0);
|
||||
}
|
||||
|
||||
TEST_P(BasicTests, ReadPixelsTest) {
|
||||
RGBA8 red(255, 0, 0, 255);
|
||||
nxt::Buffer buffer = utils::CreateFrozenBufferFromData(device, &red, sizeof(red), nxt::BufferUsageBit::TransferSrc);
|
||||
|
||||
nxt::Texture texture = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(1, 1, 1)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::TransferSrc | nxt::TextureUsageBit::TransferDst)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.GetResult();
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.TransitionTextureUsage(texture, nxt::TextureUsageBit::TransferDst)
|
||||
.CopyBufferToTexture(buffer, 0, 256, texture, 0, 0, 0, 1, 1, 1, 0)
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(red, texture, 0, 0);
|
||||
}
|
||||
|
||||
TEST_P(BasicTests, Buffer2Texture2Buffer) {
|
||||
static constexpr unsigned int kSize = 64;
|
||||
|
||||
uint8_t data[4 * kSize * kSize] = {};
|
||||
for (unsigned int i = 0; i < 4 * kSize * kSize; ++i) {
|
||||
data[i] = i % 256;
|
||||
}
|
||||
|
||||
nxt::Buffer srcBuffer = utils::CreateFrozenBufferFromData(device, data, 4 * kSize * kSize, nxt::BufferUsageBit::TransferSrc);
|
||||
|
||||
nxt::Texture texture = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(kSize, kSize, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::TransferDst | nxt::TextureUsageBit::TransferSrc)
|
||||
.GetResult();
|
||||
|
||||
nxt::Buffer dstBuffer = device.CreateBufferBuilder()
|
||||
.SetAllowedUsage(nxt::BufferUsageBit::TransferDst | nxt::BufferUsageBit::TransferSrc)
|
||||
.SetInitialUsage(nxt::BufferUsageBit::TransferDst)
|
||||
.SetSize(4 * kSize * kSize)
|
||||
.GetResult();
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.TransitionTextureUsage(texture, nxt::TextureUsageBit::TransferDst)
|
||||
.CopyBufferToTexture(srcBuffer, 0, 0, texture, 0, 0, 0, kSize, kSize, 1, 0)
|
||||
|
||||
.TransitionTextureUsage(texture, nxt::TextureUsageBit::TransferSrc)
|
||||
.TransitionBufferUsage(dstBuffer, nxt::BufferUsageBit::TransferDst)
|
||||
.CopyTextureToBuffer(texture, 0, 0, 0, kSize, kSize, 1, 0, dstBuffer, 0, 0)
|
||||
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
const uint32_t* dataView = reinterpret_cast<uint32_t*>(data);
|
||||
EXPECT_BUFFER_U32_RANGE_EQ(dataView, dstBuffer, 0, kSize * kSize);
|
||||
}
|
||||
|
||||
NXT_INSTANTIATE_TEST(BasicTests, D3D12Backend, MetalBackend, OpenGLBackend)
|
||||
|
|
|
@ -0,0 +1,517 @@
|
|||
// Copyright 2017 The NXT 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 "tests/NXTTest.h"
|
||||
|
||||
#include <array>
|
||||
#include "common/Constants.h"
|
||||
#include "common/Math.h"
|
||||
#include "utils/NXTHelpers.h"
|
||||
|
||||
class CopyTests : public NXTTest {
|
||||
protected:
|
||||
static constexpr unsigned int kBytesPerTexel = 4;
|
||||
|
||||
struct TextureSpec {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t copyWidth;
|
||||
uint32_t copyHeight;
|
||||
uint32_t level;
|
||||
};
|
||||
|
||||
struct BufferSpec {
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
uint32_t rowPitch;
|
||||
};
|
||||
|
||||
BufferSpec MinimumBufferSpec(uint32_t width, uint32_t height) {
|
||||
uint32_t rowPitch = Align(width * kBytesPerTexel, kTextureRowPitchAlignment);
|
||||
return { rowPitch * (height - 1) + width * kBytesPerTexel, 0, rowPitch };
|
||||
}
|
||||
|
||||
static void PackTextureData(const RGBA8* srcData, uint32_t width, uint32_t height, uint32_t srcTexelsPerRow, RGBA8* dstData, uint32_t dstTexelsPerRow) {
|
||||
for (unsigned int y = 0; y < height; ++y) {
|
||||
for (unsigned int x = 0; x < width; ++x) {
|
||||
unsigned int src = x + y * srcTexelsPerRow;
|
||||
unsigned int dst = x + y * dstTexelsPerRow;
|
||||
dstData[dst] = srcData[src];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class CopyTests_T2B : public CopyTests {
|
||||
protected:
|
||||
static void FillTextureData(uint32_t width, uint32_t height, uint32_t texelsPerRow, RGBA8* data) {
|
||||
for (unsigned int y = 0; y < height; ++y) {
|
||||
for (unsigned int x = 0; x < width; ++x) {
|
||||
unsigned int i = x + y * texelsPerRow;
|
||||
data[i] = RGBA8(
|
||||
static_cast<uint8_t>(x % 256),
|
||||
static_cast<uint8_t>(y % 256),
|
||||
static_cast<uint8_t>(x / 256),
|
||||
static_cast<uint8_t>(y / 256));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoTest(const TextureSpec& textureSpec, const BufferSpec& bufferSpec) {
|
||||
// Create a texture that is `width` x `height` with (`level` + 1) mip levels.
|
||||
nxt::Texture texture = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(textureSpec.width, textureSpec.height, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(textureSpec.level + 1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::TransferDst | nxt::TextureUsageBit::TransferSrc)
|
||||
.GetResult();
|
||||
|
||||
uint32_t width = textureSpec.width >> textureSpec.level;
|
||||
uint32_t height = textureSpec.height >> textureSpec.level;
|
||||
uint32_t rowPitch = Align(kBytesPerTexel * width, kTextureRowPitchAlignment);
|
||||
uint32_t texelsPerRow = rowPitch / kBytesPerTexel;
|
||||
uint32_t texelCount = texelsPerRow * (height - 1) + width;
|
||||
|
||||
// Create an upload buffer and use it to populate the `level` mip of the texture
|
||||
std::vector<RGBA8> textureData(texelCount);
|
||||
FillTextureData(width, height, rowPitch / kBytesPerTexel, textureData.data());
|
||||
nxt::Buffer uploadBuffer = utils::CreateFrozenBufferFromData(device, textureData.data(), static_cast<uint32_t>(sizeof(RGBA8) * textureData.size()), nxt::BufferUsageBit::TransferSrc);
|
||||
|
||||
nxt::CommandBuffer commands[2];
|
||||
|
||||
commands[0] = device.CreateCommandBufferBuilder()
|
||||
.TransitionTextureUsage(texture, nxt::TextureUsageBit::TransferDst)
|
||||
.CopyBufferToTexture(uploadBuffer, 0, rowPitch, texture, 0, 0, 0, width, height, 1, textureSpec.level)
|
||||
.GetResult();
|
||||
|
||||
// Create a buffer of size `size` and populate it with empty data (0,0,0,0)
|
||||
// Note: Prepopulating the buffer with empty data ensures that there is not random data in the expectation
|
||||
// and helps ensure that the padding due to the row pitch is not modified by the copy
|
||||
nxt::Buffer buffer = device.CreateBufferBuilder()
|
||||
.SetSize(bufferSpec.size)
|
||||
.SetAllowedUsage(nxt::BufferUsageBit::TransferSrc | nxt::BufferUsageBit::TransferDst)
|
||||
.SetInitialUsage(nxt::BufferUsageBit::TransferDst)
|
||||
.GetResult();
|
||||
std::vector<RGBA8> emptyData(bufferSpec.size / kBytesPerTexel);
|
||||
buffer.SetSubData(0, static_cast<uint32_t>(emptyData.size()), reinterpret_cast<const uint32_t*>(emptyData.data()));
|
||||
|
||||
// Copy the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] from the `level` mip into the buffer at the specified `offset` and `rowPitch`
|
||||
commands[1] = device.CreateCommandBufferBuilder()
|
||||
.TransitionTextureUsage(texture, nxt::TextureUsageBit::TransferSrc)
|
||||
.TransitionBufferUsage(buffer, nxt::BufferUsageBit::TransferDst)
|
||||
.CopyTextureToBuffer(texture, textureSpec.x, textureSpec.y, 0, textureSpec.copyWidth, textureSpec.copyHeight, 1, textureSpec.level, buffer, bufferSpec.offset, bufferSpec.rowPitch)
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(2, commands);
|
||||
|
||||
// Pack the data used to create the upload buffer in the specified copy region to have the same format as the expected buffer data.
|
||||
std::vector<RGBA8> expected(bufferSpec.rowPitch / kBytesPerTexel * (textureSpec.copyHeight - 1) + textureSpec.copyWidth);
|
||||
PackTextureData(
|
||||
&textureData[textureSpec.x + textureSpec.y * (rowPitch / kBytesPerTexel)],
|
||||
textureSpec.copyWidth,
|
||||
textureSpec.copyHeight,
|
||||
rowPitch / kBytesPerTexel,
|
||||
expected.data(),
|
||||
bufferSpec.rowPitch / kBytesPerTexel);
|
||||
|
||||
EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<const uint32_t*>(expected.data()), buffer, bufferSpec.offset, static_cast<uint32_t>(expected.size())) <<
|
||||
"Texture to Buffer copy failed copying region [(" << textureSpec.x << ", " << textureSpec.y << "), (" << textureSpec.x + textureSpec.copyWidth << ", " << textureSpec.y + textureSpec.copyHeight <<
|
||||
")) from " << textureSpec.width << " x " << textureSpec.height << " texture at mip level " << textureSpec.level <<
|
||||
" to " << bufferSpec.size << "-byte buffer with offset " << bufferSpec.offset << " and row pitch " << bufferSpec.rowPitch << std::endl;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
class CopyTests_B2T : public CopyTests {
|
||||
protected:
|
||||
static void FillBufferData(RGBA8* data, size_t count) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
data[i] = RGBA8(
|
||||
static_cast<uint8_t>(i % 256),
|
||||
static_cast<uint8_t>((i / 256) % 256),
|
||||
static_cast<uint8_t>((i / 256 / 256) % 255),
|
||||
255);
|
||||
}
|
||||
}
|
||||
|
||||
void DoTest(const TextureSpec& textureSpec, const BufferSpec& bufferSpec) {
|
||||
// Create a buffer of size `size` and populate it with data
|
||||
nxt::Buffer buffer = device.CreateBufferBuilder()
|
||||
.SetSize(bufferSpec.size)
|
||||
.SetAllowedUsage(nxt::BufferUsageBit::TransferSrc | nxt::BufferUsageBit::TransferDst)
|
||||
.SetInitialUsage(nxt::BufferUsageBit::TransferDst)
|
||||
.GetResult();
|
||||
std::vector<RGBA8> bufferData(bufferSpec.size / kBytesPerTexel);
|
||||
FillBufferData(bufferData.data(), bufferData.size());
|
||||
buffer.SetSubData(0, static_cast<uint32_t>(bufferData.size()), reinterpret_cast<const uint32_t*>(bufferData.data()));
|
||||
|
||||
// Create a texture that is `width` x `height` with (`level` + 1) mip levels.
|
||||
nxt::Texture texture = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(textureSpec.width, textureSpec.height, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(textureSpec.level + 1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::TransferDst | nxt::TextureUsageBit::TransferSrc)
|
||||
.GetResult();
|
||||
|
||||
nxt::CommandBuffer commands[2];
|
||||
|
||||
// Create an upload buffer filled with empty data and use it to populate the `level` mip of the texture
|
||||
// Note: Prepopulating the texture with empty data ensures that there is not random data in the expectation
|
||||
// and helps ensure that the padding due to the row pitch is not modified by the copy
|
||||
{
|
||||
uint32_t width = textureSpec.width >> textureSpec.level;
|
||||
uint32_t height = textureSpec.height >> textureSpec.level;
|
||||
uint32_t rowPitch = Align(kBytesPerTexel * width, kTextureRowPitchAlignment);
|
||||
uint32_t texelsPerRow = rowPitch / kBytesPerTexel;
|
||||
uint32_t texelCount = texelsPerRow * (height - 1) + width;
|
||||
|
||||
std::vector<RGBA8> emptyData(texelCount);
|
||||
nxt::Buffer uploadBuffer = utils::CreateFrozenBufferFromData(device, emptyData.data(), static_cast<uint32_t>(sizeof(RGBA8) * emptyData.size()), nxt::BufferUsageBit::TransferSrc);
|
||||
|
||||
commands[0] = device.CreateCommandBufferBuilder()
|
||||
.TransitionTextureUsage(texture, nxt::TextureUsageBit::TransferDst)
|
||||
.CopyBufferToTexture(uploadBuffer, 0, rowPitch, texture, 0, 0, 0, width, height, 1, textureSpec.level)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Copy to the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] at the `level` mip from the buffer at the specified `offset` and `rowPitch`
|
||||
commands[1] = device.CreateCommandBufferBuilder()
|
||||
.TransitionBufferUsage(buffer, nxt::BufferUsageBit::TransferSrc)
|
||||
.TransitionTextureUsage(texture, nxt::TextureUsageBit::TransferDst)
|
||||
.CopyBufferToTexture(buffer, bufferSpec.offset, bufferSpec.rowPitch, texture, textureSpec.x, textureSpec.y, 0, textureSpec.copyWidth, textureSpec.copyHeight, 1, textureSpec.level)
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(2, commands);
|
||||
|
||||
// Pack the data used to create the buffer in the specified copy region to have the same format as the expected texture data.
|
||||
uint32_t rowPitch = Align(kBytesPerTexel * textureSpec.copyWidth, kTextureRowPitchAlignment);
|
||||
std::vector<RGBA8> expected(rowPitch / kBytesPerTexel * (textureSpec.copyHeight - 1) + textureSpec.copyWidth);
|
||||
PackTextureData(&bufferData[bufferSpec.offset / kBytesPerTexel], textureSpec.copyWidth, textureSpec.copyHeight, bufferSpec.rowPitch / kBytesPerTexel, expected.data(), textureSpec.copyWidth);
|
||||
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, textureSpec.x, textureSpec.y, textureSpec.copyWidth, textureSpec.copyHeight, textureSpec.level) <<
|
||||
"Buffer to Texture copy failed copying "
|
||||
<< bufferSpec.size << "-byte buffer with offset " << bufferSpec.offset << " and row pitch " << bufferSpec.rowPitch << " to [("
|
||||
<< textureSpec.x << ", " << textureSpec.y << "), (" << textureSpec.x + textureSpec.copyWidth << ", " << textureSpec.y + textureSpec.copyHeight <<
|
||||
")) region of " << textureSpec.width << " x " << textureSpec.height << " texture at mip level " << textureSpec.level << std::endl;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
// Test that copying an entire texture with 256-byte aligned dimensions works
|
||||
TEST_P(CopyTests_T2B, FullTextureAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, MinimumBufferSpec(kWidth, kHeight));
|
||||
}
|
||||
|
||||
// Test that copying an entire texture without 256-byte aligned dimensions works
|
||||
TEST_P(CopyTests_T2B, FullTextureUnaligned) {
|
||||
constexpr uint32_t kWidth = 259;
|
||||
constexpr uint32_t kHeight = 127;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, MinimumBufferSpec(kWidth, kHeight));
|
||||
}
|
||||
|
||||
// Test that reading pixels from a 256-byte aligned texture works
|
||||
TEST_P(CopyTests_T2B, PixelReadAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
BufferSpec pixelBuffer = MinimumBufferSpec(1, 1);
|
||||
DoTest({ kWidth, kHeight, 0, 0, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth - 1, 0, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, 0, kHeight - 1, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth - 1, kHeight - 1, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth / 3, kHeight / 7, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth / 7, kHeight / 3, 1, 1, 0 }, pixelBuffer);
|
||||
}
|
||||
|
||||
// Test that copying pixels from a texture that is not 256-byte aligned works
|
||||
TEST_P(CopyTests_T2B, PixelReadUnaligned) {
|
||||
constexpr uint32_t kWidth = 259;
|
||||
constexpr uint32_t kHeight = 127;
|
||||
BufferSpec pixelBuffer = MinimumBufferSpec(1, 1);
|
||||
DoTest({ kWidth, kHeight, 0, 0, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth - 1, 0, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, 0, kHeight - 1, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth - 1, kHeight - 1, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth / 3, kHeight / 7, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth / 7, kHeight / 3, 1, 1, 0 }, pixelBuffer);
|
||||
}
|
||||
|
||||
// Test that copying regions with 256-byte aligned sizes works
|
||||
TEST_P(CopyTests_T2B, TextureRegionAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (unsigned int w : {64, 128, 256}) {
|
||||
for (unsigned int h : { 16, 32, 48 }) {
|
||||
DoTest({ kWidth, kHeight, 0, 0, w, h, 0 }, MinimumBufferSpec(w, h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying regions without 256-byte aligned sizes works
|
||||
TEST_P(CopyTests_T2B, TextureRegionUnaligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (unsigned int w : {13, 63, 65}) {
|
||||
for (unsigned int h : { 17, 19, 63 }) {
|
||||
DoTest({ kWidth, kHeight, 0, 0, w, h, 0 }, MinimumBufferSpec(w, h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying mips with 256-byte aligned sizes works
|
||||
TEST_P(CopyTests_T2B, TextureMipAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (unsigned int i = 1; i < 4; ++i) {
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i }, MinimumBufferSpec(kWidth >> i, kHeight >> i));
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying mips without 256-byte aligned sizes works
|
||||
TEST_P(CopyTests_T2B, TextureMipUnaligned) {
|
||||
constexpr uint32_t kWidth = 259;
|
||||
constexpr uint32_t kHeight = 127;
|
||||
for (unsigned int i = 1; i < 4; ++i) {
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i }, MinimumBufferSpec(kWidth >> i, kHeight >> i));
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying with a 512-byte aligned buffer offset works
|
||||
TEST_P(CopyTests_T2B, OffsetBufferAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
|
||||
uint32_t offset = 512 * i;
|
||||
bufferSpec.size += offset;
|
||||
bufferSpec.offset += offset;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying without a 512-byte aligned buffer offset works
|
||||
TEST_P(CopyTests_T2B, OffsetBufferUnaligned) {
|
||||
if (IsD3D12()) {
|
||||
printf("TODO(enga@google.com): Test skipped because unaligned buffer offsets not supported in D3D12\n");
|
||||
return;
|
||||
}
|
||||
constexpr uint32_t kWidth = 128;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (uint32_t i = kBytesPerTexel; i < 512; i += kBytesPerTexel * 9) {
|
||||
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
|
||||
bufferSpec.size += i;
|
||||
bufferSpec.offset += i;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying without a 512-byte aligned buffer offset that is greater than the row pitch works
|
||||
TEST_P(CopyTests_T2B, OffsetBufferUnalignedSmallRowPitch) {
|
||||
if (IsD3D12()) {
|
||||
printf("TODO(enga@google.com): Test skipped because unaligned buffer offsets not supported in D3D12\n");
|
||||
return;
|
||||
}
|
||||
constexpr uint32_t kWidth = 32;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (uint32_t i = 256 + kBytesPerTexel; i < 512; i += kBytesPerTexel * 9) {
|
||||
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
|
||||
bufferSpec.size += i;
|
||||
bufferSpec.offset += i;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying with a greater row pitch than needed on a 256-byte aligned texture works
|
||||
TEST_P(CopyTests_T2B, RowPitchAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
|
||||
for (unsigned int i = 1; i < 4; ++i) {
|
||||
bufferSpec.rowPitch += 256;
|
||||
bufferSpec.size += 256 * kHeight;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying with a greater row pitch than needed on a texture that is not 256-byte aligned works
|
||||
TEST_P(CopyTests_T2B, RowPitchUnaligned) {
|
||||
constexpr uint32_t kWidth = 259;
|
||||
constexpr uint32_t kHeight = 127;
|
||||
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
|
||||
for (unsigned int i = 1; i < 4; ++i) {
|
||||
bufferSpec.rowPitch += 256;
|
||||
bufferSpec.size += 256 * kHeight;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec);
|
||||
}
|
||||
}
|
||||
|
||||
NXT_INSTANTIATE_TEST(CopyTests_T2B, D3D12Backend, MetalBackend, OpenGLBackend)
|
||||
|
||||
// Test that copying an entire texture with 256-byte aligned dimensions works
|
||||
TEST_P(CopyTests_B2T, FullTextureAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, MinimumBufferSpec(kWidth, kHeight));
|
||||
}
|
||||
|
||||
// Test that copying an entire texture without 256-byte aligned dimensions works
|
||||
TEST_P(CopyTests_B2T, FullTextureUnaligned) {
|
||||
constexpr uint32_t kWidth = 259;
|
||||
constexpr uint32_t kHeight = 127;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, MinimumBufferSpec(kWidth, kHeight));
|
||||
}
|
||||
|
||||
// Test that reading pixels from a 256-byte aligned texture works
|
||||
TEST_P(CopyTests_B2T, PixelReadAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
BufferSpec pixelBuffer = MinimumBufferSpec(1, 1);
|
||||
DoTest({ kWidth, kHeight, 0, 0, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth - 1, 0, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, 0, kHeight - 1, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth - 1, kHeight - 1, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth / 3, kHeight / 7, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth / 7, kHeight / 3, 1, 1, 0 }, pixelBuffer);
|
||||
}
|
||||
|
||||
// Test that copying pixels from a texture that is not 256-byte aligned works
|
||||
TEST_P(CopyTests_B2T, PixelReadUnaligned) {
|
||||
constexpr uint32_t kWidth = 259;
|
||||
constexpr uint32_t kHeight = 127;
|
||||
BufferSpec pixelBuffer = MinimumBufferSpec(1, 1);
|
||||
DoTest({ kWidth, kHeight, 0, 0, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth - 1, 0, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, 0, kHeight - 1, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth - 1, kHeight - 1, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth / 3, kHeight / 7, 1, 1, 0 }, pixelBuffer);
|
||||
DoTest({ kWidth, kHeight, kWidth / 7, kHeight / 3, 1, 1, 0 }, pixelBuffer);
|
||||
}
|
||||
|
||||
// Test that copying regions with 256-byte aligned sizes works
|
||||
TEST_P(CopyTests_B2T, TextureRegionAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (unsigned int w : {64, 128, 256}) {
|
||||
for (unsigned int h : { 16, 32, 48 }) {
|
||||
DoTest({ kWidth, kHeight, 0, 0, w, h, 0 }, MinimumBufferSpec(w, h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying regions without 256-byte aligned sizes works
|
||||
TEST_P(CopyTests_B2T, TextureRegionUnaligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (unsigned int w : {13, 63, 65}) {
|
||||
for (unsigned int h : { 17, 19, 63 }) {
|
||||
DoTest({ kWidth, kHeight, 0, 0, w, h, 0 }, MinimumBufferSpec(w, h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying mips with 256-byte aligned sizes works
|
||||
TEST_P(CopyTests_B2T, TextureMipAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (unsigned int i = 1; i < 4; ++i) {
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i }, MinimumBufferSpec(kWidth >> i, kHeight >> i));
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying mips without 256-byte aligned sizes works
|
||||
TEST_P(CopyTests_B2T, TextureMipUnaligned) {
|
||||
constexpr uint32_t kWidth = 259;
|
||||
constexpr uint32_t kHeight = 127;
|
||||
for (unsigned int i = 1; i < 4; ++i) {
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i }, MinimumBufferSpec(kWidth >> i, kHeight >> i));
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying with a 512-byte aligned buffer offset works
|
||||
TEST_P(CopyTests_B2T, OffsetBufferAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
|
||||
uint32_t offset = 512 * i;
|
||||
bufferSpec.size += offset;
|
||||
bufferSpec.offset += offset;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying without a 512-byte aligned buffer offset works
|
||||
TEST_P(CopyTests_B2T, OffsetBufferUnaligned) {
|
||||
if (IsD3D12()) {
|
||||
printf("TODO(enga@google.com): Test skipped because unaligned buffer offsets not supported in D3D12\n");
|
||||
return;
|
||||
}
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (uint32_t i = kBytesPerTexel; i < 512; i += kBytesPerTexel * 9) {
|
||||
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
|
||||
bufferSpec.size += i;
|
||||
bufferSpec.offset += i;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying without a 512-byte aligned buffer offset that is greater than the row pitch works
|
||||
TEST_P(CopyTests_B2T, OffsetBufferUnalignedSmallRowPitch) {
|
||||
if (IsD3D12()) {
|
||||
printf("TODO(enga@google.com): Test skipped because unaligned buffer offsets not supported in D3D12\n");
|
||||
return;
|
||||
}
|
||||
constexpr uint32_t kWidth = 32;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
for (uint32_t i = 256 + kBytesPerTexel; i < 512; i += kBytesPerTexel * 9) {
|
||||
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
|
||||
bufferSpec.size += i;
|
||||
bufferSpec.offset += i;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying with a greater row pitch than needed on a 256-byte aligned texture works
|
||||
TEST_P(CopyTests_B2T, RowPitchAligned) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
|
||||
for (unsigned int i = 1; i < 4; ++i) {
|
||||
bufferSpec.rowPitch += 256;
|
||||
bufferSpec.size += 256 * kHeight;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that copying with a greater row pitch than needed on a texture that is not 256-byte aligned works
|
||||
TEST_P(CopyTests_B2T, RowPitchUnaligned) {
|
||||
constexpr uint32_t kWidth = 259;
|
||||
constexpr uint32_t kHeight = 127;
|
||||
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight);
|
||||
for (unsigned int i = 1; i < 4; ++i) {
|
||||
bufferSpec.rowPitch += 256;
|
||||
bufferSpec.size += 256 * kHeight;
|
||||
DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec);
|
||||
}
|
||||
}
|
||||
|
||||
NXT_INSTANTIATE_TEST(CopyTests_B2T, D3D12Backend, MetalBackend, OpenGLBackend)
|
Loading…
Reference in New Issue