diff --git a/source/graphics/LOSTexture.cpp b/source/graphics/LOSTexture.cpp index 4db23a206e..d003cac670 100644 --- a/source/graphics/LOSTexture.cpp +++ b/source/graphics/LOSTexture.cpp @@ -281,10 +281,16 @@ void CLOSTexture::ConstructTexture(Renderer::Backend::IDeviceCommandContext* dev m_SmoothTextures[1] = backendDevice->CreateTexture2D("LOSSmoothTexture1", usage, m_TextureFormat, textureSize, textureSize, defaultSamplerDesc); + Renderer::Backend::SColorAttachment colorAttachment{}; + colorAttachment.texture = m_SmoothTextures[0].get(); + colorAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::DONT_CARE; + colorAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + colorAttachment.clearColor = CColor{0.0f, 0.0f, 0.0f, 0.0f}; m_SmoothFramebuffers[0] = backendDevice->CreateFramebuffer( - "LOSSmoothFramebuffer0", m_SmoothTextures[0].get(), nullptr); + "LOSSmoothFramebuffer0", &colorAttachment, nullptr); + colorAttachment.texture = m_SmoothTextures[1].get(); m_SmoothFramebuffers[1] = backendDevice->CreateFramebuffer( - "LOSSmoothFramebuffer1", m_SmoothTextures[1].get(), nullptr); + "LOSSmoothFramebuffer1", &colorAttachment, nullptr); if (!m_SmoothFramebuffers[0] || !m_SmoothFramebuffers[1]) { LOGERROR("Failed to create LOS framebuffers"); diff --git a/source/graphics/MiniMapTexture.cpp b/source/graphics/MiniMapTexture.cpp index 7249077c6a..a04a319996 100644 --- a/source/graphics/MiniMapTexture.cpp +++ b/source/graphics/MiniMapTexture.cpp @@ -355,8 +355,13 @@ void CMiniMapTexture::CreateTextures( Renderer::Backend::Format::R8G8B8A8_UNORM, FINAL_TEXTURE_SIZE, FINAL_TEXTURE_SIZE, defaultSamplerDesc)); - m_FinalTextureFramebuffer = backendDevice->CreateFramebuffer("MiniMapFinalFramebuffer", - m_FinalTexture->GetBackendTexture(), nullptr); + Renderer::Backend::SColorAttachment colorAttachment{}; + colorAttachment.texture = m_FinalTexture->GetBackendTexture(); + colorAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::DONT_CARE; + colorAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + colorAttachment.clearColor = CColor{0.0f, 0.0f, 0.0f, 0.0f}; + m_FinalTextureFramebuffer = backendDevice->CreateFramebuffer( + "MiniMapFinalFramebuffer", &colorAttachment, nullptr); ENSURE(m_FinalTextureFramebuffer); } diff --git a/source/renderer/PostprocManager.cpp b/source/renderer/PostprocManager.cpp index 54456d4400..db96124520 100644 --- a/source/renderer/PostprocManager.cpp +++ b/source/renderer/PostprocManager.cpp @@ -148,8 +148,13 @@ void CPostprocManager::RecreateBuffers() for (BlurScale::Step& step : scale.steps) { GEN_BUFFER_RGBA(step.texture, width, height); - step.framebuffer = backendDevice->CreateFramebuffer("BlurScaleSteoFramebuffer", - step.texture.get(), nullptr); + Renderer::Backend::SColorAttachment colorAttachment{}; + colorAttachment.texture = step.texture.get(); + colorAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::LOAD; + colorAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + colorAttachment.clearColor = CColor{0.0f, 0.0f, 0.0f, 0.0f}; + step.framebuffer = backendDevice->CreateFramebuffer( + "BlurScaleSteoFramebuffer", &colorAttachment, nullptr); } width /= 2; height /= 2; @@ -167,13 +172,29 @@ void CPostprocManager::RecreateBuffers() Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE)); // Set up the framebuffers with some initial textures. - m_CaptureFramebuffer = backendDevice->CreateFramebuffer("PostprocCaptureFramebuffer", - m_ColorTex1.get(), m_DepthTex.get(), CColor(0.0f, 0.0f, 0.0f, 0.0f)); + Renderer::Backend::SColorAttachment colorAttachment{}; + colorAttachment.texture = m_ColorTex1.get(); + colorAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::DONT_CARE; + colorAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + colorAttachment.clearColor = CColor{0.0f, 0.0f, 0.0f, 0.0f}; + Renderer::Backend::SDepthStencilAttachment depthStencilAttachment{}; + depthStencilAttachment.texture = m_DepthTex.get(); + depthStencilAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::CLEAR; + depthStencilAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + + m_CaptureFramebuffer = backendDevice->CreateFramebuffer("PostprocCaptureFramebuffer", + &colorAttachment, &depthStencilAttachment); + + colorAttachment.texture = m_ColorTex1.get(); + colorAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::LOAD; + colorAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; m_PingFramebuffer = backendDevice->CreateFramebuffer("PostprocPingFramebuffer", - m_ColorTex1.get(), nullptr); + &colorAttachment, nullptr); + + colorAttachment.texture = m_ColorTex2.get(); m_PongFramebuffer = backendDevice->CreateFramebuffer("PostprocPongFramebuffer", - m_ColorTex2.get(), nullptr); + &colorAttachment, nullptr); if (!m_CaptureFramebuffer || !m_PingFramebuffer || !m_PongFramebuffer) { @@ -403,7 +424,8 @@ void CPostprocManager::CaptureRenderOutput( void CPostprocManager::ReleaseRenderOutput( - Renderer::Backend::IDeviceCommandContext* deviceCommandContext) + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IFramebuffer* destination) { ENSURE(m_IsInitialized); @@ -411,8 +433,7 @@ void CPostprocManager::ReleaseRenderOutput( // We blit to the backbuffer from the previous active buffer. deviceCommandContext->BlitFramebuffer( - deviceCommandContext->GetDevice()->GetCurrentBackbuffer(), - (m_WhichBuffer ? m_PingFramebuffer : m_PongFramebuffer).get()); + destination, (m_WhichBuffer ? m_PingFramebuffer : m_PongFramebuffer).get()); } void CPostprocManager::ApplyEffect( @@ -675,8 +696,19 @@ void CPostprocManager::CreateMultisampleBuffer() Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, m_MultisampleCount); // Set up the framebuffers with some initial textures. - m_MultisampleFramebuffer = backendDevice->CreateFramebuffer("PostprocMultisampleFramebuffer", - m_MultisampleColorTex.get(), m_MultisampleDepthTex.get(), CColor(0.0f, 0.0f, 0.0f, 0.0f)); + Renderer::Backend::SColorAttachment colorAttachment{}; + colorAttachment.texture = m_MultisampleColorTex.get(); + colorAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::DONT_CARE; + colorAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + colorAttachment.clearColor = CColor{0.0f, 0.0f, 0.0f, 0.0f}; + + Renderer::Backend::SDepthStencilAttachment depthStencilAttachment{}; + depthStencilAttachment.texture = m_MultisampleDepthTex.get(); + depthStencilAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::CLEAR; + depthStencilAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + + m_MultisampleFramebuffer = backendDevice->CreateFramebuffer( + "PostprocMultisampleFramebuffer", &colorAttachment, &depthStencilAttachment); if (!m_MultisampleFramebuffer) { diff --git a/source/renderer/PostprocManager.h b/source/renderer/PostprocManager.h index 997c9fad0a..4ef03ba720 100644 --- a/source/renderer/PostprocManager.h +++ b/source/renderer/PostprocManager.h @@ -74,10 +74,13 @@ public: void ApplyPostproc( Renderer::Backend::IDeviceCommandContext* deviceCommandContext); - // Blits the final postprocessed texture to the system framebuffer. The system framebuffer - // is selected as the output buffer. Should be called before silhouette rendering. + // Blits the final postprocessed texture to the system framebuffer. The system + // framebuffer is selected as the output buffer. Should be called before + // silhouette rendering. // @note CPostprocManager must be initialized first - void ReleaseRenderOutput(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); + void ReleaseRenderOutput( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IFramebuffer* destination); // Returns true if we render main scene in the MSAA framebuffer. bool IsMultisampleEnabled() const; diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index c1e9939c59..ce5f7925ac 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -482,8 +482,14 @@ void CRenderer::RenderFrameImpl(const bool renderGUI, const bool renderLogger) } else { + // We don't need to clear the color attachment of the framebuffer as the sky + // is going to be rendered anyway. m->deviceCommandContext->BeginFramebufferPass( - m->deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); + m->deviceCommandContext->GetDevice()->GetCurrentBackbuffer( + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::STORE, + Renderer::Backend::AttachmentLoadOp::CLEAR, + Renderer::Backend::AttachmentStoreOp::DONT_CARE)); } g_Game->GetView()->Render(m->deviceCommandContext.get()); @@ -496,18 +502,35 @@ void CRenderer::RenderFrameImpl(const bool renderGUI, const bool renderLogger) postprocManager.ResolveMultisampleFramebuffer(m->deviceCommandContext.get()); postprocManager.ApplyPostproc(m->deviceCommandContext.get()); - postprocManager.ReleaseRenderOutput(m->deviceCommandContext.get()); - m->deviceCommandContext->BeginFramebufferPass( - m->deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); + Renderer::Backend::IFramebuffer* backbuffer = + m->deviceCommandContext->GetDevice()->GetCurrentBackbuffer( + Renderer::Backend::AttachmentLoadOp::LOAD, + Renderer::Backend::AttachmentStoreOp::STORE, + Renderer::Backend::AttachmentLoadOp::LOAD, + Renderer::Backend::AttachmentStoreOp::DONT_CARE); + postprocManager.ReleaseRenderOutput( + m->deviceCommandContext.get(), backbuffer); + + m->deviceCommandContext->BeginFramebufferPass(backbuffer); } g_Game->GetView()->RenderOverlays(m->deviceCommandContext.get()); + + g_Game->GetView()->GetCinema()->Render(); } else { + // We have a fullscreen background in our UI so we don't need + // to clear the color attachment. + // We don't need a depth test to render so we don't care about the + // depth-stencil attachment content. m->deviceCommandContext->BeginFramebufferPass( - m->deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); + m->deviceCommandContext->GetDevice()->GetCurrentBackbuffer( + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::STORE, + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::DONT_CARE)); } // If we're in Atlas game view, render special tools @@ -516,11 +539,6 @@ void CRenderer::RenderFrameImpl(const bool renderGUI, const bool renderLogger) g_AtlasGameLoop->view->DrawCinemaPathTool(); } - if (g_Game && g_Game->IsGameStarted()) - { - g_Game->GetView()->GetCinema()->Render(); - } - RenderFrame2D(renderGUI, renderLogger); m->deviceCommandContext->EndFramebufferPass(); diff --git a/source/renderer/SceneRenderer.cpp b/source/renderer/SceneRenderer.cpp index 58531261da..242a751e0a 100644 --- a/source/renderer/SceneRenderer.cpp +++ b/source/renderer/SceneRenderer.cpp @@ -589,7 +589,6 @@ void CSceneRenderer::RenderReflections( deviceCommandContext->SetGraphicsPipelineState( Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); deviceCommandContext->BeginFramebufferPass(wm.m_ReflectionFramebuffer.get()); - deviceCommandContext->ClearFramebuffer(); CShaderDefines reflectionsContext = context; reflectionsContext.Add(str_PASS_REFLECTIONS, str_1); @@ -665,7 +664,6 @@ void CSceneRenderer::RenderRefractions( deviceCommandContext->SetGraphicsPipelineState( Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); deviceCommandContext->BeginFramebufferPass(wm.m_RefractionFramebuffer.get()); - deviceCommandContext->ClearFramebuffer(); // Render terrain and models RenderPatches(deviceCommandContext, context, CULL_REFRACTIONS); @@ -841,13 +839,6 @@ void CSceneRenderer::RenderSubmissions( constexpr int cullGroup = CULL_DEFAULT; - { - PROFILE3_GPU("clear buffers"); - // We don't need to clear the color attachment of the framebuffer if the sky - // is going to be rendered. Because it covers the whole view. - deviceCommandContext->ClearFramebuffer(!m->skyManager.IsSkyVisible(), true, true); - } - m->skyManager.RenderSky(deviceCommandContext); // render submitted patches and models diff --git a/source/renderer/ShadowMap.cpp b/source/renderer/ShadowMap.cpp index 7e63358748..af1cd107be 100644 --- a/source/renderer/ShadowMap.cpp +++ b/source/renderer/ShadowMap.cpp @@ -510,7 +510,7 @@ void ShadowMapInternals::CreateTexture() const char* formatName; Renderer::Backend::Format backendFormat = Renderer::Backend::Format::UNDEFINED; #if CONFIG2_GLES - formatName = "DEPTH_COMPONENT"; + formatName = "Format::D24"; backendFormat = Renderer::Backend::Format::D24; #else switch (DepthTextureBits) @@ -556,9 +556,24 @@ void ShadowMapInternals::CreateTexture() Renderer::Backend::ITexture::Usage::DEPTH_STENCIL_ATTACHMENT, backendFormat, Width, Height, samplerDesc); - Framebuffer = backendDevice->CreateFramebuffer("ShadowMapFramebuffer", - g_RenderingOptions.GetShadowAlphaFix() ? DummyTexture.get() : nullptr, Texture.get()); + const bool useDummyTexture = g_RenderingOptions.GetShadowAlphaFix(); + // In case we used ShadowAlphaFix, we ought to clear the unused + // color buffer too, else Mali 400 drivers get confused. + // Might as well clear stencil too for completeness. + Renderer::Backend::SColorAttachment colorAttachment{}; + colorAttachment.texture = DummyTexture.get(); + colorAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::CLEAR; + colorAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::DONT_CARE; + colorAttachment.clearColor = CColor{0.0f, 0.0f, 0.0f, 0.0f}; + + Renderer::Backend::SDepthStencilAttachment depthStencilAttachment{}; + depthStencilAttachment.texture = Texture.get(); + depthStencilAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::CLEAR; + depthStencilAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + + Framebuffer = backendDevice->CreateFramebuffer("ShadowMapFramebuffer", + useDummyTexture ? &colorAttachment : nullptr, &depthStencilAttachment); if (!Framebuffer) { LOGERROR("Failed to create shadows framebuffer"); @@ -574,20 +589,8 @@ void ShadowMap::BeginRender( deviceCommandContext->SetGraphicsPipelineState( Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); - { - PROFILE("bind framebuffer"); - ENSURE(m->Framebuffer); - deviceCommandContext->BeginFramebufferPass(m->Framebuffer.get()); - } - - // clear buffers - { - PROFILE("clear depth texture"); - // In case we used m_ShadowAlphaFix, we ought to clear the unused - // color buffer too, else Mali 400 drivers get confused. - // Might as well clear stencil too for completeness. - deviceCommandContext->ClearFramebuffer(); - } + ENSURE(m->Framebuffer); + deviceCommandContext->BeginFramebufferPass(m->Framebuffer.get()); m->SavedViewCamera = g_Renderer.GetSceneRenderer().GetViewCamera(); } diff --git a/source/renderer/SkyManager.cpp b/source/renderer/SkyManager.cpp index 961192c0bc..72b70f98bc 100644 --- a/source/renderer/SkyManager.cpp +++ b/source/renderer/SkyManager.cpp @@ -212,12 +212,10 @@ void SkyManager::RenderSky( { GPU_SCOPED_LABEL(deviceCommandContext, "Render sky"); - if (!m_SkyVisible) - return; - - // Do nothing unless SetSkySet was called - if (m_SkySet.empty() || !m_SkyTextureCube) - return; + const CTexturePtr& skyTextureCube = + !m_SkyVisible || m_SkySet.empty() || !m_SkyTextureCube + ? g_Renderer.GetTextureManager().GetBlackTextureCube() + : m_SkyTextureCube; const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); @@ -228,7 +226,7 @@ void SkyManager::RenderSky( deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = skytech->GetShader(); deviceCommandContext->SetTexture( - shader->GetBindingSlot(str_baseTex), m_SkyTextureCube->GetBackendTexture()); + shader->GetBindingSlot(str_baseTex), skyTextureCube->GetBackendTexture()); // Translate so the sky center is at the camera space origin. CMatrix3D translate; diff --git a/source/renderer/WaterManager.cpp b/source/renderer/WaterManager.cpp index 6fb6b20713..084592629d 100644 --- a/source/renderer/WaterManager.cpp +++ b/source/renderer/WaterManager.cpp @@ -218,13 +218,24 @@ void WaterManager::RecreateOrLoadTexturesIfNeeded() m_ReflFboDepthTexture = backendDevice->CreateTexture2D("WaterReflectionDepthTexture", Renderer::Backend::ITexture::Usage::SAMPLED | Renderer::Backend::ITexture::Usage::DEPTH_STENCIL_ATTACHMENT, - Renderer::Backend::Format::D32, m_RefTextureSize, m_RefTextureSize, + Renderer::Backend::Format::D24, m_RefTextureSize, m_RefTextureSize, Renderer::Backend::Sampler::MakeDefaultSampler( Renderer::Backend::Sampler::Filter::NEAREST, Renderer::Backend::Sampler::AddressMode::REPEAT)); + Renderer::Backend::SColorAttachment colorAttachment{}; + colorAttachment.texture = m_ReflectionTexture.get(); + colorAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::CLEAR; + colorAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + colorAttachment.clearColor = CColor{0.5f, 0.5f, 1.0f, 0.0f}; + + Renderer::Backend::SDepthStencilAttachment depthStencilAttachment{}; + depthStencilAttachment.texture = m_ReflFboDepthTexture.get(); + depthStencilAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::CLEAR; + depthStencilAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + m_ReflectionFramebuffer = backendDevice->CreateFramebuffer("ReflectionFramebuffer", - m_ReflectionTexture.get(), m_ReflFboDepthTexture.get(), CColor(0.5f, 0.5f, 1.0f, 0.0f)); + &colorAttachment, &depthStencilAttachment); if (!m_ReflectionFramebuffer) { g_RenderingOptions.SetWaterReflection(false); @@ -249,13 +260,24 @@ void WaterManager::RecreateOrLoadTexturesIfNeeded() m_RefrFboDepthTexture = backendDevice->CreateTexture2D("WaterRefractionDepthTexture", Renderer::Backend::ITexture::Usage::SAMPLED | Renderer::Backend::ITexture::Usage::DEPTH_STENCIL_ATTACHMENT, - Renderer::Backend::Format::D32, m_RefTextureSize, m_RefTextureSize, + Renderer::Backend::Format::D24, m_RefTextureSize, m_RefTextureSize, Renderer::Backend::Sampler::MakeDefaultSampler( Renderer::Backend::Sampler::Filter::NEAREST, Renderer::Backend::Sampler::AddressMode::REPEAT)); + Renderer::Backend::SColorAttachment colorAttachment{}; + colorAttachment.texture = m_RefractionTexture.get(); + colorAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::CLEAR; + colorAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + colorAttachment.clearColor = CColor{1.0f, 0.0f, 0.0f, 0.0f}; + + Renderer::Backend::SDepthStencilAttachment depthStencilAttachment{}; + depthStencilAttachment.texture = m_RefrFboDepthTexture.get(); + depthStencilAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::CLEAR; + depthStencilAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + m_RefractionFramebuffer = backendDevice->CreateFramebuffer("RefractionFramebuffer", - m_RefractionTexture.get(), m_RefrFboDepthTexture.get(), CColor(1.0f, 0.0f, 0.0f, 0.0f)); + &colorAttachment, &depthStencilAttachment); if (!m_RefractionFramebuffer) { g_RenderingOptions.SetWaterRefraction(false); @@ -288,13 +310,24 @@ void WaterManager::RecreateOrLoadTexturesIfNeeded() m_FancyTextureDepth = backendDevice->CreateTexture2D("WaterFancyDepthTexture", Renderer::Backend::ITexture::Usage::DEPTH_STENCIL_ATTACHMENT, - Renderer::Backend::Format::D32, g_Renderer.GetWidth(), g_Renderer.GetHeight(), + Renderer::Backend::Format::D24, g_Renderer.GetWidth(), g_Renderer.GetHeight(), Renderer::Backend::Sampler::MakeDefaultSampler( Renderer::Backend::Sampler::Filter::LINEAR, Renderer::Backend::Sampler::AddressMode::REPEAT)); + Renderer::Backend::SColorAttachment colorAttachment{}; + colorAttachment.texture = m_FancyTexture.get(); + colorAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::CLEAR; + colorAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::STORE; + colorAttachment.clearColor = CColor{0.0f, 0.0f, 0.0f, 0.0f}; + + Renderer::Backend::SDepthStencilAttachment depthStencilAttachment{}; + depthStencilAttachment.texture = m_FancyTextureDepth.get(); + depthStencilAttachment.loadOp = Renderer::Backend::AttachmentLoadOp::CLEAR; + depthStencilAttachment.storeOp = Renderer::Backend::AttachmentStoreOp::DONT_CARE; + m_FancyEffectsFramebuffer = backendDevice->CreateFramebuffer("FancyEffectsFramebuffer", - m_FancyTexture.get(), m_FancyTextureDepth.get()); + &colorAttachment, &depthStencilAttachment); if (!m_FancyEffectsFramebuffer) { g_RenderingOptions.SetWaterRefraction(false); @@ -810,7 +843,6 @@ void WaterManager::RenderWaves( deviceCommandContext->SetGraphicsPipelineState( Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); deviceCommandContext->BeginFramebufferPass(m_FancyEffectsFramebuffer.get()); - deviceCommandContext->ClearFramebuffer(); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_water_waves); deviceCommandContext->SetGraphicsPipelineState( diff --git a/source/renderer/backend/IDevice.h b/source/renderer/backend/IDevice.h index da9632f11f..85a35e4649 100644 --- a/source/renderer/backend/IDevice.h +++ b/source/renderer/backend/IDevice.h @@ -72,8 +72,6 @@ public: virtual void Report(const ScriptRequest& rq, JS::HandleValue settings) = 0; - virtual IFramebuffer* GetCurrentBackbuffer() = 0; - virtual std::unique_ptr CreateCommandContext() = 0; virtual std::unique_ptr CreateTexture( @@ -86,13 +84,19 @@ public: const Format format, const uint32_t width, const uint32_t height, const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) = 0; + /** + * @see IFramebuffer + * + * The color attachment and the depth-stencil attachment should not be + * nullptr at the same time. There should not be many different clear + * colors along all color attachments for all framebuffers created for + * the device. + * + * @return A valid framebuffer if it was created successfully else nullptr. + */ virtual std::unique_ptr CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment) = 0; - - virtual std::unique_ptr CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment, const CColor& clearColor) = 0; + const char* name, SColorAttachment* colorAttachment, + SDepthStencilAttachment* depthStencilAttachment) = 0; virtual std::unique_ptr CreateBuffer( const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) = 0; @@ -100,7 +104,36 @@ public: virtual std::unique_ptr CreateShaderProgram( const CStr& name, const CShaderDefines& defines) = 0; + /** + * Acquires a backbuffer for rendering a frame. + * + * @return True if it was successfully acquired and we can render to it. + */ virtual bool AcquireNextBackbuffer() = 0; + + /** + * Returns a framebuffer for the current backbuffer with the required + * attachment operations. It should not be called if the last + * AcquireNextBackbuffer call returned false. + * + * It's guaranteed that for the same acquired backbuffer this function returns + * a framebuffer with the same attachments and properties except load and + * store operations. + * + * @return The last successfully acquired framebuffer that wasn't + * presented. + */ + virtual IFramebuffer* GetCurrentBackbuffer( + const AttachmentLoadOp colorAttachmentLoadOp, + const AttachmentStoreOp colorAttachmentStoreOp, + const AttachmentLoadOp depthStencilAttachmentLoadOp, + const AttachmentStoreOp depthStencilAttachmentStoreOp) = 0; + + /** + * Presents the backbuffer to the swapchain queue to be flipped on a + * screen. Should be called only if the last AcquireNextBackbuffer call + * returned true. + */ virtual void Present() = 0; virtual bool IsTextureFormatSupported(const Format format) const = 0; diff --git a/source/renderer/backend/IDeviceCommandContext.h b/source/renderer/backend/IDeviceCommandContext.h index 10ef729496..d8263019d7 100644 --- a/source/renderer/backend/IDeviceCommandContext.h +++ b/source/renderer/backend/IDeviceCommandContext.h @@ -45,10 +45,25 @@ public: virtual void BlitFramebuffer( IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer) = 0; - virtual void ClearFramebuffer() = 0; - virtual void ClearFramebuffer(const bool color, const bool depth, const bool stencil) = 0; + /** + * Starts a framebuffer pass, performs attachment load operations. + * It should be called as rarely as possible. + * + * @see IFramebuffer + */ virtual void BeginFramebufferPass(IFramebuffer* framebuffer) = 0; + + /** + * Finishes a framebuffer pass, performs attachment store operations. + */ virtual void EndFramebufferPass() = 0; + + /** + * Clears all mentioned attachments. Prefer to use attachment load operations over + * this function. It should be called only inside a framebuffer pass. + */ + virtual void ClearFramebuffer(const bool color, const bool depth, const bool stencil) = 0; + virtual void ReadbackFramebufferSync( const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height, void* data) = 0; diff --git a/source/renderer/backend/IFramebuffer.h b/source/renderer/backend/IFramebuffer.h index d9a58e1ea9..f1ea5a70ef 100644 --- a/source/renderer/backend/IFramebuffer.h +++ b/source/renderer/backend/IFramebuffer.h @@ -27,9 +27,67 @@ namespace Renderer namespace Backend { +class ITexture; + +/** + * Load operation is set for each attachment, what should be done with its + * content on BeginFramebufferPass. + */ +enum class AttachmentLoadOp +{ + // Loads the attachment content. + LOAD, + // Clears the attachment content without loading. Prefer to use that + // operation over manual ClearFramebuffer. + CLEAR, + // After BeginFramebufferPass the attachment content is undefined. + DONT_CARE +}; + +/** + * Store operation is set for each attachment, what should be done with its + * content on EndFramebufferPass. + */ +enum class AttachmentStoreOp +{ + // Stores the attachment content. + STORE, + // After EndFramebufferPass the attachment content is undefined. + DONT_CARE +}; + +struct SColorAttachment +{ + ITexture* texture = nullptr; + AttachmentLoadOp loadOp = AttachmentLoadOp::DONT_CARE; + AttachmentStoreOp storeOp = AttachmentStoreOp::DONT_CARE; + CColor clearColor; +}; + +struct SDepthStencilAttachment +{ + ITexture* texture = nullptr; + AttachmentLoadOp loadOp = AttachmentLoadOp::DONT_CARE; + AttachmentStoreOp storeOp = AttachmentStoreOp::DONT_CARE; +}; + +/** + * IFramebuffer stores attachments which should be used by backend as rendering + * destinations. That combining allows to set these destinations at once. + * IFramebuffer doesn't own its attachments so clients must keep them alive. + * The number of framebuffers ever created for a device during its lifetime + * should be as small as possible. + * + * Framebuffer is a term from OpenGL/Vulkan worlds (D3D synonym is a render + * target). + */ class IFramebuffer : public IDeviceObject { public: + /** + * Returns a clear color for all color attachments of the framebuffer. + * @see IDevice::CreateFramebuffer() + */ virtual const CColor& GetClearColor() const = 0; }; diff --git a/source/renderer/backend/dummy/Device.cpp b/source/renderer/backend/dummy/Device.cpp index 5549c4e2ef..90a9586a9c 100644 --- a/source/renderer/backend/dummy/Device.cpp +++ b/source/renderer/backend/dummy/Device.cpp @@ -91,13 +91,7 @@ std::unique_ptr CDevice::CreateTexture2D( } std::unique_ptr CDevice::CreateFramebuffer( - const char*, ITexture*, ITexture*) -{ - return CFramebuffer::Create(this); -} - -std::unique_ptr CDevice::CreateFramebuffer( - const char*, ITexture*, ITexture*, const CColor&) + const char*, SColorAttachment*, SDepthStencilAttachment*) { return CFramebuffer::Create(this); } @@ -120,6 +114,13 @@ bool CDevice::AcquireNextBackbuffer() return true; } +IFramebuffer* CDevice::GetCurrentBackbuffer( + const AttachmentLoadOp, const AttachmentStoreOp, + const AttachmentLoadOp, const AttachmentStoreOp) +{ + return m_Backbuffer.get(); +} + void CDevice::Present() { // We have nothing to present. diff --git a/source/renderer/backend/dummy/Device.h b/source/renderer/backend/dummy/Device.h index 5761579f3d..41419ba304 100644 --- a/source/renderer/backend/dummy/Device.h +++ b/source/renderer/backend/dummy/Device.h @@ -49,8 +49,6 @@ public: void Report(const ScriptRequest& rq, JS::HandleValue settings) override; - IFramebuffer* GetCurrentBackbuffer() override { return m_Backbuffer.get(); } - std::unique_ptr CreateCommandContext() override; std::unique_ptr CreateTexture( @@ -64,12 +62,8 @@ public: const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) override; std::unique_ptr CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment) override; - - std::unique_ptr CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment, const CColor& clearColor) override; + const char* name, SColorAttachment* colorAttachment, + SDepthStencilAttachment* depthStencilAttachment) override; std::unique_ptr CreateBuffer( const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) override; @@ -78,6 +72,11 @@ public: const CStr& name, const CShaderDefines& defines) override; bool AcquireNextBackbuffer() override; + + IFramebuffer* GetCurrentBackbuffer( + const AttachmentLoadOp, const AttachmentStoreOp, + const AttachmentLoadOp, const AttachmentStoreOp) override; + void Present() override; bool IsTextureFormatSupported(const Format format) const override; diff --git a/source/renderer/backend/dummy/DeviceCommandContext.cpp b/source/renderer/backend/dummy/DeviceCommandContext.cpp index 33d8c9f99b..cbb6f8626f 100644 --- a/source/renderer/backend/dummy/DeviceCommandContext.cpp +++ b/source/renderer/backend/dummy/DeviceCommandContext.cpp @@ -103,10 +103,6 @@ void CDeviceCommandContext::BlitFramebuffer(IFramebuffer*, IFramebuffer*) { } -void CDeviceCommandContext::ClearFramebuffer() -{ -} - void CDeviceCommandContext::ClearFramebuffer(const bool, const bool, const bool) { } diff --git a/source/renderer/backend/dummy/DeviceCommandContext.h b/source/renderer/backend/dummy/DeviceCommandContext.h index 859b6754f1..56b80bab21 100644 --- a/source/renderer/backend/dummy/DeviceCommandContext.h +++ b/source/renderer/backend/dummy/DeviceCommandContext.h @@ -50,7 +50,6 @@ public: void BlitFramebuffer(IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer) override; - void ClearFramebuffer() override; void ClearFramebuffer(const bool color, const bool depth, const bool stencil) override; void BeginFramebufferPass(IFramebuffer* framebuffer) override; void EndFramebufferPass() override; diff --git a/source/renderer/backend/gl/Device.cpp b/source/renderer/backend/gl/Device.cpp index f5192641fb..b1bed390b5 100644 --- a/source/renderer/backend/gl/Device.cpp +++ b/source/renderer/backend/gl/Device.cpp @@ -20,6 +20,7 @@ #include "Device.h" #include "lib/external_libraries/libsdl.h" +#include "lib/hash.h" #include "lib/ogl.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" @@ -358,7 +359,11 @@ std::unique_ptr CDevice::Create(SDL_Window* window, const bool arb) #endif } - device->m_Backbuffer = CFramebuffer::CreateBackbuffer(device.get()); +#if CONFIG2_GLES + device->m_UseFramebufferInvalidating = ogl_HaveExtension("GL_EXT_discard_framebuffer"); +#else + device->m_UseFramebufferInvalidating = !arb && ogl_HaveExtension("GL_ARB_invalidate_subdata"); +#endif Capabilities& capabilities = device->m_Capabilities; capabilities.ARBShaders = !ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", nullptr); @@ -880,18 +885,11 @@ std::unique_ptr CDevice::CreateTexture2D( } std::unique_ptr CDevice::CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment) -{ - return CreateFramebuffer(name, colorAttachment, depthStencilAttachment, CColor(0.0f, 0.0f, 0.0f, 0.0f)); -} - -std::unique_ptr CDevice::CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment, const CColor& clearColor) + const char* name, SColorAttachment* colorAttachment, + SDepthStencilAttachment* depthStencilAttachment) { return CFramebuffer::Create( - this, name, colorAttachment->As(), depthStencilAttachment->As(), clearColor); + this, name, colorAttachment, depthStencilAttachment); } std::unique_ptr CDevice::CreateBuffer( @@ -913,6 +911,35 @@ bool CDevice::AcquireNextBackbuffer() return true; } +size_t CDevice::BackbufferKeyHash::operator()(const BackbufferKey& key) const +{ + size_t seed = 0; + hash_combine(seed, std::get<0>(key)); + hash_combine(seed, std::get<1>(key)); + hash_combine(seed, std::get<2>(key)); + hash_combine(seed, std::get<3>(key)); + return seed; +} + +IFramebuffer* CDevice::GetCurrentBackbuffer( + const AttachmentLoadOp colorAttachmentLoadOp, + const AttachmentStoreOp colorAttachmentStoreOp, + const AttachmentLoadOp depthStencilAttachmentLoadOp, + const AttachmentStoreOp depthStencilAttachmentStoreOp) +{ + const BackbufferKey key{ + colorAttachmentLoadOp, colorAttachmentStoreOp, + depthStencilAttachmentLoadOp, depthStencilAttachmentStoreOp}; + auto it = m_Backbuffers.find(key); + if (it == m_Backbuffers.end()) + { + it = m_Backbuffers.emplace(key, CFramebuffer::CreateBackbuffer( + this, colorAttachmentLoadOp, colorAttachmentStoreOp, + depthStencilAttachmentLoadOp, depthStencilAttachmentStoreOp)).first; + } + return it->second.get(); +} + void CDevice::Present() { ENSURE(m_BackbufferAcquired); diff --git a/source/renderer/backend/gl/Device.h b/source/renderer/backend/gl/Device.h index 16664e3aa9..f186e67ec6 100644 --- a/source/renderer/backend/gl/Device.h +++ b/source/renderer/backend/gl/Device.h @@ -29,6 +29,8 @@ #include #include +#include +#include #include typedef struct SDL_Window SDL_Window; @@ -64,8 +66,6 @@ public: void Report(const ScriptRequest& rq, JS::HandleValue settings) override; - IFramebuffer* GetCurrentBackbuffer() override { return m_Backbuffer.get(); } - std::unique_ptr CreateCommandContext() override; CDeviceCommandContext* GetActiveCommandContext() { return m_ActiveCommandContext; } @@ -81,12 +81,8 @@ public: const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) override; std::unique_ptr CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment) override; - - std::unique_ptr CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment, const CColor& clearColor) override; + const char* name, SColorAttachment* colorAttachment, + SDepthStencilAttachment* depthStencilAttachment) override; std::unique_ptr CreateBuffer( const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) override; @@ -95,8 +91,17 @@ public: const CStr& name, const CShaderDefines& defines) override; bool AcquireNextBackbuffer() override; + + IFramebuffer* GetCurrentBackbuffer( + const AttachmentLoadOp colorAttachmentLoadOp, + const AttachmentStoreOp colorAttachmentStoreOp, + const AttachmentLoadOp depthStencilAttachmentLoadOp, + const AttachmentStoreOp depthStencilAttachmentStoreOp) override; + void Present() override; + bool UseFramebufferInvalidating() const { return m_UseFramebufferInvalidating; } + bool IsTextureFormatSupported(const Format format) const override; bool IsFramebufferFormatSupported(const Format format) const override; @@ -121,8 +126,20 @@ private: // it's used only as a helper for transition. CDeviceCommandContext* m_ActiveCommandContext = nullptr; - std::unique_ptr m_Backbuffer; + using BackbufferKey = std::tuple< + AttachmentLoadOp, AttachmentStoreOp, + AttachmentLoadOp, AttachmentStoreOp>; + struct BackbufferKeyHash + { + size_t operator()(const BackbufferKey& key) const; + }; + // We use std::unordered_map to avoid storing sizes of Attachment*Op + // enumerations. If it becomes a performance issue we'll replace it + // by an array. + std::unordered_map< + BackbufferKey, std::unique_ptr, BackbufferKeyHash> m_Backbuffers; bool m_BackbufferAcquired = false; + bool m_UseFramebufferInvalidating = false; Capabilities m_Capabilities{}; }; diff --git a/source/renderer/backend/gl/DeviceCommandContext.cpp b/source/renderer/backend/gl/DeviceCommandContext.cpp index 4b0cd40239..c93e9d8561 100644 --- a/source/renderer/backend/gl/DeviceCommandContext.cpp +++ b/source/renderer/backend/gl/DeviceCommandContext.cpp @@ -150,13 +150,76 @@ void UploadDynamicBufferRegionImpl( } } +/** + * In case we don't need a framebuffer content (because of the following clear + * or overwriting by a shader) we might give a hint to a driver via + * glInvalidateFramebuffer. + */ +void InvalidateFramebuffer( + CFramebuffer* framebuffer, const bool color, const bool depthStencil) +{ + GLsizei numberOfAttachments = 0; + GLenum attachments[8]; + const bool isBackbuffer = framebuffer->GetHandle() == 0; + if (color && (framebuffer->GetAttachmentMask() & GL_COLOR_BUFFER_BIT)) + { + if (isBackbuffer) +#if CONFIG2_GLES + attachments[numberOfAttachments++] = GL_COLOR_EXT; +#else + attachments[numberOfAttachments++] = GL_COLOR; +#endif + else + attachments[numberOfAttachments++] = GL_COLOR_ATTACHMENT0; + } + if (depthStencil) + { + if (isBackbuffer) + { + if (framebuffer->GetAttachmentMask() & GL_DEPTH_BUFFER_BIT) +#if CONFIG2_GLES + attachments[numberOfAttachments++] = GL_DEPTH_EXT; +#else + attachments[numberOfAttachments++] = GL_DEPTH; +#endif + if (framebuffer->GetAttachmentMask() & GL_STENCIL_BUFFER_BIT) +#if CONFIG2_GLES + attachments[numberOfAttachments++] = GL_STENCIL_EXT; +#else + attachments[numberOfAttachments++] = GL_STENCIL; +#endif + } + else + { + if (framebuffer->GetAttachmentMask() & GL_DEPTH_BUFFER_BIT) + attachments[numberOfAttachments++] = GL_DEPTH_ATTACHMENT; + if (framebuffer->GetAttachmentMask() & GL_STENCIL_BUFFER_BIT) + attachments[numberOfAttachments++] = GL_STENCIL_ATTACHMENT; + } + } + + if (numberOfAttachments > 0) + { +#if CONFIG2_GLES + glDiscardFramebufferEXT(GL_FRAMEBUFFER_EXT, numberOfAttachments, attachments); +#else + glInvalidateFramebuffer(GL_FRAMEBUFFER_EXT, numberOfAttachments, attachments); +#endif + ogl_WarnIfError(); + } +} + } // anonymous namespace // static std::unique_ptr CDeviceCommandContext::Create(CDevice* device) { std::unique_ptr deviceCommandContext(new CDeviceCommandContext(device)); - deviceCommandContext->m_Framebuffer = static_cast(device->GetCurrentBackbuffer()); + deviceCommandContext->m_Framebuffer = device->GetCurrentBackbuffer( + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::DONT_CARE, + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::DONT_CARE)->As(); deviceCommandContext->ResetStates(); return deviceCommandContext; } @@ -483,7 +546,11 @@ void CDeviceCommandContext::ResetStates() { SetGraphicsPipelineStateImpl(MakeDefaultGraphicsPipelineStateDesc(), true); SetScissors(0, nullptr); - m_Framebuffer = static_cast(m_Device->GetCurrentBackbuffer()); + m_Framebuffer = m_Device->GetCurrentBackbuffer( + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::DONT_CARE, + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::DONT_CARE)->As(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_Framebuffer->GetHandle()); ogl_WarnIfError(); } @@ -761,13 +828,9 @@ void CDeviceCommandContext::BlitFramebuffer( #endif } -void CDeviceCommandContext::ClearFramebuffer() -{ - ClearFramebuffer(true, true, true); -} - void CDeviceCommandContext::ClearFramebuffer(const bool color, const bool depth, const bool stencil) { + ENSURE(m_InsideFramebufferPass); const bool needsColor = color && (m_Framebuffer->GetAttachmentMask() & GL_COLOR_BUFFER_BIT) != 0; const bool needsDepth = depth && (m_Framebuffer->GetAttachmentMask() & GL_DEPTH_BUFFER_BIT) != 0; const bool needsStencil = stencil && (m_Framebuffer->GetAttachmentMask() & GL_STENCIL_BUFFER_BIT) != 0; @@ -811,15 +874,46 @@ void CDeviceCommandContext::BeginFramebufferPass(IFramebuffer* framebuffer) ENSURE(m_Framebuffer->GetHandle() == 0 || (m_Framebuffer->GetWidth() > 0 && m_Framebuffer->GetHeight() > 0)); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_Framebuffer->GetHandle()); ogl_WarnIfError(); + if (m_Device->UseFramebufferInvalidating()) + { + InvalidateFramebuffer( + m_Framebuffer, + m_Framebuffer->GetColorAttachmentLoadOp() != AttachmentLoadOp::LOAD, + m_Framebuffer->GetDepthStencilAttachmentLoadOp() != AttachmentLoadOp::LOAD); + } + const bool needsClearColor = + m_Framebuffer->GetColorAttachmentLoadOp() == AttachmentLoadOp::CLEAR; + const bool needsClearDepthStencil = + m_Framebuffer->GetDepthStencilAttachmentLoadOp() == AttachmentLoadOp::CLEAR; + if (needsClearColor || needsClearDepthStencil) + { + ClearFramebuffer( + needsClearColor, needsClearDepthStencil, needsClearDepthStencil); + } } void CDeviceCommandContext::EndFramebufferPass() { + if (m_Device->UseFramebufferInvalidating()) + { + InvalidateFramebuffer( + m_Framebuffer, + m_Framebuffer->GetColorAttachmentStoreOp() != AttachmentStoreOp::STORE, + m_Framebuffer->GetDepthStencilAttachmentStoreOp() != AttachmentStoreOp::STORE); + } ENSURE(m_InsideFramebufferPass); m_InsideFramebufferPass = false; - m_Framebuffer = static_cast(m_Device->GetCurrentBackbuffer()); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_Framebuffer->GetHandle()); - ogl_WarnIfError(); + CFramebuffer* framebuffer = m_Device->GetCurrentBackbuffer( + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::DONT_CARE, + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::DONT_CARE)->As(); + if (framebuffer->GetHandle() != m_Framebuffer->GetHandle()) + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->GetHandle()); + ogl_WarnIfError(); + } + m_Framebuffer = framebuffer; } void CDeviceCommandContext::ReadbackFramebufferSync( diff --git a/source/renderer/backend/gl/DeviceCommandContext.h b/source/renderer/backend/gl/DeviceCommandContext.h index 93ee260036..4a4ad80bc8 100644 --- a/source/renderer/backend/gl/DeviceCommandContext.h +++ b/source/renderer/backend/gl/DeviceCommandContext.h @@ -57,10 +57,9 @@ public: void BlitFramebuffer(IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer) override; - void ClearFramebuffer() override; - void ClearFramebuffer(const bool color, const bool depth, const bool stencil) override; void BeginFramebufferPass(IFramebuffer* framebuffer) override; void EndFramebufferPass() override; + void ClearFramebuffer(const bool color, const bool depth, const bool stencil) override; void ReadbackFramebufferSync( const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height, void* data) override; diff --git a/source/renderer/backend/gl/Framebuffer.cpp b/source/renderer/backend/gl/Framebuffer.cpp index 1f3babf8e0..c00a4304bd 100644 --- a/source/renderer/backend/gl/Framebuffer.cpp +++ b/source/renderer/backend/gl/Framebuffer.cpp @@ -36,15 +36,24 @@ namespace GL // static std::unique_ptr CFramebuffer::Create( - CDevice* device, const char* name, - CTexture* colorAttachment, CTexture* depthStencilAttachment, - const CColor& clearColor) + CDevice* device, const char* name, SColorAttachment* colorAttachment, + SDepthStencilAttachment* depthStencilAttachment) { ENSURE(colorAttachment || depthStencilAttachment); std::unique_ptr framebuffer(new CFramebuffer()); framebuffer->m_Device = device; - framebuffer->m_ClearColor = clearColor; + if (colorAttachment) + { + framebuffer->m_ClearColor = colorAttachment->clearColor; + framebuffer->m_ColorAttachmentLoadOp = colorAttachment->loadOp; + framebuffer->m_ColorAttachmentStoreOp = colorAttachment->storeOp; + } + if (depthStencilAttachment) + { + framebuffer->m_DepthStencilAttachmentLoadOp = depthStencilAttachment->loadOp; + framebuffer->m_DepthStencilAttachmentStoreOp = depthStencilAttachment->storeOp; + } glGenFramebuffersEXT(1, &framebuffer->m_Handle); if (!framebuffer->m_Handle) @@ -56,59 +65,62 @@ std::unique_ptr CFramebuffer::Create( if (colorAttachment) { - ENSURE(device->IsFramebufferFormatSupported(colorAttachment->GetFormat())); - ENSURE(colorAttachment->GetUsage() & Renderer::Backend::ITexture::Usage::COLOR_ATTACHMENT); + CTexture* colorAttachmentTexture = colorAttachment->texture->As(); + ENSURE(device->IsFramebufferFormatSupported(colorAttachmentTexture->GetFormat())); + ENSURE(colorAttachmentTexture->GetUsage() & Renderer::Backend::ITexture::Usage::COLOR_ATTACHMENT); framebuffer->m_AttachmentMask |= GL_COLOR_BUFFER_BIT; #if CONFIG2_GLES - ENSURE(colorAttachment->GetType() == CTexture::Type::TEXTURE_2D); + ENSURE(colorAttachmentTexture->GetType() == CTexture::Type::TEXTURE_2D); const GLenum textureTarget = GL_TEXTURE_2D; #else - const GLenum textureTarget = colorAttachment->GetType() == CTexture::Type::TEXTURE_2D_MULTISAMPLE ? + const GLenum textureTarget = colorAttachmentTexture->GetType() == CTexture::Type::TEXTURE_2D_MULTISAMPLE ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; #endif - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - textureTarget, colorAttachment->GetHandle(), 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, + textureTarget, colorAttachmentTexture->GetHandle(), 0); } + if (depthStencilAttachment) { - ENSURE(depthStencilAttachment->GetUsage() & Renderer::Backend::ITexture::Usage::DEPTH_STENCIL_ATTACHMENT); + CTexture* depthStencilAttachmentTexture = depthStencilAttachment->texture->As(); + ENSURE(depthStencilAttachmentTexture->GetUsage() & Renderer::Backend::ITexture::Usage::DEPTH_STENCIL_ATTACHMENT); - framebuffer->m_Width = depthStencilAttachment->GetWidth(); - framebuffer->m_Height = depthStencilAttachment->GetHeight(); + framebuffer->m_Width = depthStencilAttachmentTexture->GetWidth(); + framebuffer->m_Height = depthStencilAttachmentTexture->GetHeight(); framebuffer->m_AttachmentMask |= GL_DEPTH_BUFFER_BIT; - if (depthStencilAttachment->GetFormat() == Format::D24_S8) + if (depthStencilAttachmentTexture->GetFormat() == Format::D24_S8) framebuffer->m_AttachmentMask |= GL_STENCIL_BUFFER_BIT; if (colorAttachment) { - ENSURE(colorAttachment->GetWidth() == depthStencilAttachment->GetWidth()); - ENSURE(colorAttachment->GetHeight() == depthStencilAttachment->GetHeight()); - ENSURE(colorAttachment->GetType() == depthStencilAttachment->GetType()); + ENSURE(colorAttachment->texture->GetWidth() == depthStencilAttachmentTexture->GetWidth()); + ENSURE(colorAttachment->texture->GetHeight() == depthStencilAttachmentTexture->GetHeight()); + ENSURE(colorAttachment->texture->GetType() == depthStencilAttachmentTexture->GetType()); } ENSURE( - depthStencilAttachment->GetFormat() == Format::D16 || - depthStencilAttachment->GetFormat() == Format::D24 || - depthStencilAttachment->GetFormat() == Format::D32 || - depthStencilAttachment->GetFormat() == Format::D24_S8); + depthStencilAttachmentTexture->GetFormat() == Format::D16 || + depthStencilAttachmentTexture->GetFormat() == Format::D24 || + depthStencilAttachmentTexture->GetFormat() == Format::D32 || + depthStencilAttachmentTexture->GetFormat() == Format::D24_S8); #if CONFIG2_GLES - ENSURE(depthStencilAttachment->GetFormat() != Format::D24_S8); + ENSURE(depthStencilAttachmentTexture->GetFormat() != Format::D24_S8); const GLenum attachment = GL_DEPTH_ATTACHMENT; - ENSURE(depthStencilAttachment->GetType() == CTexture::Type::TEXTURE_2D); + ENSURE(depthStencilAttachmentTexture->GetType() == CTexture::Type::TEXTURE_2D); const GLenum textureTarget = GL_TEXTURE_2D; #else - const GLenum attachment = depthStencilAttachment->GetFormat() == Format::D24_S8 ? + const GLenum attachment = depthStencilAttachmentTexture->GetFormat() == Format::D24_S8 ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT; - const GLenum textureTarget = depthStencilAttachment->GetType() == CTexture::Type::TEXTURE_2D_MULTISAMPLE ? + const GLenum textureTarget = depthStencilAttachmentTexture->GetType() == CTexture::Type::TEXTURE_2D_MULTISAMPLE ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; #endif glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, - textureTarget, depthStencilAttachment->GetHandle(), 0); + textureTarget, depthStencilAttachmentTexture->GetHandle(), 0); } else { - framebuffer->m_Width = colorAttachment->GetWidth(); - framebuffer->m_Height = colorAttachment->GetHeight(); + framebuffer->m_Width = colorAttachment->texture->GetWidth(); + framebuffer->m_Height = colorAttachment->texture->GetHeight(); } ogl_WarnIfError(); @@ -120,7 +132,7 @@ std::unique_ptr CFramebuffer::Create( glDrawBuffer(GL_NONE); } else - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glDrawBuffer(GL_COLOR_ATTACHMENT0); #endif ogl_WarnIfError(); @@ -151,13 +163,21 @@ std::unique_ptr CFramebuffer::Create( // static std::unique_ptr CFramebuffer::CreateBackbuffer( - CDevice* device) + CDevice* device, + const AttachmentLoadOp colorAttachmentLoadOp, + const AttachmentStoreOp colorAttachmentStoreOp, + const AttachmentLoadOp depthStencilAttachmentLoadOp, + const AttachmentStoreOp depthStencilAttachmentStoreOp) { // Backbuffer for GL is a special case with a zero framebuffer. std::unique_ptr framebuffer(new CFramebuffer()); framebuffer->m_Device = device; framebuffer->m_AttachmentMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; framebuffer->m_ClearColor = CColor(0.0f, 0.0f, 0.0f, 0.0f); + framebuffer->m_ColorAttachmentLoadOp = colorAttachmentLoadOp; + framebuffer->m_ColorAttachmentStoreOp = colorAttachmentStoreOp; + framebuffer->m_DepthStencilAttachmentLoadOp = depthStencilAttachmentLoadOp; + framebuffer->m_DepthStencilAttachmentStoreOp = depthStencilAttachmentStoreOp; return framebuffer; } diff --git a/source/renderer/backend/gl/Framebuffer.h b/source/renderer/backend/gl/Framebuffer.h index 7c69789654..515590e249 100644 --- a/source/renderer/backend/gl/Framebuffer.h +++ b/source/renderer/backend/gl/Framebuffer.h @@ -49,6 +49,11 @@ public: GLuint GetHandle() const { return m_Handle; } GLbitfield GetAttachmentMask() const { return m_AttachmentMask; } + AttachmentLoadOp GetColorAttachmentLoadOp() const { return m_ColorAttachmentLoadOp; } + AttachmentStoreOp GetColorAttachmentStoreOp() const { return m_ColorAttachmentStoreOp; } + AttachmentLoadOp GetDepthStencilAttachmentLoadOp() const { return m_DepthStencilAttachmentLoadOp; } + AttachmentStoreOp GetDepthStencilAttachmentStoreOp() const { return m_DepthStencilAttachmentStoreOp; } + uint32_t GetWidth() const { return m_Width; } uint32_t GetHeight() const { return m_Height; } @@ -56,17 +61,29 @@ private: friend class CDevice; static std::unique_ptr Create( - CDevice* device, const char* name, - CTexture* colorAttachment, CTexture* depthStencilAttachment, const CColor& clearColor); - static std::unique_ptr CreateBackbuffer(CDevice* device); + CDevice* device, const char* name, SColorAttachment* colorAttachment, + SDepthStencilAttachment* depthStencilAttachment); + static std::unique_ptr CreateBackbuffer( + CDevice* device, + const AttachmentLoadOp colorAttachmentLoadOp, + const AttachmentStoreOp colorAttachmentStoreOp, + const AttachmentLoadOp depthStencilAttachmentLoadOp, + const AttachmentStoreOp depthStencilAttachmentStoreOp); CFramebuffer(); CDevice* m_Device = nullptr; + GLuint m_Handle = 0; uint32_t m_Width = 0, m_Height = 0; GLbitfield m_AttachmentMask = 0; + CColor m_ClearColor; + + AttachmentLoadOp m_ColorAttachmentLoadOp = AttachmentLoadOp::DONT_CARE; + AttachmentStoreOp m_ColorAttachmentStoreOp = AttachmentStoreOp::DONT_CARE; + AttachmentLoadOp m_DepthStencilAttachmentLoadOp = AttachmentLoadOp::DONT_CARE; + AttachmentStoreOp m_DepthStencilAttachmentStoreOp = AttachmentStoreOp::DONT_CARE; }; } // namespace GL diff --git a/source/renderer/backend/vulkan/Device.cpp b/source/renderer/backend/vulkan/Device.cpp index 5a699734a2..1818cda14a 100644 --- a/source/renderer/backend/vulkan/Device.cpp +++ b/source/renderer/backend/vulkan/Device.cpp @@ -74,11 +74,6 @@ void CDevice::Report(const ScriptRequest& rq, JS::HandleValue settings) Script::SetProperty(rq, settings, "status", vulkanSupport); } -IFramebuffer* CDevice::GetCurrentBackbuffer() -{ - return nullptr; -} - std::unique_ptr CDevice::CreateCommandContext() { return nullptr; @@ -112,8 +107,8 @@ std::unique_ptr CDevice::CreateTexture2D( } std::unique_ptr CDevice::CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment) + const char* name, SColorAttachment* colorAttachment, + SDepthStencilAttachment* depthStencilAttachment) { UNUSED2(name); UNUSED2(colorAttachment); @@ -121,17 +116,6 @@ std::unique_ptr CDevice::CreateFramebuffer( return nullptr; } -std::unique_ptr CDevice::CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment, const CColor& clearColor) -{ - UNUSED2(name); - UNUSED2(colorAttachment); - UNUSED2(depthStencilAttachment); - UNUSED2(clearColor); - return nullptr; -} - std::unique_ptr CDevice::CreateBuffer( const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) { @@ -155,6 +139,19 @@ bool CDevice::AcquireNextBackbuffer() return false; } +IFramebuffer* CDevice::GetCurrentBackbuffer( + const AttachmentLoadOp colorAttachmentLoadOp, + const AttachmentStoreOp colorAttachmentStoreOp, + const AttachmentLoadOp depthStencilAttachmentLoadOp, + const AttachmentStoreOp depthStencilAttachmentStoreOp) +{ + UNUSED2(colorAttachmentLoadOp); + UNUSED2(colorAttachmentStoreOp); + UNUSED2(depthStencilAttachmentLoadOp); + UNUSED2(depthStencilAttachmentStoreOp); + return nullptr; +} + void CDevice::Present() { } diff --git a/source/renderer/backend/vulkan/Device.h b/source/renderer/backend/vulkan/Device.h index c20a721221..be3193a143 100644 --- a/source/renderer/backend/vulkan/Device.h +++ b/source/renderer/backend/vulkan/Device.h @@ -54,8 +54,6 @@ public: void Report(const ScriptRequest& rq, JS::HandleValue settings) override; - IFramebuffer* GetCurrentBackbuffer() override; - std::unique_ptr CreateCommandContext() override; std::unique_ptr CreateTexture( @@ -69,12 +67,8 @@ public: const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) override; std::unique_ptr CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment) override; - - std::unique_ptr CreateFramebuffer( - const char* name, ITexture* colorAttachment, - ITexture* depthStencilAttachment, const CColor& clearColor) override; + const char* name, SColorAttachment* colorAttachment, + SDepthStencilAttachment* depthStencilAttachment) override; std::unique_ptr CreateBuffer( const char* name, const IBuffer::Type type, const uint32_t size, const bool dynamic) override; @@ -83,6 +77,13 @@ public: const CStr& name, const CShaderDefines& defines) override; bool AcquireNextBackbuffer() override; + + IFramebuffer* GetCurrentBackbuffer( + const AttachmentLoadOp colorAttachmentLoadOp, + const AttachmentStoreOp colorAttachmentStoreOp, + const AttachmentLoadOp depthStencilAttachmentLoadOp, + const AttachmentStoreOp depthStencilAttachmentStoreOp) override; + void Present() override; bool IsTextureFormatSupported(const Format format) const override; diff --git a/source/tools/atlas/GameInterface/ActorViewer.cpp b/source/tools/atlas/GameInterface/ActorViewer.cpp index 021bb431df..db11c022b0 100644 --- a/source/tools/atlas/GameInterface/ActorViewer.cpp +++ b/source/tools/atlas/GameInterface/ActorViewer.cpp @@ -540,7 +540,11 @@ void ActorViewer::Render() sceneRenderer.PrepareScene(deviceCommandContext, m); deviceCommandContext->BeginFramebufferPass( - deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); + deviceCommandContext->GetDevice()->GetCurrentBackbuffer( + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::STORE, + Renderer::Backend::AttachmentLoadOp::DONT_CARE, + Renderer::Backend::AttachmentStoreOp::DONT_CARE)); sceneRenderer.RenderScene(deviceCommandContext); sceneRenderer.RenderSceneOverlays(deviceCommandContext);