OpenGL: clear nonrenderable texture formats

Clears nonrenderable color formats and merges zero vs nonzero clears
to use the same code path.

Bug: dawn:145
Change-Id: I8f2f36134b56787e07231d82e37c36897ba1d4ba
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/10820
Commit-Queue: Natasha Lee <natlee@microsoft.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Natasha Lee 2019-09-17 18:54:47 +00:00 committed by Commit Bot service account
parent be990077f4
commit 617e356580
7 changed files with 271 additions and 94 deletions

View File

@ -552,15 +552,19 @@ namespace dawn_native { namespace d3d12 {
Extent3D copySize = {GetSize().width, GetSize().height, 1}; Extent3D copySize = {GetSize().width, GetSize().height, 1};
TextureCopySplit copySplit = ComputeTextureCopySplit( TextureCopySplit copySplit = ComputeTextureCopySplit(
{0, 0, 0}, copySize, GetFormat(), uploadHandle.startOffset, rowPitch, 0); {0, 0, 0}, copySize, GetFormat(), uploadHandle.startOffset, rowPitch, 0);
for (uint32_t level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
for (uint32_t layer = baseArrayLayer; layer < baseArrayLayer + layerCount;
++layer) {
D3D12_TEXTURE_COPY_LOCATION textureLocation = D3D12_TEXTURE_COPY_LOCATION textureLocation =
ComputeTextureCopyLocationForTexture(this, baseMipLevel, baseArrayLayer); ComputeTextureCopyLocationForTexture(this, level, layer);
for (uint32_t i = 0; i < copySplit.count; ++i) { for (uint32_t i = 0; i < copySplit.count; ++i) {
TextureCopySplit::CopyInfo& info = copySplit.copies[i]; TextureCopySplit::CopyInfo& info = copySplit.copies[i];
D3D12_TEXTURE_COPY_LOCATION bufferLocation = D3D12_TEXTURE_COPY_LOCATION bufferLocation =
ComputeBufferLocationForCopyTextureRegion( ComputeBufferLocationForCopyTextureRegion(
this, ToBackend(uploadHandle.stagingBuffer)->GetResource(), info.bufferSize, this, ToBackend(uploadHandle.stagingBuffer)->GetResource(),
copySplit.offset, rowPitch); info.bufferSize, copySplit.offset, rowPitch);
D3D12_BOX sourceRegion = D3D12_BOX sourceRegion =
ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize); ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize);
@ -570,6 +574,8 @@ namespace dawn_native { namespace d3d12 {
&bufferLocation, &sourceRegion); &bufferLocation, &sourceRegion);
} }
} }
}
}
if (clearValue == TextureBase::ClearValue::Zero) { if (clearValue == TextureBase::ClearValue::Zero) {
SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
layerCount); layerCount);

View File

