From 617e3565801f2ff05cacc9c738d9a14e310667a0 Mon Sep 17 00:00:00 2001 From: Natasha Lee Date: Tue, 17 Sep 2019 18:54:47 +0000 Subject: [PATCH] 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 Reviewed-by: Kai Ninomiya Reviewed-by: Corentin Wallez --- src/dawn_native/d3d12/TextureD3D12.cpp | 34 ++-- src/dawn_native/opengl/CommandBufferGL.cpp | 14 +- src/dawn_native/opengl/TextureGL.cpp | 157 +++++++++++++----- src/dawn_native/opengl/TextureGL.h | 9 +- src/dawn_native/vulkan/TextureVk.cpp | 31 ++-- .../end2end/NonzeroTextureCreationTests.cpp | 40 ++++- src/tests/end2end/TextureZeroInitTests.cpp | 80 +++++++-- 7 files changed, 271 insertions(+), 94 deletions(-) diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp index dbc88642ab..97843588a9 100644 --- a/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/src/dawn_native/d3d12/TextureD3D12.cpp @@ -552,22 +552,28 @@ namespace dawn_native { namespace d3d12 { Extent3D copySize = {GetSize().width, GetSize().height, 1}; TextureCopySplit copySplit = ComputeTextureCopySplit( {0, 0, 0}, copySize, GetFormat(), uploadHandle.startOffset, rowPitch, 0); - D3D12_TEXTURE_COPY_LOCATION textureLocation = - ComputeTextureCopyLocationForTexture(this, baseMipLevel, baseArrayLayer); - 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); - D3D12_BOX sourceRegion = - ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize); + 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, level, layer); + for (uint32_t i = 0; i < copySplit.count; ++i) { + TextureCopySplit::CopyInfo& info = copySplit.copies[i]; - // copy the buffer filled with clear color to the texture - commandList->CopyTextureRegion(&textureLocation, info.textureOffset.x, - info.textureOffset.y, info.textureOffset.z, - &bufferLocation, &sourceRegion); + D3D12_TEXTURE_COPY_LOCATION bufferLocation = + ComputeBufferLocationForCopyTextureRegion( + this, ToBackend(uploadHandle.stagingBuffer)->GetResource(), + info.bufferSize, copySplit.offset, rowPitch); + D3D12_BOX sourceRegion = + ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize); + + // copy the buffer filled with clear color to the texture + commandList->CopyTextureRegion(&textureLocation, info.textureOffset.x, + info.textureOffset.y, info.textureOffset.z, + &bufferLocation, &sourceRegion); + } + } } } if (clearValue == TextureBase::ClearValue::Zero) { diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp index 51c0624068..ea753f59a4 100644 --- a/src/dawn_native/opengl/CommandBufferGL.cpp +++ b/src/dawn_native/opengl/CommandBufferGL.cpp @@ -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) { diff --git a/src/dawn_native/opengl/TextureGL.cpp b/src/dawn_native/opengl/TextureGL.cpp index 94bd58f028..5dce58235c 100644 --- a/src/dawn_native/opengl/TextureGL.cpp +++ b/src/dawn_native/opengl/TextureGL.cpp @@ -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,50 +179,123 @@ namespace dawn_native { namespace opengl { return ToBackend(GetDevice())->GetGLFormat(GetFormat()); } - void Texture::ClearTexture(GLint baseMipLevel, - GLint levelCount, - GLint baseArrayLayer, - uint32_t layerCount) { - const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; + MaybeError Texture::ClearTexture(GLint baseMipLevel, + GLint levelCount, + GLint baseArrayLayer, + uint32_t layerCount, + TextureBase::ClearValue clearValue) { // TODO(jiawei.shao@intel.com): initialize the textures with compressed formats. if (GetFormat().isCompressed) { - return; + return {}; } - if (GetFormat().HasDepthOrStencil()) { - bool doDepthClear = GetFormat().HasDepth(); - bool doStencilClear = GetFormat().HasStencil(); - GLfloat depth = 0.0f; - GLint stencil = 0u; - if (doDepthClear) { - gl.DepthMask(GL_TRUE); - } - if (doStencilClear) { - gl.StencilMask(GetStencilMaskFromStencilFormat(GetFormat().format)); - } + 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 = clearColor; + GLint stencil = clearColor; + if (doDepthClear) { + gl.DepthMask(GL_TRUE); + } + if (doStencilClear) { + gl.StencilMask(GetStencilMaskFromStencilFormat(GetFormat().format)); + } - 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); - if (doDepthClear && doStencilClear) { - gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil); - } else if (doDepthClear) { - gl.ClearBufferfv(GL_DEPTH, 0, &depth); - } else if (doStencilClear) { - gl.ClearBufferiv(GL_STENCIL, 0, &stencil); + GLuint framebuffer = 0; + gl.GenFramebuffers(1, &framebuffer); + gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); + // 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) { + gl.ClearBufferfv(GL_DEPTH, 0, &depth); + } else if (doStencilClear) { + gl.ClearBufferiv(GL_STENCIL, 0, &stencil); + } + gl.DeleteFramebuffers(1, &framebuffer); + } else { + static constexpr uint32_t MAX_TEXEL_SIZE = 16; + ASSERT(GetFormat().blockByteSize <= MAX_TEXEL_SIZE); + std::array 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, + clearColorData.data()); + } } - gl.DeleteFramebuffers(1, &framebuffer); } else { - const GLFormat& glFormat = GetGLFormat(); + // 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::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 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 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(clearBuffer), + reinterpret_cast(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) { - Extent3D mipSize = GetMipLevelPhysicalSize(level); - gl.ClearTexSubImage(mHandle, level, 0, 0, baseArrayLayer, mipSize.width, - mipSize.height, layerCount, glFormat.format, glFormat.type, - nullptr); + 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(); } diff --git a/src/dawn_native/opengl/TextureGL.h b/src/dawn_native/opengl/TextureGL.h index 40d82e8a91..b72c4fc2ec 100644 --- a/src/dawn_native/opengl/TextureGL.h +++ b/src/dawn_native/opengl/TextureGL.h @@ -45,10 +45,11 @@ namespace dawn_native { namespace opengl { private: void DestroyImpl() override; - void ClearTexture(GLint baseMipLevel, - GLint levelCount, - GLint baseArrayLayer, - uint32_t layerCount); + MaybeError ClearTexture(GLint baseMipLevel, + GLint levelCount, + GLint baseArrayLayer, + uint32_t layerCount, + TextureBase::ClearValue clearValue); GLuint mHandle; GLenum mTarget; diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp index a37e300a03..43a18c5dc7 100644 --- a/src/dawn_native/vulkan/TextureVk.cpp +++ b/src/dawn_native/vulkan/TextureVk.cpp @@ -701,22 +701,27 @@ namespace dawn_native { namespace vulkan { bufferCopy.offset = uploadHandle.startOffset; bufferCopy.rowPitch = rowPitch; - 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}; - VkBufferImageCopy region = - ComputeBufferImageCopyRegion(bufferCopy, textureCopy, copySize); + 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 = level; + textureCopy.arrayLayer = layer; - // copy the clear buffer to the texture image - device->fn.CmdCopyBufferToImage( - recordingContext->commandBuffer, - ToBackend(uploadHandle.stagingBuffer)->GetBufferHandle(), GetHandle(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + VkBufferImageCopy region = + ComputeBufferImageCopyRegion(bufferCopy, textureCopy, copySize); + + // copy the clear buffer to the texture image + device->fn.CmdCopyBufferToImage( + recordingContext->commandBuffer, + ToBackend(uploadHandle.stagingBuffer)->GetBufferHandle(), GetHandle(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + } + } } if (clearValue == TextureBase::ClearValue::Zero) { SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, diff --git a/src/tests/end2end/NonzeroTextureCreationTests.cpp b/src/tests/end2end/NonzeroTextureCreationTests.cpp index e94d93ab3f..fb507b8eb7 100644 --- a/src/tests/end2end/NonzeroTextureCreationTests.cpp +++ b/src/tests/end2end/NonzeroTextureCreationTests.cpp @@ -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 data(bufferSize, 100); + dawn::Buffer bufferDst = utils::CreateBufferFromData( + device, data.data(), static_cast(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, ©Size); + dawn::CommandBuffer commands = encoder.Finish(); + queue.Submit(1, &commands); + + std::vector 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"}, diff --git a/src/tests/end2end/TextureZeroInitTests.cpp b/src/tests/end2end/TextureZeroInitTests.cpp index b73c2c4137..18d98e36c3 100644 --- a/src/tests/end2end/TextureZeroInitTests.cpp +++ b/src/tests/end2end/TextureZeroInitTests.cpp @@ -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 data(4 * kSize * kSize, 100); + std::vector data(kFormatBlockByteSize * kSize * kSize, 100); dawn::Buffer stagingBuffer = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), dawn::BufferUsage::CopySrc); @@ -192,7 +197,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTextureHalf) { kColorFormat); dawn::Texture texture = device.CreateTexture(&descriptor); - std::vector data(4 * kSize * kSize, 100); + std::vector data(kFormatBlockByteSize * kSize * kSize, 100); dawn::Buffer stagingBuffer = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), dawn::BufferUsage::CopySrc); @@ -256,7 +261,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToTextureHalf) { // fill srcTexture with 100 { - std::vector data(4 * kSize * kSize, 100); + std::vector data(kFormatBlockByteSize * kSize * kSize, 100); dawn::Buffer stagingBuffer = utils::CreateBufferFromData( device, data.data(), static_cast(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 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 data(bufferSize, 100); + dawn::Buffer bufferDst = utils::CreateBufferFromData( + device, data.data(), static_cast(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, ©Size); + dawn::CommandBuffer commands = encoder.Finish(); + EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands)); + + std::vector 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 data(bufferSize, 100); + dawn::Buffer bufferDst = utils::CreateBufferFromData( + device, data.data(), static_cast(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, ©Size); + dawn::CommandBuffer commands = encoder.Finish(); + EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands)); + + std::vector 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 data(bufferSize, 100); dawn::Buffer bufferDst = utils::CreateBufferFromData( device, data.data(), static_cast(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();