diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp index 92209f6cce..2e4a062aba 100644 --- a/src/dawn_native/opengl/CommandBufferGL.cpp +++ b/src/dawn_native/opengl/CommandBufferGL.cpp @@ -26,6 +26,7 @@ #include "dawn_native/opengl/RenderPipelineGL.h" #include "dawn_native/opengl/SamplerGL.h" #include "dawn_native/opengl/TextureGL.h" +#include "dawn_native/opengl/UtilsGL.h" #include @@ -129,15 +130,6 @@ namespace dawn_native { namespace opengl { } } - GLint GetStencilMaskFromStencilFormat(dawn::TextureFormat depthStencilFormat) { - switch (depthStencilFormat) { - case dawn::TextureFormat::Depth24PlusStencil8: - return 0xFF; - default: - UNREACHABLE(); - } - } - // Vertex buffers and index buffers are implemented as part of an OpenGL VAO that // corresponds to an VertexInput. On the contrary in Dawn they are part of the global state. // This means that we have to re-apply these buffers on an VertexInput change. @@ -349,17 +341,34 @@ namespace dawn_native { namespace opengl { void CommandBuffer::Execute() { const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; + auto TransitionForPass = [](const PassResourceUsage& usages) { + for (size_t i = 0; i < usages.textures.size(); i++) { + Texture* texture = ToBackend(usages.textures[i]); + texture->EnsureSubresourceContentInitialized(0, texture->GetNumMipLevels(), 0, + texture->GetArrayLayers()); + } + }; + + const std::vector& passResourceUsages = GetResourceUsages().perPass; + uint32_t nextPassNumber = 0; + Command type; while (mCommands.NextCommandId(&type)) { switch (type) { case Command::BeginComputePass: { mCommands.NextCommand(); + TransitionForPass(passResourceUsages[nextPassNumber]); ExecuteComputePass(); + + nextPassNumber++; } break; case Command::BeginRenderPass: { auto* cmd = mCommands.NextCommand(); + TransitionForPass(passResourceUsages[nextPassNumber]); ExecuteRenderPass(cmd); + + nextPassNumber++; } break; case Command::CopyBufferToBuffer: { @@ -384,6 +393,11 @@ namespace dawn_native { namespace opengl { Texture* texture = ToBackend(dst.texture.Get()); GLenum target = texture->GetGLTarget(); auto format = texture->GetGLFormat(); + if (IsCompleteSubresourceCopiedTo(texture, copySize, dst.level)) { + texture->SetIsSubresourceContentInitialized(dst.level, 1, dst.slice, 1); + } else { + texture->EnsureSubresourceContentInitialized(dst.level, 1, dst.slice, 1); + } gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->GetHandle()); gl.ActiveTexture(GL_TEXTURE0); @@ -426,6 +440,7 @@ namespace dawn_native { namespace opengl { auto format = texture->GetGLFormat(); GLenum target = texture->GetGLTarget(); + texture->EnsureSubresourceContentInitialized(src.level, 1, src.slice, 1); // The only way to move data from a texture to a buffer in GL is via // glReadPixels with a pack buffer. Create a temporary FBO for the copy. gl.BindTexture(target, texture->GetHandle()); @@ -473,7 +488,12 @@ namespace dawn_native { namespace opengl { auto& copySize = copy->copySize; Texture* srcTexture = ToBackend(src.texture.Get()); Texture* dstTexture = ToBackend(dst.texture.Get()); - + srcTexture->EnsureSubresourceContentInitialized(src.level, 1, src.slice, 1); + if (IsCompleteSubresourceCopiedTo(dstTexture, copySize, dst.level)) { + dstTexture->SetIsSubresourceContentInitialized(dst.level, 1, dst.slice, 1); + } else { + dstTexture->EnsureSubresourceContentInitialized(dst.level, 1, dst.slice, 1); + } gl.CopyImageSubData(srcTexture->GetHandle(), srcTexture->GetGLTarget(), src.level, src.origin.x, src.origin.y, src.slice, dstTexture->GetHandle(), dstTexture->GetGLTarget(), @@ -683,7 +703,6 @@ namespace dawn_native { namespace opengl { if (renderPass->sampleCount > 1) { ResolveMultisampledRenderTargets(gl, renderPass); } - gl.DeleteFramebuffers(1, &fbo); return; } break; diff --git a/src/dawn_native/opengl/TextureGL.cpp b/src/dawn_native/opengl/TextureGL.cpp index 3c5f01d8e6..ade6652605 100644 --- a/src/dawn_native/opengl/TextureGL.cpp +++ b/src/dawn_native/opengl/TextureGL.cpp @@ -14,8 +14,10 @@ #include "dawn_native/opengl/TextureGL.h" #include "dawn_native/opengl/DeviceGL.h" +#include "dawn_native/opengl/UtilsGL.h" #include "common/Assert.h" +#include "dawn_native/Commands.h" #include #include @@ -174,9 +176,8 @@ namespace dawn_native { namespace opengl { 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 < GL_TEXTURE_MAX_LEVEL; i++) { + for (uint32_t i = 0; i < GetNumMipLevels(); i++) { gl.ClearTexImage(mHandle, i, formatInfo.format, formatInfo.type, clearColor); } } @@ -211,6 +212,60 @@ namespace dawn_native { namespace opengl { return GetGLFormatInfo(GetFormat().format); } + void Texture::ClearTexture(GLint baseMipLevel, + GLint levelCount, + GLint baseArrayLayer, + uint32_t layerCount) { + const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; + 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)); + } + + 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); + } + gl.DeleteFramebuffers(1, &framebuffer); + } else { + auto formatInfo = GetGLFormatInfo(GetFormat().format); + for (GLint level = baseMipLevel; level < baseMipLevel + levelCount; ++level) { + gl.ClearTexSubImage(mHandle, level, 0, 0, baseArrayLayer, GetSize().width, + GetSize().height, layerCount, formatInfo.format, + formatInfo.type, nullptr); + } + } + SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount); + } + + void Texture::EnsureSubresourceContentInitialized(uint32_t baseMipLevel, + uint32_t levelCount, + uint32_t baseArrayLayer, + uint32_t layerCount) { + if (!GetDevice()->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) { + return; + } + if (!IsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, + layerCount)) { + ClearTexture(baseMipLevel, levelCount, baseArrayLayer, layerCount); + } + } + // TextureView TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor) diff --git a/src/dawn_native/opengl/TextureGL.h b/src/dawn_native/opengl/TextureGL.h index cf17f13b03..28dc2382ae 100644 --- a/src/dawn_native/opengl/TextureGL.h +++ b/src/dawn_native/opengl/TextureGL.h @@ -42,8 +42,17 @@ namespace dawn_native { namespace opengl { GLenum GetGLTarget() const; TextureFormatInfo GetGLFormat() const; + void EnsureSubresourceContentInitialized(uint32_t baseMipLevel, + uint32_t levelCount, + uint32_t baseArrayLayer, + uint32_t layerCount); + private: void DestroyImpl() override; + void ClearTexture(GLint baseMipLevel, + GLint levelCount, + GLint baseArrayLayer, + uint32_t layerCount); GLuint mHandle; GLenum mTarget; diff --git a/src/dawn_native/opengl/UtilsGL.cpp b/src/dawn_native/opengl/UtilsGL.cpp index 0419d4be99..00a4fca961 100644 --- a/src/dawn_native/opengl/UtilsGL.cpp +++ b/src/dawn_native/opengl/UtilsGL.cpp @@ -41,4 +41,12 @@ namespace dawn_native { namespace opengl { } } + GLint GetStencilMaskFromStencilFormat(dawn::TextureFormat depthStencilFormat) { + switch (depthStencilFormat) { + case dawn::TextureFormat::Depth24PlusStencil8: + return 0xFF; + default: + UNREACHABLE(); + } + } }} // namespace dawn_native::opengl diff --git a/src/dawn_native/opengl/UtilsGL.h b/src/dawn_native/opengl/UtilsGL.h index 12bb741158..5c8f8ed45e 100644 --- a/src/dawn_native/opengl/UtilsGL.h +++ b/src/dawn_native/opengl/UtilsGL.h @@ -21,7 +21,7 @@ namespace dawn_native { namespace opengl { GLuint ToOpenGLCompareFunction(dawn::CompareFunction compareFunction); - + GLint GetStencilMaskFromStencilFormat(dawn::TextureFormat depthStencilFormat); }} // namespace dawn_native::opengl #endif // DAWNNATIVE_OPENGL_UTILSGL_H_ diff --git a/src/tests/end2end/TextureZeroInitTests.cpp b/src/tests/end2end/TextureZeroInitTests.cpp index f469d05488..81ede5d6ed 100644 --- a/src/tests/end2end/TextureZeroInitTests.cpp +++ b/src/tests/end2end/TextureZeroInitTests.cpp @@ -403,8 +403,29 @@ TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencil) { EXPECT_TEXTURE_RGBA8_EQ(expected.data(), srcTexture, 0, 0, kSize, kSize, 0, 0); } -DAWN_INSTANTIATE_TEST(TextureZeroInitTest, - ForceWorkarounds(D3D12Backend, - {"nonzero_clear_resources_on_creation_for_testing"}), - ForceWorkarounds(VulkanBackend, - {"nonzero_clear_resources_on_creation_for_testing"})); +// This tests the color attachments clear to 0s +TEST_P(TextureZeroInitTest, ColorAttachmentsClear) { + dawn::TextureDescriptor descriptor = CreateTextureDescriptor( + 1, 1, dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::TransferSrc, + kColorFormat); + dawn::Texture texture = device.CreateTexture(&descriptor); + utils::BasicRenderPass renderPass = utils::BasicRenderPass(kSize, kSize, texture, kColorFormat); + renderPass.renderPassInfo.cColorAttachmentsInfoPtr[0]->loadOp = dawn::LoadOp::Load; + + dawn::CommandEncoder encoder = device.CreateCommandEncoder(); + { + dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo); + pass.EndPass(); + } + dawn::CommandBuffer commands = encoder.Finish(); + queue.Submit(1, &commands); + + std::vector expected(kSize * kSize, {0, 0, 0, 0}); + EXPECT_TEXTURE_RGBA8_EQ(expected.data(), renderPass.color, 0, 0, kSize, kSize, 0, 0); +} + +DAWN_INSTANTIATE_TEST( + TextureZeroInitTest, + ForceWorkarounds(D3D12Backend, {"nonzero_clear_resources_on_creation_for_testing"}), + ForceWorkarounds(OpenGLBackend, {"nonzero_clear_resources_on_creation_for_testing"}), + ForceWorkarounds(VulkanBackend, {"nonzero_clear_resources_on_creation_for_testing"}));