@ -457,22 +457,20 @@ namespace dawn_native { namespace opengl {
gl.BindTexture(target, texture->GetHandle()); gl.BindTexture(target, texture->GetHandle());
const Format& formatInfo = texture->GetFormat(); const Format& formatInfo = texture->GetFormat();
gl.PixelStorei( gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
GL_UNPACK_ROW_LENGTH, src.rowPitch / formatInfo.blockByteSize * formatInfo.blockWidth);
src.rowPitch / texture->GetFormat().blockByteSize * formatInfo.blockWidth);
gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, src.imageHeight); gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, src.imageHeight);
if (texture->GetFormat().isCompressed) { if (formatInfo.isCompressed) {
gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, formatInfo.blockByteSize); gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, formatInfo.blockByteSize);
gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, formatInfo.blockWidth); gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, formatInfo.blockWidth);
gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, formatInfo.blockHeight); gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, formatInfo.blockHeight);
gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 1); gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 1);
ASSERT(texture->GetDimension() == dawn::TextureDimension::e2D); ASSERT(texture->GetDimension() == dawn::TextureDimension::e2D);
uint64_t copyDataSize = uint64_t copyDataSize = (copySize.width / formatInfo.blockWidth) *
(copySize.width / texture->GetFormat().blockWidth) * (copySize.height / formatInfo.blockHeight) *
(copySize.height / texture->GetFormat().blockHeight) * formatInfo.blockByteSize;
texture->GetFormat().blockByteSize;
Extent3D copyExtent = ComputeTextureCopyExtent(dst, copySize); Extent3D copyExtent = ComputeTextureCopyExtent(dst, copySize);
if (texture->GetArrayLayers() > 1) { if (texture->GetArrayLayers() > 1) {

View File

@ -15,6 +15,9 @@
#include "dawn_native/opengl/TextureGL.h" #include "dawn_native/opengl/TextureGL.h"
#include "common/Assert.h" #include "common/Assert.h"
#include "common/Constants.h"
#include "common/Math.h"
#include "dawn_native/opengl/BufferGL.h"
#include "dawn_native/opengl/DeviceGL.h" #include "dawn_native/opengl/DeviceGL.h"
#include "dawn_native/opengl/UtilsGL.h" #include "dawn_native/opengl/UtilsGL.h"
@ -142,14 +145,8 @@ namespace dawn_native { namespace opengl {
gl.TexParameteri(mTarget, GL_TEXTURE_MAX_LEVEL, levels - 1); gl.TexParameteri(mTarget, GL_TEXTURE_MAX_LEVEL, levels - 1);
if (GetDevice()->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) { if (GetDevice()->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
static constexpr uint32_t MAX_TEXEL_SIZE = 16; GetDevice()->ConsumedError(ClearTexture(0, GetNumMipLevels(), 0, GetArrayLayers(),
ASSERT(GetFormat().blockByteSize <= MAX_TEXEL_SIZE); TextureBase::ClearValue::NonZero));
GLubyte clearColor[MAX_TEXEL_SIZE];
std::fill(clearColor, clearColor + MAX_TEXEL_SIZE, 255);
// TODO(natlee@microsoft.com): clear all subresources
for (uint32_t i = 0; i < GetNumMipLevels(); i++) {
gl.ClearTexImage(mHandle, i, glFormat.format, glFormat.type, clearColor);
}
} }
} }
@ -182,21 +179,25 @@ namespace dawn_native { namespace opengl {
return ToBackend(GetDevice())->GetGLFormat(GetFormat()); return ToBackend(GetDevice())->GetGLFormat(GetFormat());
} }
void Texture::ClearTexture(GLint baseMipLevel, MaybeError Texture::ClearTexture(GLint baseMipLevel,
GLint levelCount, GLint levelCount,
GLint baseArrayLayer, GLint baseArrayLayer,
uint32_t layerCount) { uint32_t layerCount,
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; TextureBase::ClearValue clearValue) {
// TODO(jiawei.shao@intel.com): initialize the textures with compressed formats. // TODO(jiawei.shao@intel.com): initialize the textures with compressed formats.
if (GetFormat().isCompressed) { if (GetFormat().isCompressed) {
return; return {};
} }
Device* device = ToBackend(GetDevice());
const OpenGLFunctions& gl = device->gl;
uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1;
if (GetFormat().isRenderable) {
if (GetFormat().HasDepthOrStencil()) { if (GetFormat().HasDepthOrStencil()) {
bool doDepthClear = GetFormat().HasDepth(); bool doDepthClear = GetFormat().HasDepth();
bool doStencilClear = GetFormat().HasStencil(); bool doStencilClear = GetFormat().HasStencil();
GLfloat depth = 0.0f; GLfloat depth = clearColor;
GLint stencil = 0u; GLint stencil = clearColor;
if (doDepthClear) { if (doDepthClear) {
gl.DepthMask(GL_TRUE); gl.DepthMask(GL_TRUE);
} }
@ -207,8 +208,9 @@ namespace dawn_native { namespace opengl {
GLuint framebuffer = 0; GLuint framebuffer = 0;
gl.GenFramebuffers(1, &framebuffer); gl.GenFramebuffers(1, &framebuffer);
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GetGLTarget(), // TODO(natlee@microsoft.com): clear all mip levels and array layers.
GetHandle(), 0); gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GetGLTarget(), GetHandle(), 0);
if (doDepthClear && doStencilClear) { if (doDepthClear && doStencilClear) {
gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil); gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil);
} else if (doDepthClear) { } else if (doDepthClear) {
@ -218,14 +220,82 @@ namespace dawn_native { namespace opengl {
} }
gl.DeleteFramebuffers(1, &framebuffer); gl.DeleteFramebuffers(1, &framebuffer);
} else { } else {
static constexpr uint32_t MAX_TEXEL_SIZE = 16;
ASSERT(GetFormat().blockByteSize <= MAX_TEXEL_SIZE);
std::array<GLbyte, MAX_TEXEL_SIZE> clearColorData;
clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 255;
clearColorData.fill(clearColor);
const GLFormat& glFormat = GetGLFormat(); const GLFormat& glFormat = GetGLFormat();
for (GLint level = baseMipLevel; level < baseMipLevel + levelCount; ++level) { for (GLint level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
Extent3D mipSize = GetMipLevelPhysicalSize(level); Extent3D mipSize = GetMipLevelPhysicalSize(level);
gl.ClearTexSubImage(mHandle, level, 0, 0, baseArrayLayer, mipSize.width, gl.ClearTexSubImage(mHandle, level, 0, 0, baseArrayLayer, mipSize.width,
mipSize.height, layerCount, glFormat.format, glFormat.type, mipSize.height, layerCount, glFormat.format, glFormat.type,
nullptr); clearColorData.data());
} }
} }
} else {
// TODO(natlee@microsoft.com): test compressed textures are cleared
// create temp buffer with clear color to copy to the texture image
ASSERT(kTextureRowPitchAlignment % GetFormat().blockByteSize == 0);
uint32_t rowPitch =
Align((GetSize().width / GetFormat().blockWidth) * GetFormat().blockByteSize,
kTextureRowPitchAlignment);
// Make sure that we are not rounding
ASSERT(rowPitch % GetFormat().blockByteSize == 0);
ASSERT(GetSize().height % GetFormat().blockHeight == 0);
dawn_native::BufferDescriptor descriptor;
descriptor.size = rowPitch * (GetSize().height / GetFormat().blockHeight);
if (descriptor.size > std::numeric_limits<uint32_t>::max()) {
return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer.");
}
descriptor.nextInChain = nullptr;
descriptor.usage = dawn::BufferUsage::CopySrc | dawn::BufferUsage::MapWrite;
// TODO(natlee@microsoft.com): use Dynamic Uplaoder here for temp buffer
Ref<Buffer> srcBuffer = ToBackend(device->CreateBuffer(&descriptor));
// Call release here to prevent memory leak since CreateBuffer will up the ref count to
// 1, then assigning to Ref<Buffer> ups the ref count to 2. Release will reduce the ref
// count and ensure it to reach 0 when out of use.
srcBuffer->Release();
// Fill the buffer with clear color
uint8_t* clearBuffer = nullptr;
DAWN_TRY(srcBuffer->MapAtCreation(&clearBuffer));
std::fill(reinterpret_cast<uint32_t*>(clearBuffer),
reinterpret_cast<uint32_t*>(clearBuffer + descriptor.size), clearColor);
srcBuffer->Unmap();
// Bind buffer and texture, and make the buffer to texture copy
gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
(rowPitch / GetFormat().blockByteSize) * GetFormat().blockWidth);
gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
for (GLint level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, srcBuffer->GetHandle());
gl.ActiveTexture(GL_TEXTURE0);
gl.BindTexture(GetGLTarget(), GetHandle());
Extent3D size = GetMipLevelPhysicalSize(level);
switch (GetDimension()) {
case dawn::TextureDimension::e2D:
// TODO(natlee@microsoft.com): This will break when layerCount is greater
// than 1, because the buffer is only sized for one layer.
ASSERT(layerCount == 1);
gl.TexSubImage2D(GetGLTarget(), level, 0, 0, size.width, size.height,
GetGLFormat().format, GetGLFormat().type, 0);
break;
default:
UNREACHABLE();
}
gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
}
return {};
} }
void Texture::EnsureSubresourceContentInitialized(uint32_t baseMipLevel, void Texture::EnsureSubresourceContentInitialized(uint32_t baseMipLevel,
@ -238,7 +308,8 @@ namespace dawn_native { namespace opengl {
} }
if (!IsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, if (!IsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
layerCount)) { layerCount)) {
ClearTexture(baseMipLevel, levelCount, baseArrayLayer, layerCount); GetDevice()->ConsumedError(ClearTexture(baseMipLevel, levelCount, baseArrayLayer,
layerCount, TextureBase::ClearValue::Zero));
if (isLazyClear) { if (isLazyClear) {
GetDevice()->IncrementLazyClearCountForTesting(); GetDevice()->IncrementLazyClearCountForTesting();
} }

View File

@ -45,10 +45,11 @@ namespace dawn_native { namespace opengl {
private: private:
void DestroyImpl() override; void DestroyImpl() override;
void ClearTexture(GLint baseMipLevel, MaybeError ClearTexture(GLint baseMipLevel,
GLint levelCount, GLint levelCount,
GLint baseArrayLayer, GLint baseArrayLayer,
uint32_t layerCount); uint32_t layerCount,
TextureBase::ClearValue clearValue);
GLuint mHandle; GLuint mHandle;
GLenum mTarget; GLenum mTarget;

View File

@ -701,13 +701,16 @@ namespace dawn_native { namespace vulkan {
bufferCopy.offset = uploadHandle.startOffset; bufferCopy.offset = uploadHandle.startOffset;
bufferCopy.rowPitch = rowPitch; bufferCopy.rowPitch = rowPitch;
Extent3D copySize = {GetSize().width, GetSize().height, 1};
for (uint32_t level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
for (uint32_t layer = baseArrayLayer; layer < baseArrayLayer + layerCount;
++layer) {
dawn_native::TextureCopy textureCopy; dawn_native::TextureCopy textureCopy;
textureCopy.texture = this; textureCopy.texture = this;
textureCopy.origin = {0, 0, 0}; textureCopy.origin = {0, 0, 0};
textureCopy.mipLevel = baseMipLevel; textureCopy.mipLevel = level;
textureCopy.arrayLayer = baseArrayLayer; textureCopy.arrayLayer = layer;
Extent3D copySize = {GetSize().width, GetSize().height, 1};
VkBufferImageCopy region = VkBufferImageCopy region =
ComputeBufferImageCopyRegion(bufferCopy, textureCopy, copySize); ComputeBufferImageCopyRegion(bufferCopy, textureCopy, copySize);
@ -718,6 +721,8 @@ namespace dawn_native { namespace vulkan {
ToBackend(uploadHandle.stagingBuffer)->GetBufferHandle(), GetHandle(), ToBackend(uploadHandle.stagingBuffer)->GetBufferHandle(), GetHandle(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region); VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
} }
}
}
if (clearValue == TextureBase::ClearValue::Zero) { if (clearValue == TextureBase::ClearValue::Zero) {
SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
layerCount); layerCount);

View File

@ -96,8 +96,6 @@ TEST_P(NonzeroTextureCreationTests, ArrayLayerClears) {
// Test that nonrenderable texture formats clear to 1's because toggle is enabled // Test that nonrenderable texture formats clear to 1's because toggle is enabled
TEST_P(NonzeroTextureCreationTests, NonrenderableTextureFormat) { TEST_P(NonzeroTextureCreationTests, NonrenderableTextureFormat) {
// skip test for other backends since they are not implemented yet
DAWN_SKIP_TEST_IF(IsOpenGL());
dawn::TextureDescriptor descriptor; dawn::TextureDescriptor descriptor;
descriptor.dimension = dawn::TextureDimension::e2D; descriptor.dimension = dawn::TextureDimension::e2D;
descriptor.size.width = kSize; descriptor.size.width = kSize;
@ -129,6 +127,44 @@ TEST_P(NonzeroTextureCreationTests, NonrenderableTextureFormat) {
EXPECT_BUFFER_U32_RANGE_EQ(expected.data(), bufferDst, 0, 8); EXPECT_BUFFER_U32_RANGE_EQ(expected.data(), bufferDst, 0, 8);
} }
// Test that textures with more than 1 array layers and nonrenderable texture formats clear to 1's
// because toggle is enabled
TEST_P(NonzeroTextureCreationTests, NonRenderableTextureClearWithMultiArrayLayers) {
// TODO(natlee@microsoft.com): skip for now on opengl because TextureClear nonrenderable
// textures does not create large enough buffers for array layers greater than 1.
DAWN_SKIP_TEST_IF(IsOpenGL());
dawn::TextureDescriptor descriptor;
descriptor.dimension = dawn::TextureDimension::e2D;
descriptor.size.width = kSize;
descriptor.size.height = kSize;
descriptor.size.depth = 1;
descriptor.arrayLayerCount = 2;
descriptor.sampleCount = 1;
descriptor.format = dawn::TextureFormat::RGBA8Snorm;
descriptor.mipLevelCount = 1;
descriptor.usage = dawn::TextureUsage::CopySrc;
dawn::Texture texture = device.CreateTexture(&descriptor);
// Set buffer with dirty data so we know it is cleared by the lazy cleared texture copy
uint32_t bufferSize = 4 * kSize * kSize;
std::vector<uint8_t> data(bufferSize, 100);
dawn::Buffer bufferDst = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, 0, 0);
dawn::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, 1, {0, 0, 0});
dawn::Extent3D copySize = {kSize, kSize, 1};
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &copySize);
dawn::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
std::vector<uint32_t> expectedWithZeros(bufferSize, 1);
EXPECT_BUFFER_U32_RANGE_EQ(expectedWithZeros.data(), bufferDst, 0, 8);
}
DAWN_INSTANTIATE_TEST(NonzeroTextureCreationTests, DAWN_INSTANTIATE_TEST(NonzeroTextureCreationTests,
ForceWorkarounds(D3D12Backend, ForceWorkarounds(D3D12Backend,
{"nonzero_clear_resources_on_creation_for_testing"}, {"nonzero_clear_resources_on_creation_for_testing"},

View File

@ -14,6 +14,7 @@
#include "tests/DawnTest.h" #include "tests/DawnTest.h"
#include "common/Math.h"
#include "utils/ComboRenderPipelineDescriptor.h" #include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/DawnHelpers.h" #include "utils/DawnHelpers.h"
@ -83,6 +84,10 @@ class TextureZeroInitTest : public DawnTest {
return device.CreateRenderPipeline(&pipelineDescriptor); return device.CreateRenderPipeline(&pipelineDescriptor);
} }
constexpr static uint32_t kSize = 128; constexpr static uint32_t kSize = 128;
constexpr static uint32_t kUnalignedSize = 127;
// All three texture formats used (RGBA8Unorm, Depth24PlusStencil8, and RGBA8Snorm) have the
// same byte size of 4.
constexpr static uint32_t kFormatBlockByteSize = 4;
constexpr static dawn::TextureFormat kColorFormat = dawn::TextureFormat::RGBA8Unorm; constexpr static dawn::TextureFormat kColorFormat = dawn::TextureFormat::RGBA8Unorm;
constexpr static dawn::TextureFormat kDepthStencilFormat = constexpr static dawn::TextureFormat kDepthStencilFormat =
dawn::TextureFormat::Depth24PlusStencil8; dawn::TextureFormat::Depth24PlusStencil8;
@ -165,7 +170,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTexture) {
kColorFormat); kColorFormat);
dawn::Texture texture = device.CreateTexture(&descriptor); dawn::Texture texture = device.CreateTexture(&descriptor);
std::vector<uint8_t> data(4 * kSize * kSize, 100); std::vector<uint8_t> data(kFormatBlockByteSize * kSize * kSize, 100);
dawn::Buffer stagingBuffer = utils::CreateBufferFromData( dawn::Buffer stagingBuffer = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
@ -192,7 +197,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTextureHalf) {
kColorFormat); kColorFormat);
dawn::Texture texture = device.CreateTexture(&descriptor); dawn::Texture texture = device.CreateTexture(&descriptor);
std::vector<uint8_t> data(4 * kSize * kSize, 100); std::vector<uint8_t> data(kFormatBlockByteSize * kSize * kSize, 100);
dawn::Buffer stagingBuffer = utils::CreateBufferFromData( dawn::Buffer stagingBuffer = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
@ -256,7 +261,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToTextureHalf) {
// fill srcTexture with 100 // fill srcTexture with 100
{ {
std::vector<uint8_t> data(4 * kSize * kSize, 100); std::vector<uint8_t> data(kFormatBlockByteSize * kSize * kSize, 100);
dawn::Buffer stagingBuffer = utils::CreateBufferFromData( dawn::Buffer stagingBuffer = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 0, 0); dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 0, 0);
@ -504,7 +509,7 @@ TEST_P(TextureZeroInitTest, ComputePassSampledTextureClear) {
descriptor.size.height = 1; descriptor.size.height = 1;
dawn::Texture texture = device.CreateTexture(&descriptor); dawn::Texture texture = device.CreateTexture(&descriptor);
uint32_t bufferSize = 4 * sizeof(uint32_t); uint32_t bufferSize = kFormatBlockByteSize * sizeof(uint32_t);
dawn::BufferDescriptor bufferDescriptor; dawn::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = bufferSize; bufferDescriptor.size = bufferSize;
bufferDescriptor.usage = bufferDescriptor.usage =
@ -560,26 +565,81 @@ TEST_P(TextureZeroInitTest, ComputePassSampledTextureClear) {
// Expect the buffer to be zeroed out by the compute pass // Expect the buffer to be zeroed out by the compute pass
std::vector<uint32_t> expectedWithZeros(bufferSize, 0); std::vector<uint32_t> expectedWithZeros(bufferSize, 0);
EXPECT_BUFFER_U32_RANGE_EQ(expectedWithZeros.data(), bufferTex, 0, 4); EXPECT_BUFFER_U32_RANGE_EQ(expectedWithZeros.data(), bufferTex, 0, kFormatBlockByteSize);
} }
// This tests that the code path of CopyTextureToBuffer clears correctly for non-renderable textures // This tests that the code path of CopyTextureToBuffer clears correctly for non-renderable textures
TEST_P(TextureZeroInitTest, NonRenderableTextureClear) { TEST_P(TextureZeroInitTest, NonRenderableTextureClear) {
// skip test for other backends since they are not implemented yet
DAWN_SKIP_TEST_IF(IsOpenGL());
dawn::TextureDescriptor descriptor = dawn::TextureDescriptor descriptor =
CreateTextureDescriptor(1, 1, dawn::TextureUsage::CopySrc, kNonrenderableColorFormat); CreateTextureDescriptor(1, 1, dawn::TextureUsage::CopySrc, kNonrenderableColorFormat);
dawn::Texture texture = device.CreateTexture(&descriptor); dawn::Texture texture = device.CreateTexture(&descriptor);
// Set buffer with dirty data so we know it is cleared by the lazy cleared texture copy // Set buffer with dirty data so we know it is cleared by the lazy cleared texture copy
uint32_t bufferSize = 4 * kSize * kSize; uint32_t rowPitch = Align(kSize * kFormatBlockByteSize, kTextureRowPitchAlignment);
uint32_t bufferSize = rowPitch * kSize;
std::vector<uint8_t> data(bufferSize, 100);
dawn::Buffer bufferDst = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, rowPitch, 0);
dawn::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, 0, {0, 0, 0});
dawn::Extent3D copySize = {kSize, kSize, 1};
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &copySize);
dawn::CommandBuffer commands = encoder.Finish();
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
std::vector<uint32_t> expectedWithZeros(bufferSize, 0);
EXPECT_BUFFER_U32_RANGE_EQ(expectedWithZeros.data(), bufferDst, 0, kSize);
}
// This tests that the code path of CopyTextureToBuffer clears correctly for non-renderable textures
TEST_P(TextureZeroInitTest, NonRenderableTextureClearUnalignedSize) {
dawn::TextureDescriptor descriptor =
CreateTextureDescriptor(1, 1, dawn::TextureUsage::CopySrc, kNonrenderableColorFormat);
descriptor.size.width = kUnalignedSize;
descriptor.size.height = kUnalignedSize;
dawn::Texture texture = device.CreateTexture(&descriptor);
// Set buffer with dirty data so we know it is cleared by the lazy cleared texture copy
uint32_t rowPitch = Align(kUnalignedSize * kFormatBlockByteSize, kTextureRowPitchAlignment);
uint32_t bufferSize = rowPitch * kUnalignedSize;
std::vector<uint8_t> data(bufferSize, 100);
dawn::Buffer bufferDst = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, rowPitch, 0);
dawn::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, 0, {0, 0, 0});
dawn::Extent3D copySize = {kUnalignedSize, kUnalignedSize, 1};
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &copySize);
dawn::CommandBuffer commands = encoder.Finish();
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
std::vector<uint32_t> expectedWithZeros(bufferSize, 0);
EXPECT_BUFFER_U32_RANGE_EQ(expectedWithZeros.data(), bufferDst, 0, kUnalignedSize);
}
// This tests that the code path of CopyTextureToBuffer clears correctly for non-renderable textures
// with more than 1 array layers
TEST_P(TextureZeroInitTest, NonRenderableTextureClearWithMultiArrayLayers) {
// TODO(natlee@microsoft.com): skip for now on opengl because TextureClear nonrenderable
// textures does not create large enough buffers for array layers greater than 1.
DAWN_SKIP_TEST_IF(IsOpenGL());
dawn::TextureDescriptor descriptor =
CreateTextureDescriptor(1, 2, dawn::TextureUsage::CopySrc, kNonrenderableColorFormat);
dawn::Texture texture = device.CreateTexture(&descriptor);
// Set buffer with dirty data so we know it is cleared by the lazy cleared texture copy
uint32_t bufferSize = kFormatBlockByteSize * kSize * kSize;
std::vector<uint8_t> data(bufferSize, 100); std::vector<uint8_t> data(bufferSize, 100);
dawn::Buffer bufferDst = utils::CreateBufferFromData( dawn::Buffer bufferDst = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, 0, 0); dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, 0, 0);
dawn::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, 0, {0, 0, 0}); dawn::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, 1, {0, 0, 0});
dawn::Extent3D copySize = {kSize, kSize, 1}; dawn::Extent3D copySize = {kSize, kSize, 1};
dawn::CommandEncoder encoder = device.CreateCommandEncoder(); dawn::CommandEncoder encoder = device.CreateCommandEncoder();