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

View File

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

View File

@ -15,6 +15,9 @@
#include "dawn_native/opengl/TextureGL.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/UtilsGL.h"
@ -142,14 +145,8 @@ namespace dawn_native { namespace opengl {
gl.TexParameteri(mTarget, GL_TEXTURE_MAX_LEVEL, levels - 1);
if (GetDevice()->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
static constexpr uint32_t MAX_TEXEL_SIZE = 16;
ASSERT(GetFormat().blockByteSize <= MAX_TEXEL_SIZE);
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);
}
GetDevice()->ConsumedError(ClearTexture(0, GetNumMipLevels(), 0, GetArrayLayers(),
TextureBase::ClearValue::NonZero));
}
}
@ -182,21 +179,25 @@ namespace dawn_native { namespace opengl {
return ToBackend(GetDevice())->GetGLFormat(GetFormat());
}
void Texture::ClearTexture(GLint baseMipLevel,
MaybeError Texture::ClearTexture(GLint baseMipLevel,
GLint levelCount,
GLint baseArrayLayer,
uint32_t layerCount) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
uint32_t layerCount,
TextureBase::ClearValue clearValue) {
// TODO(jiawei.shao@intel.com): initialize the textures with compressed formats.
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()) {
bool doDepthClear = GetFormat().HasDepth();
bool doStencilClear = GetFormat().HasStencil();
GLfloat depth = 0.0f;
GLint stencil = 0u;
GLfloat depth = clearColor;
GLint stencil = clearColor;
if (doDepthClear) {
gl.DepthMask(GL_TRUE);
}
@ -207,8 +208,9 @@ namespace dawn_native { namespace opengl {
GLuint framebuffer = 0;
gl.GenFramebuffers(1, &framebuffer);
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GetGLTarget(),
GetHandle(), 0);
// TODO(natlee@microsoft.com): clear all mip levels and array layers.
gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GetGLTarget(), GetHandle(), 0);
if (doDepthClear && doStencilClear) {
gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil);
} else if (doDepthClear) {
@ -218,14 +220,82 @@ namespace dawn_native { namespace opengl {
}
gl.DeleteFramebuffers(1, &framebuffer);
} 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();
for (GLint level = baseMipLevel; level < baseMipLevel + levelCount; ++level) {
Extent3D mipSize = GetMipLevelPhysicalSize(level);
gl.ClearTexSubImage(mHandle, level, 0, 0, baseArrayLayer, mipSize.width,
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,
@ -238,7 +308,8 @@ namespace dawn_native { namespace opengl {
}
if (!IsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
layerCount)) {
ClearTexture(baseMipLevel, levelCount, baseArrayLayer, layerCount);
GetDevice()->ConsumedError(ClearTexture(baseMipLevel, levelCount, baseArrayLayer,
layerCount, TextureBase::ClearValue::Zero));
if (isLazyClear) {
GetDevice()->IncrementLazyClearCountForTesting();
}

View File

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

View File

@ -701,13 +701,16 @@ namespace dawn_native { namespace vulkan {
bufferCopy.offset = uploadHandle.startOffset;
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;
textureCopy.texture = this;
textureCopy.origin = {0, 0, 0};
textureCopy.mipLevel = baseMipLevel;
textureCopy.arrayLayer = baseArrayLayer;
Extent3D copySize = {GetSize().width, GetSize().height, 1};
textureCopy.mipLevel = level;
textureCopy.arrayLayer = layer;
VkBufferImageCopy region =
ComputeBufferImageCopyRegion(bufferCopy, textureCopy, copySize);
@ -718,6 +721,8 @@ namespace dawn_native { namespace vulkan {
ToBackend(uploadHandle.stagingBuffer)->GetBufferHandle(), GetHandle(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
}
}
}
if (clearValue == TextureBase::ClearValue::Zero) {
SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
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_P(NonzeroTextureCreationTests, NonrenderableTextureFormat) {
// skip test for other backends since they are not implemented yet
DAWN_SKIP_TEST_IF(IsOpenGL());
dawn::TextureDescriptor descriptor;
descriptor.dimension = dawn::TextureDimension::e2D;
descriptor.size.width = kSize;
@ -129,6 +127,44 @@ TEST_P(NonzeroTextureCreationTests, NonrenderableTextureFormat) {
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,
ForceWorkarounds(D3D12Backend,
{"nonzero_clear_resources_on_creation_for_testing"},

View File

@ -14,6 +14,7 @@
#include "tests/DawnTest.h"
#include "common/Math.h"
#include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/DawnHelpers.h"
@ -83,6 +84,10 @@ class TextureZeroInitTest : public DawnTest {
return device.CreateRenderPipeline(&pipelineDescriptor);
}
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 kDepthStencilFormat =
dawn::TextureFormat::Depth24PlusStencil8;
@ -165,7 +170,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTexture) {
kColorFormat);
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(
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
@ -192,7 +197,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTextureHalf) {
kColorFormat);
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(
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
@ -256,7 +261,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToTextureHalf) {
// 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(
device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsage::CopySrc);
dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 0, 0);
@ -504,7 +509,7 @@ TEST_P(TextureZeroInitTest, ComputePassSampledTextureClear) {
descriptor.size.height = 1;
dawn::Texture texture = device.CreateTexture(&descriptor);
uint32_t bufferSize = 4 * sizeof(uint32_t);
uint32_t bufferSize = kFormatBlockByteSize * sizeof(uint32_t);
dawn::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = bufferSize;
bufferDescriptor.usage =
@ -560,26 +565,81 @@ TEST_P(TextureZeroInitTest, ComputePassSampledTextureClear) {
// Expect the buffer to be zeroed out by the compute pass
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
TEST_P(TextureZeroInitTest, NonRenderableTextureClear) {
// skip test for other backends since they are not implemented yet
DAWN_SKIP_TEST_IF(IsOpenGL());
dawn::TextureDescriptor descriptor =
CreateTextureDescriptor(1, 1, 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 = 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);
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, 0, {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();