Update tests and examples to follow copy row pitch alignment constraints

This commit is contained in:
Austin Eng 2017-07-13 13:50:16 -04:00 committed by Austin Eng
parent 3f47729df6
commit 972a1e59a7
3 changed files with 65 additions and 29 deletions

View File

@ -21,6 +21,8 @@
#include "SampleUtils.h" #include "SampleUtils.h"
#include "utils/NXTHelpers.h" #include "utils/NXTHelpers.h"
#include "common/Math.h"
#include "common/Constants.h"
#include <bitset> #include <bitset>
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
@ -410,29 +412,48 @@ namespace {
.GetResult(); .GetResult();
// TODO: release this texture // TODO: release this texture
uint32_t numPixels = iImage.width * iImage.height;
const uint8_t* origData = iImage.image.data(); const uint8_t* origData = iImage.image.data();
const uint8_t* data = nullptr; const uint8_t* data = nullptr;
std::vector<uint8_t> newData; std::vector<uint8_t> newData;
uint32_t width = static_cast<uint32_t>(iImage.width);
uint32_t height = static_cast<uint32_t>(iImage.height);
uint32_t rowSize = width * 4;
uint32_t rowPitch = Align(rowSize, kTextureRowPitchAlignment);
if (iImage.component == 3 || iImage.component == 4) {
if (rowSize != rowPitch || iImage.component == 3) {
newData.resize(rowPitch * height);
uint32_t pixelsPerRow = rowPitch / 4;
for (uint32_t y = 0; y < height; ++y) {
for (uint32_t x = 0; x < width; ++x) {
size_t oldIndex = x + y * height;
size_t newIndex = x + y * pixelsPerRow;
if (iImage.component == 4) { if (iImage.component == 4) {
data = origData; newData[4 * newIndex + 0] = origData[4 * oldIndex + 0];
newData[4 * newIndex + 1] = origData[4 * oldIndex + 1];
newData[4 * newIndex + 2] = origData[4 * oldIndex + 2];
newData[4 * newIndex + 3] = origData[4 * oldIndex + 3];
} else if (iImage.component == 3) { } else if (iImage.component == 3) {
newData.resize(numPixels * 4); newData[4 * newIndex + 0] = origData[3 * oldIndex + 0];
for (size_t i = 0; i < numPixels; ++i) { newData[4 * newIndex + 1] = origData[3 * oldIndex + 1];
newData[4 * i + 0] = origData[3 * i + 0]; newData[4 * newIndex + 2] = origData[3 * oldIndex + 2];
newData[4 * i + 1] = origData[3 * i + 1]; newData[4 * newIndex + 3] = 255;
newData[4 * i + 2] = origData[3 * i + 2]; }
newData[4 * i + 3] = 255; }
} }
data = newData.data(); data = newData.data();
} else {
data = origData;
}
} else { } else {
fprintf(stderr, "unsupported image.component %d\n", iImage.component); fprintf(stderr, "unsupported image.component %d\n", iImage.component);
} }
nxt::Buffer staging = utils::CreateFrozenBufferFromData(device, data, numPixels * 4, nxt::BufferUsageBit::TransferSrc); nxt::Buffer staging = utils::CreateFrozenBufferFromData(device, data, rowPitch * iImage.height, nxt::BufferUsageBit::TransferSrc);
auto cmdbuf = device.CreateCommandBufferBuilder() auto cmdbuf = device.CreateCommandBufferBuilder()
.TransitionTextureUsage(oTexture, nxt::TextureUsageBit::TransferDst) .TransitionTextureUsage(oTexture, nxt::TextureUsageBit::TransferDst)
.CopyBufferToTexture(staging, 0, 0, oTexture, 0, 0, 0, iImage.width, iImage.height, 1, 0) .CopyBufferToTexture(staging, 0, rowPitch, oTexture, 0, 0, 0, iImage.width, iImage.height, 1, 0)
.GetResult(); .GetResult();
queue.Submit(1, &cmdbuf); queue.Submit(1, &cmdbuf);
oTexture.FreezeUsage(nxt::TextureUsageBit::Sampled); oTexture.FreezeUsage(nxt::TextureUsageBit::Sampled);

View File

@ -48,7 +48,7 @@ TEST_P(BasicTests, ReadPixelsTest) {
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.TransitionTextureUsage(texture, nxt::TextureUsageBit::TransferDst) .TransitionTextureUsage(texture, nxt::TextureUsageBit::TransferDst)
.CopyBufferToTexture(buffer, 0, 0, texture, 0, 0, 0, 1, 1, 1, 0) .CopyBufferToTexture(buffer, 0, 256, texture, 0, 0, 0, 1, 1, 1, 0)
.GetResult(); .GetResult();
queue.Submit(1, &commands); queue.Submit(1, &commands);

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "common/Constants.h"
#include "common/Math.h"
#include "tests/unittests/validation/ValidationTest.h" #include "tests/unittests/validation/ValidationTest.h"
class CopyCommandTest : public ValidationTest { class CopyCommandTest : public ValidationTest {
@ -37,6 +39,11 @@ class CopyCommandTest : public ValidationTest {
tex.FreezeUsage(usage); tex.FreezeUsage(usage);
return tex; 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;
}
}; };
class CopyCommandTest_B2B : public CopyCommandTest { class CopyCommandTest_B2B : public CopyCommandTest {
@ -114,7 +121,8 @@ class CopyCommandTest_B2T : public CopyCommandTest {
// Test a successfull B2T copy // Test a successfull B2T copy
TEST_F(CopyCommandTest_B2T, Success) { TEST_F(CopyCommandTest_B2T, Success) {
nxt::Buffer source = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::TransferSrc); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
nxt::Buffer source = CreateFrozenBuffer(bufferSize, nxt::BufferUsageBit::TransferSrc);
nxt::Texture destination = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm, nxt::Texture destination = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm,
nxt::TextureUsageBit::TransferDst); nxt::TextureUsageBit::TransferDst);
@ -128,7 +136,7 @@ TEST_F(CopyCommandTest_B2T, Success) {
// Copy 4x4 block in the 4x4 mip. // Copy 4x4 block in the 4x4 mip.
.CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 4, 4, 1, 2) .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 4, 4, 1, 2)
// Copy with a buffer offset // Copy with a buffer offset
.CopyBufferToTexture(source, 15 * 4, 0, destination, 0, 0, 0, 1, 1, 1, 4) .CopyBufferToTexture(source, bufferSize - 4, 0, destination, 0, 0, 0, 1, 1, 1, 4)
.GetResult(); .GetResult();
} }
@ -138,7 +146,7 @@ TEST_F(CopyCommandTest_B2T, Success) {
// An empty copy // An empty copy
.CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 0) .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 0)
// An empty copy touching the end of the buffer // An empty copy touching the end of the buffer
.CopyBufferToTexture(source, 16 * 4, 0, destination, 0, 0, 0, 0, 0, 1, 0) .CopyBufferToTexture(source, bufferSize, 0, destination, 0, 0, 0, 0, 0, 1, 0)
// An empty copy touching the side of the texture // An empty copy touching the side of the texture
.CopyBufferToTexture(source, 0, 0, destination, 16, 16, 0, 0, 0, 1, 0) .CopyBufferToTexture(source, 0, 0, destination, 16, 16, 0, 0, 0, 1, 0)
.GetResult(); .GetResult();
@ -147,7 +155,8 @@ TEST_F(CopyCommandTest_B2T, Success) {
// Test OOB conditions on the buffer // Test OOB conditions on the buffer
TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) { TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) {
nxt::Buffer source = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::TransferSrc); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
nxt::Buffer source = CreateFrozenBuffer(bufferSize, nxt::BufferUsageBit::TransferSrc);
nxt::Texture destination = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm, nxt::Texture destination = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm,
nxt::TextureUsageBit::TransferDst); nxt::TextureUsageBit::TransferDst);
@ -168,7 +177,8 @@ TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) {
// Test OOB conditions on the texture // Test OOB conditions on the texture
TEST_F(CopyCommandTest_B2T, OutOfBoundsOnTexture) { TEST_F(CopyCommandTest_B2T, OutOfBoundsOnTexture) {
nxt::Buffer source = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::TransferSrc); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
nxt::Buffer source = CreateFrozenBuffer(bufferSize, nxt::BufferUsageBit::TransferSrc);
nxt::Texture destination = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm, nxt::Texture destination = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm,
nxt::TextureUsageBit::TransferDst); nxt::TextureUsageBit::TransferDst);
@ -222,7 +232,7 @@ TEST_F(CopyCommandTest_B2T, ZDepthConstraintFor2DTextures) {
} }
} }
// Test B2B copies with incorrect buffer usage // Test B2T copies with incorrect buffer usage
TEST_F(CopyCommandTest_B2T, IncorrectUsage) { TEST_F(CopyCommandTest_B2T, IncorrectUsage) {
nxt::Buffer source = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::TransferSrc); nxt::Buffer source = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::TransferSrc);
nxt::Buffer vertex = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::Vertex); nxt::Buffer vertex = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::Vertex);
@ -251,9 +261,10 @@ class CopyCommandTest_T2B : public CopyCommandTest {
// Test a successfull T2B copy // Test a successfull T2B copy
TEST_F(CopyCommandTest_T2B, Success) { TEST_F(CopyCommandTest_T2B, Success) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
nxt::Texture source = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm, nxt::Texture source = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm,
nxt::TextureUsageBit::TransferSrc); nxt::TextureUsageBit::TransferSrc);
nxt::Buffer destination = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::TransferDst); nxt::Buffer destination = CreateFrozenBuffer(bufferSize, nxt::BufferUsageBit::TransferDst);
// Different copies, including some that touch the OOB condition // Different copies, including some that touch the OOB condition
{ {
@ -265,7 +276,7 @@ TEST_F(CopyCommandTest_T2B, Success) {
// Copy from 4x4 block in the 4x4 mip. // Copy from 4x4 block in the 4x4 mip.
.CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 2, destination, 0, 0) .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 2, destination, 0, 0)
// Copy with a buffer offset // Copy with a buffer offset
.CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 4, destination, 15 * 4, 0) .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 4, destination, bufferSize - 4, 0)
.GetResult(); .GetResult();
} }
@ -275,7 +286,7 @@ TEST_F(CopyCommandTest_T2B, Success) {
// An empty copy // An empty copy
.CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, destination, 0, 0) .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, destination, 0, 0)
// An empty copy touching the end of the buffer // An empty copy touching the end of the buffer
.CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, destination, 16 * 4, 0) .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, destination, bufferSize, 0)
// An empty copy touching the side of the texture // An empty copy touching the side of the texture
.CopyTextureToBuffer(source, 16, 16, 0, 0, 0, 1, 0, destination, 0, 0) .CopyTextureToBuffer(source, 16, 16, 0, 0, 0, 1, 0, destination, 0, 0)
.GetResult(); .GetResult();
@ -284,9 +295,10 @@ TEST_F(CopyCommandTest_T2B, Success) {
// Test OOB conditions on the texture // Test OOB conditions on the texture
TEST_F(CopyCommandTest_T2B, OutOfBoundsOnTexture) { TEST_F(CopyCommandTest_T2B, OutOfBoundsOnTexture) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
nxt::Texture source = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm, nxt::Texture source = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm,
nxt::TextureUsageBit::TransferSrc); nxt::TextureUsageBit::TransferSrc);
nxt::Buffer destination = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::TransferDst); nxt::Buffer destination = CreateFrozenBuffer(bufferSize, nxt::BufferUsageBit::TransferDst);
// OOB on the texture because x + width overflows // OOB on the texture because x + width overflows
{ {
@ -319,9 +331,10 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnTexture) {
// Test OOB conditions on the buffer // Test OOB conditions on the buffer
TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) { TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
nxt::Texture source = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm, nxt::Texture source = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm,
nxt::TextureUsageBit::TransferSrc); nxt::TextureUsageBit::TransferSrc);
nxt::Buffer destination = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::TransferDst); nxt::Buffer destination = CreateFrozenBuffer(bufferSize, nxt::BufferUsageBit::TransferDst);
// OOB on the buffer because we copy too many pixels // OOB on the buffer because we copy too many pixels
{ {
@ -340,9 +353,10 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) {
// Test that we force Z=0 and Depth=1 on copies from to 2D textures // Test that we force Z=0 and Depth=1 on copies from to 2D textures
TEST_F(CopyCommandTest_T2B, ZDepthConstraintFor2DTextures) { TEST_F(CopyCommandTest_T2B, ZDepthConstraintFor2DTextures) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
nxt::Texture source = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm, nxt::Texture source = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm,
nxt::TextureUsageBit::TransferSrc); nxt::TextureUsageBit::TransferSrc);
nxt::Buffer destination = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::TransferDst); nxt::Buffer destination = CreateFrozenBuffer(bufferSize, nxt::BufferUsageBit::TransferDst);
// Z=1 on an empty copy still errors // Z=1 on an empty copy still errors
{ {
@ -359,14 +373,15 @@ TEST_F(CopyCommandTest_T2B, ZDepthConstraintFor2DTextures) {
} }
} }
// Test B2B copies with incorrect buffer usage // Test T2B copies with incorrect buffer usage
TEST_F(CopyCommandTest_T2B, IncorrectUsage) { TEST_F(CopyCommandTest_T2B, IncorrectUsage) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
nxt::Texture source = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm, nxt::Texture source = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm,
nxt::TextureUsageBit::TransferSrc); nxt::TextureUsageBit::TransferSrc);
nxt::Texture sampled = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm, nxt::Texture sampled = CreateFrozen2DTexture(16, 16, 5, nxt::TextureFormat::R8G8B8A8Unorm,
nxt::TextureUsageBit::Sampled); nxt::TextureUsageBit::Sampled);
nxt::Buffer destination = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::TransferDst); nxt::Buffer destination = CreateFrozenBuffer(bufferSize, nxt::BufferUsageBit::TransferDst);
nxt::Buffer vertex = CreateFrozenBuffer(16 * 4, nxt::BufferUsageBit::Vertex); nxt::Buffer vertex = CreateFrozenBuffer(bufferSize, nxt::BufferUsageBit::Vertex);
// Incorrect source usage // Incorrect source usage
{ {