diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-08-15 22:42:13 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-08-15 22:42:13 +0000 |
| commit | df3a2c7c744eae194c79187a59914c6662f69b52 (patch) | |
| tree | 6f67919092b671b4a0fb637db26f75293f849886 /Graphics/GraphicsEngineOpenGL | |
| parent | Fixed Visual Studio 16.7 build error (diff) | |
| parent | Vk backend: not setting render pass in SetPipelineState (diff) | |
| download | DiligentCore-df3a2c7c744eae194c79187a59914c6662f69b52.tar.gz DiligentCore-df3a2c7c744eae194c79187a59914c6662f69b52.zip | |
Added render passes to the API (fixed https://github.com/DiligentGraphics/DiligentCore/issues/9)
Diffstat (limited to 'Graphics/GraphicsEngineOpenGL')
12 files changed, 680 insertions, 129 deletions
diff --git a/Graphics/GraphicsEngineOpenGL/CMakeLists.txt b/Graphics/GraphicsEngineOpenGL/CMakeLists.txt index 1072d067..76c51a8c 100644 --- a/Graphics/GraphicsEngineOpenGL/CMakeLists.txt +++ b/Graphics/GraphicsEngineOpenGL/CMakeLists.txt @@ -9,6 +9,7 @@ set(INCLUDE include/DeviceContextGLImpl.hpp include/FBOCache.hpp include/FenceGLImpl.hpp + include/FramebufferGLImpl.hpp include/GLContext.hpp include/GLContextState.hpp include/GLObjectWrapper.hpp @@ -20,6 +21,7 @@ set(INCLUDE include/PipelineStateGLImpl.hpp include/QueryGLImpl.hpp include/RenderDeviceGLImpl.hpp + include/RenderPassGLImpl.hpp include/SamplerGLImpl.hpp include/ShaderGLImpl.hpp include/ShaderResourceBindingGLImpl.hpp @@ -62,6 +64,7 @@ set(SOURCE src/EngineFactoryOpenGL.cpp src/FBOCache.cpp src/FenceGLImpl.cpp + src/FramebufferGLImpl.cpp src/GLContextState.cpp src/GLObjectWrapper.cpp src/GLProgramResourceCache.cpp @@ -71,6 +74,7 @@ set(SOURCE src/PipelineStateGLImpl.cpp src/QueryGLImpl.cpp src/RenderDeviceGLImpl.cpp + src/RenderPassGLImpl.cpp src/SamplerGLImpl.cpp src/ShaderGLImpl.cpp src/ShaderResourceBindingGLImpl.cpp diff --git a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp index e80e0d04..aac30d49 100644 --- a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp @@ -27,6 +27,8 @@ #pragma once +#include <vector> + #include "DeviceContextGL.h" #include "DeviceContextBase.hpp" #include "BaseInterfacesGL.h" @@ -35,6 +37,8 @@ #include "BufferGLImpl.hpp" #include "TextureBaseGL.hpp" #include "QueryGLImpl.hpp" +#include "FramebufferGLImpl.hpp" +#include "RenderPassGLImpl.hpp" #include "PipelineStateGLImpl.hpp" namespace Diligent @@ -47,6 +51,8 @@ struct DeviceContextGLImplTraits using PipelineStateType = PipelineStateGLImpl; using DeviceType = RenderDeviceGLImpl; using QueryType = QueryGLImpl; + using FramebufferType = FramebufferGLImpl; + using RenderPassType = RenderPassGLImpl; }; /// Device context implementation in OpenGL backend. @@ -110,6 +116,15 @@ public: ITextureView* pDepthStencil, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) override final; + /// Implementation of IDeviceContext::BeginRenderPass() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE BeginRenderPass(const BeginRenderPassAttribs& Attribs) override final; + + /// Implementation of IDeviceContext::NextSubpass() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE NextSubpass() override final; + + /// Implementation of IDeviceContext::EndRenderPass() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE EndRenderPass() override final; + // clang-format off /// Implementation of IDeviceContext::Draw() in OpenGL backend. @@ -251,6 +266,9 @@ private: __forceinline void PrepareForIndirectDraw(IBuffer* pAttribsBuffer); __forceinline void PostDraw(); + void BeginSubpass(); + void EndSubpass(); + Uint32 m_CommitedResourcesTentativeBarriers = 0; std::vector<class TextureBaseGL*> m_BoundWritableTextures; @@ -261,6 +279,8 @@ private: bool m_IsDefaultFBOBound = false; GLObjectWrappers::GLFrameBufferObj m_DefaultFBO; + + std::vector<OptimizedClearValue> m_AttachmentClearValues; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/FBOCache.hpp b/Graphics/GraphicsEngineOpenGL/include/FBOCache.hpp index 98e097d2..928da3f8 100644 --- a/Graphics/GraphicsEngineOpenGL/include/FBOCache.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/FBOCache.hpp @@ -51,6 +51,11 @@ public: FBOCache& operator = ( FBOCache&&) = delete; // clang-format on + static GLObjectWrappers::GLFrameBufferObj CreateFBO(class GLContextState& ContextState, + Uint32 NumRenderTargets, + TextureViewGLImpl* ppRTVs[], + TextureViewGLImpl* pDSV); + const GLObjectWrappers::GLFrameBufferObj& GetFBO(Uint32 NumRenderTargets, TextureViewGLImpl* ppRTVs[], TextureViewGLImpl* pDSV, @@ -91,7 +96,7 @@ private: // Multimap that sets up correspondence between unique texture id and all // FBOs it is used in - std::unordered_multimap<Diligent::UniqueIdentifier, FBOCacheKey> m_TexIdToKey; + std::unordered_multimap<UniqueIdentifier, FBOCacheKey> m_TexIdToKey; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/FramebufferGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/FramebufferGLImpl.hpp new file mode 100644 index 00000000..49ea8b84 --- /dev/null +++ b/Graphics/GraphicsEngineOpenGL/include/FramebufferGLImpl.hpp @@ -0,0 +1,78 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of Diligent::FramebufferGLImpl class + +#include <vector> + +#include "RenderDeviceGL.h" +#include "FramebufferBase.hpp" +#include "RenderDeviceGLImpl.hpp" +#include "GLObjectWrapper.hpp" + +namespace Diligent +{ + +class FixedBlockMemoryAllocator; + +/// Render pass implementation in Direct3D11 backend. +class FramebufferGLImpl final : public FramebufferBase<IFramebuffer, RenderDeviceGLImpl> +{ +public: + using TFramebufferBase = FramebufferBase<IFramebuffer, RenderDeviceGLImpl>; + + FramebufferGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDevice, + GLContextState& CtxState, + const FramebufferDesc& Desc); + ~FramebufferGLImpl(); + + struct SubpassFramebuffers + { + SubpassFramebuffers(GLObjectWrappers::GLFrameBufferObj&& _RenderTarget, + GLObjectWrappers::GLFrameBufferObj&& _Resolve) : + RenderTarget{std::move(_RenderTarget)}, + Resolve{std::move(_Resolve)} + {} + + GLObjectWrappers::GLFrameBufferObj RenderTarget; + GLObjectWrappers::GLFrameBufferObj Resolve; + }; + + const SubpassFramebuffers& GetSubpassFramebuffer(Uint32 subpass) + { + return m_SubpassFramebuffers[subpass]; + } + +private: + std::vector<SubpassFramebuffers> m_SubpassFramebuffers; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp index 310faaf6..dbdb51c8 100644 --- a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp @@ -113,6 +113,14 @@ public: /// Implementation of IRenderDevice::CreateQuery() in OpenGL backend. virtual void DILIGENT_CALL_TYPE CreateQuery(const QueryDesc& Desc, IQuery** ppQuery) override final; + /// Implementation of IRenderDevice::CreateRenderPass() in OpenGL backend. + virtual void DILIGENT_CALL_TYPE CreateRenderPass(const RenderPassDesc& Desc, + IRenderPass** ppRenderPass) override final; + + /// Implementation of IRenderDevice::CreateFramebuffer() in OpenGL backend. + virtual void DILIGENT_CALL_TYPE CreateFramebuffer(const FramebufferDesc& Desc, + IFramebuffer** ppFramebuffer) override final; + /// Implementation of IRenderDeviceGL::CreateTextureFromGLHandle(). virtual void DILIGENT_CALL_TYPE CreateTextureFromGLHandle(Uint32 GLHandle, Uint32 GLBindTarget, diff --git a/Graphics/GraphicsEngineOpenGL/include/RenderPassGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/RenderPassGLImpl.hpp new file mode 100644 index 00000000..e5d77333 --- /dev/null +++ b/Graphics/GraphicsEngineOpenGL/include/RenderPassGLImpl.hpp @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of Diligent::RenderPassGLImpl class + +#include "RenderDeviceGL.h" +#include "RenderPassBase.hpp" +#include "RenderDeviceGLImpl.hpp" + +namespace Diligent +{ + +class FixedBlockMemoryAllocator; + +/// Render pass implementation in Direct3D11 backend. +class RenderPassGLImpl final : public RenderPassBase<IRenderPass, RenderDeviceGLImpl> +{ +public: + using TRenderPassBase = RenderPassBase<IRenderPass, RenderDeviceGLImpl>; + + RenderPassGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDevice, + const RenderPassDesc& Desc); + ~RenderPassGLImpl(); +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index f6308229..8b10e196 100644 --- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp @@ -147,6 +147,11 @@ void DeviceContextGLImpl::SetPipelineState(IPipelineState* pPipelineState) void DeviceContextGLImpl::TransitionShaderResources(IPipelineState* pPipelineState, IShaderResourceBinding* pShaderResourceBinding) { + if (m_pActiveRenderPass) + { + LOG_ERROR_MESSAGE("State transitions are not allowed inside a render pass."); + return; + } } void DeviceContextGLImpl::CommitShaderResources(IShaderResourceBinding* pShaderResourceBinding, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) @@ -250,10 +255,10 @@ void DeviceContextGLImpl::SetViewports(Uint32 NumViewports, const Viewport* pVie // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glViewportIndexed.xhtml glViewportIndexedf(0, BottomLeftX, BottomLeftY, vp.Width, vp.Height); } - CHECK_GL_ERROR("Failed to set viewport"); + DEV_CHECK_GL_ERROR("Failed to set viewport"); glDepthRangef(vp.MinDepth, vp.MaxDepth); - CHECK_GL_ERROR("Failed to set depth range"); + DEV_CHECK_GL_ERROR("Failed to set depth range"); } else { @@ -263,9 +268,9 @@ void DeviceContextGLImpl::SetViewports(Uint32 NumViewports, const Viewport* pVie float BottomLeftY = static_cast<float>(RTHeight) - (vp.TopLeftY + vp.Height); float BottomLeftX = vp.TopLeftX; glViewportIndexedf(i, BottomLeftX, BottomLeftY, vp.Width, vp.Height); - CHECK_GL_ERROR("Failed to set viewport #", i); + DEV_CHECK_GL_ERROR("Failed to set viewport #", i); glDepthRangef(vp.MinDepth, vp.MaxDepth); - CHECK_GL_ERROR("Failed to set depth range for viewport #", i); + DEV_CHECK_GL_ERROR("Failed to set depth range for viewport #", i); } } } @@ -296,7 +301,7 @@ void DeviceContextGLImpl::SetScissorRects(Uint32 NumRects, const Rect* pRects, U auto width = Rect.right - Rect.left; auto height = Rect.bottom - Rect.top; glScissor(Rect.left, glBottom, width, height); - CHECK_GL_ERROR("Failed to set scissor rect"); + DEV_CHECK_GL_ERROR("Failed to set scissor rect"); } else { @@ -307,7 +312,7 @@ void DeviceContextGLImpl::SetScissorRects(Uint32 NumRects, const Rect* pRects, U auto width = Rect.right - Rect.left; auto height = Rect.bottom - Rect.top; glScissorIndexed(sr, Rect.left, glBottom, width, height); - CHECK_GL_ERROR("Failed to set scissor rect #", sr); + DEV_CHECK_GL_ERROR("Failed to set scissor rect #", sr); } } } @@ -319,6 +324,8 @@ void DeviceContextGLImpl::SetSwapChain(ISwapChainGL* pSwapChain) void DeviceContextGLImpl::CommitRenderTargets() { + VERIFY(m_pActiveRenderPass == nullptr, "This method must not be called inside render pass"); + if (!m_IsDefaultFBOBound && m_NumBoundRenderTargets == 0 && !m_pBoundDepthStencil) return; @@ -327,7 +334,7 @@ void DeviceContextGLImpl::CommitRenderTargets() GLuint DefaultFBOHandle = m_pSwapChain->GetDefaultFBO(); if (m_DefaultFBO != DefaultFBOHandle) { - m_DefaultFBO = GLObjectWrappers::GLFrameBufferObj(true, GLObjectWrappers::GLFBOCreateReleaseHelper(DefaultFBOHandle)); + m_DefaultFBO = GLObjectWrappers::GLFrameBufferObj{true, GLObjectWrappers::GLFBOCreateReleaseHelper(DefaultFBOHandle)}; } m_ContextState.BindFBO(m_DefaultFBO); } @@ -373,6 +380,14 @@ void DeviceContextGLImpl::SetRenderTargets(Uint32 NumRen ITextureView* pDepthStencil, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) { +#ifdef DILIGENT_DEVELOPMENT + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("Calling SetRenderTargets inside active render pass is invalid. End the render pass first"); + return; + } +#endif + if (TDeviceContextBase::SetRenderTargets(NumRenderTargets, ppRenderTargets, pDepthStencil)) { if (m_NumBoundRenderTargets == 1 && m_pBoundRenderTargets[0] && m_pBoundRenderTargets[0]->GetTexture<TextureBaseGL>()->GetGLHandle() == 0) @@ -403,6 +418,140 @@ void DeviceContextGLImpl::ResetRenderTargets() m_ContextState.InvalidateFBO(); } +void DeviceContextGLImpl::BeginSubpass() +{ + VERIFY_EXPR(m_pActiveRenderPass); + VERIFY_EXPR(m_pBoundFramebuffer); + const auto& RPDesc = m_pActiveRenderPass->GetDesc(); + VERIFY_EXPR(m_SubpassIndex < RPDesc.SubpassCount); + const auto& SubpassDesc = RPDesc.pSubpasses[m_SubpassIndex]; + const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); + + const auto& RenderTargetFBO = m_pBoundFramebuffer->GetSubpassFramebuffer(m_SubpassIndex).RenderTarget; + if (RenderTargetFBO != 0) + { + m_ContextState.BindFBO(RenderTargetFBO); + } + else + { + GLuint DefaultFBOHandle = m_pSwapChain->GetDefaultFBO(); + if (m_DefaultFBO != DefaultFBOHandle) + { + m_DefaultFBO = GLObjectWrappers::GLFrameBufferObj{true, GLObjectWrappers::GLFBOCreateReleaseHelper(DefaultFBOHandle)}; + } + m_ContextState.BindFBO(m_DefaultFBO); + } + + for (Uint32 rt = 0; rt < SubpassDesc.RenderTargetAttachmentCount; ++rt) + { + const auto& RTAttachmentRef = SubpassDesc.pRenderTargetAttachments[rt]; + if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + auto* const pRTV = ValidatedCast<TextureViewGLImpl>(FBDesc.ppAttachments[RTAttachmentRef.AttachmentIndex]); + if (pRTV == nullptr) + continue; + + auto* const pColorTexGL = pRTV->GetTexture<TextureBaseGL>(); + pColorTexGL->TextureMemoryBarrier( + GL_FRAMEBUFFER_BARRIER_BIT, // Reads and writes via framebuffer object attachments after the + // barrier will reflect data written by shaders prior to the barrier. + // Additionally, framebuffer writes issued after the barrier will wait + // on the completion of all shader writes issued prior to the barrier. + m_ContextState); + + const auto& AttachmentDesc = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex]; + auto FirstLastUse = m_pActiveRenderPass->GetAttachmentFirstLastUse(RTAttachmentRef.AttachmentIndex); + if (FirstLastUse.first == m_SubpassIndex && AttachmentDesc.LoadOp == ATTACHMENT_LOAD_OP_CLEAR) + { + ClearRenderTarget(pRTV, m_AttachmentClearValues[RTAttachmentRef.AttachmentIndex].Color, RESOURCE_STATE_TRANSITION_MODE_NONE); + } + } + } + + if (SubpassDesc.pDepthStencilAttachment != nullptr) + { + const auto DepthAttachmentIndex = SubpassDesc.pDepthStencilAttachment->AttachmentIndex; + if (DepthAttachmentIndex != ATTACHMENT_UNUSED) + { + auto* const pDSV = ValidatedCast<TextureViewGLImpl>(FBDesc.ppAttachments[DepthAttachmentIndex]); + if (pDSV != nullptr) + { + auto* pDepthTexGL = pDSV->GetTexture<TextureBaseGL>(); + pDepthTexGL->TextureMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT, m_ContextState); + + const auto& AttachmentDesc = RPDesc.pAttachments[DepthAttachmentIndex]; + auto FirstLastUse = m_pActiveRenderPass->GetAttachmentFirstLastUse(DepthAttachmentIndex); + if (FirstLastUse.first == m_SubpassIndex && AttachmentDesc.LoadOp == ATTACHMENT_LOAD_OP_CLEAR) + { + const auto& ClearVal = m_AttachmentClearValues[DepthAttachmentIndex].DepthStencil; + ClearDepthStencil(pDSV, CLEAR_DEPTH_FLAG | CLEAR_STENCIL_FLAG, ClearVal.Depth, ClearVal.Stencil, RESOURCE_STATE_TRANSITION_MODE_NONE); + } + } + } + } +} + +void DeviceContextGLImpl::EndSubpass() +{ + VERIFY_EXPR(m_pActiveRenderPass); + VERIFY_EXPR(m_pBoundFramebuffer); + const auto& RPDesc = m_pActiveRenderPass->GetDesc(); + VERIFY_EXPR(m_SubpassIndex < RPDesc.SubpassCount); + const auto& SubpassDesc = RPDesc.pSubpasses[m_SubpassIndex]; + if (SubpassDesc.pResolveAttachments != nullptr) + { + const auto& SubpassFBOs = m_pBoundFramebuffer->GetSubpassFramebuffer(m_SubpassIndex); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, SubpassFBOs.RenderTarget); + DEV_CHECK_GL_ERROR("Failed to bind subpass render target FBO as read framebuffer"); + + GLuint ResolveDstFBO = SubpassFBOs.Resolve; + if (ResolveDstFBO == 0) + { + ResolveDstFBO = m_pSwapChain.RawPtr<ISwapChainGL>()->GetDefaultFBO(); + } + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ResolveDstFBO); + DEV_CHECK_GL_ERROR("Failed to bind resolve destination FBO as draw framebuffer"); + + const auto& FBODesc = m_pBoundFramebuffer->GetDesc(); + glBlitFramebuffer(0, 0, static_cast<GLint>(FBODesc.Width), static_cast<GLint>(FBODesc.Height), + 0, 0, static_cast<GLint>(FBODesc.Width), static_cast<GLint>(FBODesc.Height), + GL_COLOR_BUFFER_BIT, + GL_NEAREST // Filter is ignored + ); + DEV_CHECK_GL_ERROR("glBlitFramebuffer() failed when resolving multi-sampled attachments"); + } + m_ContextState.InvalidateFBO(); +} + +void DeviceContextGLImpl::BeginRenderPass(const BeginRenderPassAttribs& Attribs) +{ + TDeviceContextBase::BeginRenderPass(Attribs); + + m_AttachmentClearValues.resize(Attribs.ClearValueCount); + for (Uint32 i = 0; i < Attribs.ClearValueCount; ++i) + m_AttachmentClearValues[i] = Attribs.pClearValues[i]; + + VERIFY_EXPR(m_pBoundFramebuffer); + + SetViewports(1, nullptr, 0, 0); + + BeginSubpass(); +} + +void DeviceContextGLImpl::NextSubpass() +{ + EndSubpass(); + TDeviceContextBase::NextSubpass(); + BeginSubpass(); +} + +void DeviceContextGLImpl::EndRenderPass() +{ + EndSubpass(); + TDeviceContextBase::EndRenderPass(); + m_ContextState.InvalidateFBO(); +} void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShaderResourceBinding* pResBinding) { @@ -524,7 +673,7 @@ void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShade m_ContextState.BindTexture(-1, pTexViewGL->GetBindTarget(), pTexViewGL->GetHandle()); GLint IsImmutable = 0; glGetTexParameteriv(pTexViewGL->GetBindTarget(), GL_TEXTURE_IMMUTABLE_FORMAT, &IsImmutable); - CHECK_GL_ERROR("glGetTexParameteriv() failed"); + DEV_CHECK_GL_ERROR("glGetTexParameteriv() failed"); VERIFY(IsImmutable, "Only immutable textures can be bound to pipeline using glBindImageTexture()"); m_ContextState.BindTexture(-1, pTexViewGL->GetBindTarget(), GLObjectWrappers::GLTextureObj::Null()); } @@ -883,7 +1032,7 @@ void DeviceContextGLImpl::DispatchCompute(const DispatchComputeAttribs& Attribs) #if GL_ARB_compute_shader m_pPipelineState->CommitProgram(m_ContextState); glDispatchCompute(Attribs.ThreadGroupCountX, Attribs.ThreadGroupCountY, Attribs.ThreadGroupCountZ); - CHECK_GL_ERROR("glDispatchCompute() failed"); + DEV_CHECK_GL_ERROR("glDispatchCompute() failed"); PostDraw(); #else @@ -910,10 +1059,10 @@ void DeviceContextGLImpl::DispatchComputeIndirect(const DispatchComputeIndirectA constexpr bool ResetVAO = false; // GL_DISPATCH_INDIRECT_BUFFER does not affect VAO m_ContextState.BindBuffer(GL_DISPATCH_INDIRECT_BUFFER, pBufferGL->m_GlBuffer, ResetVAO); - CHECK_GL_ERROR("Failed to bind a buffer for dispatch indirect command"); + DEV_CHECK_GL_ERROR("Failed to bind a buffer for dispatch indirect command"); glDispatchComputeIndirect(Attribs.DispatchArgsByteOffset); - CHECK_GL_ERROR("glDispatchComputeIndirect() failed"); + DEV_CHECK_GL_ERROR("glDispatchComputeIndirect() failed"); m_ContextState.BindBuffer(GL_DISPATCH_INDIRECT_BUFFER, GLObjectWrappers::GLBufferObj::Null(), ResetVAO); @@ -959,7 +1108,7 @@ void DeviceContextGLImpl::ClearDepthStencil(ITextureView* pView // blend function, logical operation, stenciling, texture mapping, and depth-buffering // are ignored by glClear. glClear(glClearFlags); - CHECK_GL_ERROR("glClear() failed"); + DEV_CHECK_GL_ERROR("glClear() failed"); m_ContextState.EnableDepthWrites(DepthWritesEnabled); m_ContextState.EnableScissorTest(ScissorTestEnabled); } @@ -972,8 +1121,6 @@ void DeviceContextGLImpl::ClearRenderTarget(ITextureView* pView, const float* RG VERIFY_EXPR(pView != nullptr); Int32 RTIndex = -1; - VERIFY(pView->GetDesc().ViewType == TEXTURE_VIEW_RENDER_TARGET, "Incorrect view type: render target is expected"); - CHECK_DYNAMIC_TYPE(TextureViewGLImpl, pView); for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) { if (m_pBoundRenderTargets[rt] == pView) @@ -1012,7 +1159,7 @@ void DeviceContextGLImpl::ClearRenderTarget(ITextureView* pView, const float* RG m_ContextState.SetColorWriteMask(RTIndex, COLOR_MASK_ALL, bIndependentBlend); glClearBufferfv(GL_COLOR, RTIndex, RGBA); - CHECK_GL_ERROR("glClearBufferfv() failed"); + DEV_CHECK_GL_ERROR("glClearBufferfv() failed"); m_ContextState.SetColorWriteMask(RTIndex, WriteMask, bIndependentBlend); m_ContextState.EnableScissorTest(ScissorTestEnabled); @@ -1020,6 +1167,11 @@ void DeviceContextGLImpl::ClearRenderTarget(ITextureView* pView, const float* RG void DeviceContextGLImpl::Flush() { + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("Flushing device context inside an active render pass."); + } + glFlush(); } @@ -1044,7 +1196,7 @@ void DeviceContextGLImpl::SignalFence(IFence* pFence, Uint64 Value) GL_SYNC_GPU_COMMANDS_COMPLETE, // Condition must always be GL_SYNC_GPU_COMMANDS_COMPLETE 0 // Flags, must be 0 )}; - CHECK_GL_ERROR("Failed to create gl fence"); + DEV_CHECK_GL_ERROR("Failed to create gl fence"); auto* pFenceGLImpl = ValidatedCast<FenceGLImpl>(pFence); pFenceGLImpl->AddPendingFence(std::move(GLFence), Value); } @@ -1077,7 +1229,7 @@ void DeviceContextGLImpl::BeginQuery(IQuery* pQuery) case QUERY_TYPE_OCCLUSION: #if GL_SAMPLES_PASSED glBeginQuery(GL_SAMPLES_PASSED, glQuery); - CHECK_GL_ERROR("Failed to begin GL_SAMPLES_PASSED query"); + DEV_CHECK_GL_ERROR("Failed to begin GL_SAMPLES_PASSED query"); #else LOG_ERROR_MESSAGE_ONCE("GL_SAMPLES_PASSED query is not supported by this device"); #endif @@ -1085,13 +1237,13 @@ void DeviceContextGLImpl::BeginQuery(IQuery* pQuery) case QUERY_TYPE_BINARY_OCCLUSION: glBeginQuery(GL_ANY_SAMPLES_PASSED, glQuery); - CHECK_GL_ERROR("Failed to begin GL_ANY_SAMPLES_PASSED query"); + DEV_CHECK_GL_ERROR("Failed to begin GL_ANY_SAMPLES_PASSED query"); break; case QUERY_TYPE_PIPELINE_STATISTICS: #if GL_PRIMITIVES_GENERATED glBeginQuery(GL_PRIMITIVES_GENERATED, glQuery); - CHECK_GL_ERROR("Failed to begin GL_PRIMITIVES_GENERATED query"); + DEV_CHECK_GL_ERROR("Failed to begin GL_PRIMITIVES_GENERATED query"); #else LOG_ERROR_MESSAGE_ONCE("GL_PRIMITIVES_GENERATED query is not supported by this device"); #endif @@ -1114,26 +1266,26 @@ void DeviceContextGLImpl::EndQuery(IQuery* pQuery) case QUERY_TYPE_OCCLUSION: #if GL_SAMPLES_PASSED glEndQuery(GL_SAMPLES_PASSED); - CHECK_GL_ERROR("Failed to end GL_SAMPLES_PASSED query"); + DEV_CHECK_GL_ERROR("Failed to end GL_SAMPLES_PASSED query"); #endif break; case QUERY_TYPE_BINARY_OCCLUSION: glEndQuery(GL_ANY_SAMPLES_PASSED); - CHECK_GL_ERROR("Failed to end GL_ANY_SAMPLES_PASSED query"); + DEV_CHECK_GL_ERROR("Failed to end GL_ANY_SAMPLES_PASSED query"); break; case QUERY_TYPE_PIPELINE_STATISTICS: #if GL_PRIMITIVES_GENERATED glEndQuery(GL_PRIMITIVES_GENERATED); - CHECK_GL_ERROR("Failed to end GL_PRIMITIVES_GENERATED query"); + DEV_CHECK_GL_ERROR("Failed to end GL_PRIMITIVES_GENERATED query"); #endif break; case QUERY_TYPE_TIMESTAMP: #if GL_ARB_timer_query glQueryCounter(pQueryGLImpl->GetGlQueryHandle(), GL_TIMESTAMP); - CHECK_GL_ERROR("glQueryCounter failed"); + DEV_CHECK_GL_ERROR("glQueryCounter failed"); #else LOG_ERROR_MESSAGE_ONCE("Timer queries are not supported by this device"); #endif @@ -1373,12 +1525,13 @@ void DeviceContextGLImpl::GenerateMips(ITextureView* pTexView) auto BindTarget = pTexViewGL->GetBindTarget(); m_ContextState.BindTexture(-1, BindTarget, pTexViewGL->GetHandle()); glGenerateMipmap(BindTarget); - CHECK_GL_ERROR("Failed to generate mip maps"); + DEV_CHECK_GL_ERROR("Failed to generate mip maps"); m_ContextState.BindTexture(-1, BindTarget, GLObjectWrappers::GLTextureObj::Null()); } void DeviceContextGLImpl::TransitionResourceStates(Uint32 BarrierCount, StateTransitionDesc* pResourceBarriers) { + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); } void DeviceContextGLImpl::ResolveTextureSubresource(ITexture* pSrcTexture, diff --git a/Graphics/GraphicsEngineOpenGL/src/FBOCache.cpp b/Graphics/GraphicsEngineOpenGL/src/FBOCache.cpp index 5d18a955..e11a3af2 100644 --- a/Graphics/GraphicsEngineOpenGL/src/FBOCache.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/FBOCache.cpp @@ -109,6 +109,116 @@ void FBOCache::OnReleaseTexture(ITexture* pTexture) m_TexIdToKey.erase(EqualRange.first, EqualRange.second); } +GLObjectWrappers::GLFrameBufferObj FBOCache::CreateFBO(GLContextState& ContextState, + Uint32 NumRenderTargets, + TextureViewGLImpl* ppRTVs[], + TextureViewGLImpl* pDSV) +{ + GLObjectWrappers::GLFrameBufferObj FBO{true}; + + ContextState.BindFBO(FBO); + + // Initialize the FBO + for (Uint32 rt = 0; rt < NumRenderTargets; ++rt) + { + if (auto* pRTView = ppRTVs[rt]) + { + const auto& RTVDesc = pRTView->GetDesc(); + auto* pColorTexGL = pRTView->GetTexture<TextureBaseGL>(); + pColorTexGL->AttachToFramebuffer(RTVDesc, GL_COLOR_ATTACHMENT0 + rt); + } + } + + if (pDSV != nullptr) + { + const auto& DSVDesc = pDSV->GetDesc(); + auto* pDepthTexGL = pDSV->GetTexture<TextureBaseGL>(); + GLenum AttachmentPoint = 0; + if (DSVDesc.Format == TEX_FORMAT_D32_FLOAT || + DSVDesc.Format == TEX_FORMAT_D16_UNORM) + { +#ifdef DILIGENT_DEBUG + { + const auto GLTexFmt = pDepthTexGL->GetGLTexFormat(); + VERIFY(GLTexFmt == GL_DEPTH_COMPONENT32F || GLTexFmt == GL_DEPTH_COMPONENT16, + "Inappropriate internal texture format (", GLTexFmt, + ") for depth attachment. GL_DEPTH_COMPONENT32F or GL_DEPTH_COMPONENT16 is expected"); + } +#endif + AttachmentPoint = GL_DEPTH_ATTACHMENT; + } + else if (DSVDesc.Format == TEX_FORMAT_D32_FLOAT_S8X24_UINT || + DSVDesc.Format == TEX_FORMAT_D24_UNORM_S8_UINT) + { +#ifdef DILIGENT_DEBUG + { + const auto GLTexFmt = pDepthTexGL->GetGLTexFormat(); + VERIFY(GLTexFmt == GL_DEPTH24_STENCIL8 || GLTexFmt == GL_DEPTH32F_STENCIL8, + "Inappropriate internal texture format (", GLTexFmt, + ") for depth-stencil attachment. GL_DEPTH24_STENCIL8 or GL_DEPTH32F_STENCIL8 is expected"); + } +#endif + AttachmentPoint = GL_DEPTH_STENCIL_ATTACHMENT; + } + else + { + UNEXPECTED(GetTextureFormatAttribs(DSVDesc.Format).Name, " is not valid depth-stencil view format"); + } + pDepthTexGL->AttachToFramebuffer(DSVDesc, AttachmentPoint); + } + + // We now need to set mapping between shader outputs and + // color attachments. This largely redundant step is performed + // by glDrawBuffers() + // clang-format off + static const GLenum DrawBuffers[] = + { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7, + GL_COLOR_ATTACHMENT8, + GL_COLOR_ATTACHMENT9, + GL_COLOR_ATTACHMENT10, + GL_COLOR_ATTACHMENT11, + GL_COLOR_ATTACHMENT12, + GL_COLOR_ATTACHMENT13, + GL_COLOR_ATTACHMENT14, + GL_COLOR_ATTACHMENT15 + }; + // clang-format on + + // The state set by glDrawBuffers() is part of the state of the framebuffer. + // So it can be set up once and left it set. + glDrawBuffers(NumRenderTargets, DrawBuffers); + CHECK_GL_ERROR("Failed to set draw buffers via glDrawBuffers()"); + + GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (Status != GL_FRAMEBUFFER_COMPLETE) + { + const Char* StatusString = "Unknown"; + switch (Status) + { + // clang-format off + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break; + case GL_FRAMEBUFFER_UNSUPPORTED: StatusString = "GL_FRAMEBUFFER_UNSUPPORTED"; break; + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break; + case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break; + // clang-format on + } + LOG_ERROR("Framebuffer is incomplete. FB status: ", StatusString); + UNEXPECTED("Framebuffer is incomplete"); + } + return FBO; +} + const GLObjectWrappers::GLFrameBufferObj& FBOCache::GetFBO(Uint32 NumRenderTargets, TextureViewGLImpl* ppRTVs[], TextureViewGLImpl* pDSV, @@ -163,108 +273,7 @@ const GLObjectWrappers::GLFrameBufferObj& FBOCache::GetFBO(Uint32 Nu else { // Create a new FBO - GLObjectWrappers::GLFrameBufferObj NewFBO(true); - - ContextState.BindFBO(NewFBO); - - // Initialize the FBO - for (Uint32 rt = 0; rt < NumRenderTargets; ++rt) - { - if (auto* pRTView = ppRTVs[rt]) - { - const auto& RTVDesc = pRTView->GetDesc(); - auto* pColorTexGL = pRTView->GetTexture<TextureBaseGL>(); - pColorTexGL->AttachToFramebuffer(RTVDesc, GL_COLOR_ATTACHMENT0 + rt); - } - } - - if (pDSV != nullptr) - { - const auto& DSVDesc = pDSV->GetDesc(); - auto* pDepthTexGL = pDSV->GetTexture<TextureBaseGL>(); - GLenum AttachmentPoint = 0; - if (DSVDesc.Format == TEX_FORMAT_D32_FLOAT || - DSVDesc.Format == TEX_FORMAT_D16_UNORM) - { -#ifdef DILIGENT_DEBUG - { - const auto GLTexFmt = pDepthTexGL->GetGLTexFormat(); - VERIFY(GLTexFmt == GL_DEPTH_COMPONENT32F || GLTexFmt == GL_DEPTH_COMPONENT16, - "Inappropriate internal texture format (", GLTexFmt, - ") for depth attachment. GL_DEPTH_COMPONENT32F or GL_DEPTH_COMPONENT16 is expected"); - } -#endif - AttachmentPoint = GL_DEPTH_ATTACHMENT; - } - else if (DSVDesc.Format == TEX_FORMAT_D32_FLOAT_S8X24_UINT || - DSVDesc.Format == TEX_FORMAT_D24_UNORM_S8_UINT) - { -#ifdef DILIGENT_DEBUG - { - const auto GLTexFmt = pDepthTexGL->GetGLTexFormat(); - VERIFY(GLTexFmt == GL_DEPTH24_STENCIL8 || GLTexFmt == GL_DEPTH32F_STENCIL8, - "Inappropriate internal texture format (", GLTexFmt, - ") for depth-stencil attachment. GL_DEPTH24_STENCIL8 or GL_DEPTH32F_STENCIL8 is expected"); - } -#endif - AttachmentPoint = GL_DEPTH_STENCIL_ATTACHMENT; - } - else - { - UNEXPECTED(GetTextureFormatAttribs(DSVDesc.Format).Name, " is not valid depth-stencil view format"); - } - pDepthTexGL->AttachToFramebuffer(DSVDesc, AttachmentPoint); - } - - // We now need to set mapping between shader outputs and - // color attachments. This largely redundant step is performed - // by glDrawBuffers() - // clang-format off - static const GLenum DrawBuffers[] = - { - GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1, - GL_COLOR_ATTACHMENT2, - GL_COLOR_ATTACHMENT3, - GL_COLOR_ATTACHMENT4, - GL_COLOR_ATTACHMENT5, - GL_COLOR_ATTACHMENT6, - GL_COLOR_ATTACHMENT7, - GL_COLOR_ATTACHMENT8, - GL_COLOR_ATTACHMENT9, - GL_COLOR_ATTACHMENT10, - GL_COLOR_ATTACHMENT11, - GL_COLOR_ATTACHMENT12, - GL_COLOR_ATTACHMENT13, - GL_COLOR_ATTACHMENT14, - GL_COLOR_ATTACHMENT15 - }; - // clang-format on - - // The state set by glDrawBuffers() is part of the state of the framebuffer. - // So it can be set up once and left it set. - glDrawBuffers(NumRenderTargets, DrawBuffers); - CHECK_GL_ERROR("Failed to set draw buffers via glDrawBuffers()"); - - GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (Status != GL_FRAMEBUFFER_COMPLETE) - { - const Char* StatusString = "Unknown"; - switch (Status) - { - // clang-format off - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break; - case GL_FRAMEBUFFER_UNSUPPORTED: StatusString = "GL_FRAMEBUFFER_UNSUPPORTED"; break; - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break; - case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: StatusString = "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break; - // clang-format on - } - LOG_ERROR("Framebuffer is incomplete. FB status: ", StatusString); - UNEXPECTED("Framebuffer is incomplete"); - } + auto NewFBO = CreateFBO(ContextState, NumRenderTargets, ppRTVs, pDSV); auto NewElems = m_Cache.emplace(std::make_pair(Key, std::move(NewFBO))); // New element must be actually inserted diff --git a/Graphics/GraphicsEngineOpenGL/src/FramebufferGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/FramebufferGLImpl.cpp new file mode 100644 index 00000000..c84d9816 --- /dev/null +++ b/Graphics/GraphicsEngineOpenGL/src/FramebufferGLImpl.cpp @@ -0,0 +1,138 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" + +#include "FramebufferGLImpl.hpp" +#include "FBOCache.hpp" +#include "TextureViewGLImpl.hpp" + +namespace Diligent +{ + +static bool UseDefaultFBO(Uint32 NumRenderTargets, + TextureViewGLImpl* ppRTVs[], + TextureViewGLImpl* pDSV) +{ + bool useDefaultFBO = false; + for (Uint32 rt = 0; rt < NumRenderTargets; ++rt) + { + if (ppRTVs[rt] != nullptr && ppRTVs[rt]->GetHandle() == 0) + { + if (rt == 0) + { + useDefaultFBO = true; + } + else + { + LOG_ERROR_AND_THROW("In OpenGL, swap chain back buffer can be the only render target in the framebuffer " + "and cannot be combined with any other render target."); + } + } + } + + if (pDSV != nullptr) + { + if (useDefaultFBO && pDSV->GetHandle() != 0) + { + LOG_ERROR_AND_THROW("In OpenGL, swap chain back buffer can only be paired with the default depth-stencil buffer."); + } + + if (pDSV->GetHandle() == 0) + { + if (!useDefaultFBO && NumRenderTargets > 0) + { + LOG_ERROR_AND_THROW("In OpenGL, the swap chain's depth-stencil buffer can only be paired with its back buffer."); + } + else + { + useDefaultFBO = true; + } + } + } + + return useDefaultFBO; +} + +FramebufferGLImpl::FramebufferGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDevice, + GLContextState& CtxState, + const FramebufferDesc& Desc) : + TFramebufferBase{pRefCounters, pDevice, Desc} +{ + const auto& RPDesc = m_Desc.pRenderPass->GetDesc(); + m_SubpassFramebuffers.reserve(RPDesc.SubpassCount); + for (Uint32 subpass = 0; subpass < RPDesc.SubpassCount; ++subpass) + { + const auto& SubpassDesc = RPDesc.pSubpasses[subpass]; + + TextureViewGLImpl* ppRTVs[MAX_RENDER_TARGETS] = {}; + TextureViewGLImpl* pDSV = nullptr; + + for (Uint32 rt = 0; rt < SubpassDesc.RenderTargetAttachmentCount; ++rt) + { + const auto& RTAttachmentRef = SubpassDesc.pRenderTargetAttachments[rt]; + if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + ppRTVs[rt] = ValidatedCast<TextureViewGLImpl>(m_Desc.ppAttachments[RTAttachmentRef.AttachmentIndex]); + } + } + + if (SubpassDesc.pDepthStencilAttachment != nullptr && SubpassDesc.pDepthStencilAttachment->AttachmentIndex != ATTACHMENT_UNUSED) + { + pDSV = ValidatedCast<TextureViewGLImpl>(m_Desc.ppAttachments[SubpassDesc.pDepthStencilAttachment->AttachmentIndex]); + } + auto RenderTargetFBO = UseDefaultFBO(SubpassDesc.RenderTargetAttachmentCount, ppRTVs, pDSV) ? + GLObjectWrappers::GLFrameBufferObj{false} : + FBOCache::CreateFBO(CtxState, SubpassDesc.RenderTargetAttachmentCount, ppRTVs, pDSV); + + GLObjectWrappers::GLFrameBufferObj ResolveFBO{false}; + if (SubpassDesc.pResolveAttachments != nullptr) + { + TextureViewGLImpl* ppRsvlViews[MAX_RENDER_TARGETS] = {}; + for (Uint32 rt = 0; rt < SubpassDesc.RenderTargetAttachmentCount; ++rt) + { + const auto& RslvAttachmentRef = SubpassDesc.pResolveAttachments[rt]; + if (RslvAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + ppRsvlViews[rt] = ValidatedCast<TextureViewGLImpl>(m_Desc.ppAttachments[RslvAttachmentRef.AttachmentIndex]); + } + } + ResolveFBO = UseDefaultFBO(SubpassDesc.RenderTargetAttachmentCount, ppRsvlViews, nullptr) ? + GLObjectWrappers::GLFrameBufferObj{false} : + FBOCache::CreateFBO(CtxState, SubpassDesc.RenderTargetAttachmentCount, ppRsvlViews, nullptr); + } + + m_SubpassFramebuffers.emplace_back(std::move(RenderTargetFBO), std::move(ResolveFBO)); + } +} + +FramebufferGLImpl::~FramebufferGLImpl() +{ +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp index 5734ae75..ae77fbcf 100644 --- a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp @@ -46,6 +46,8 @@ #include "ShaderResourceBindingGLImpl.hpp" #include "FenceGLImpl.hpp" #include "QueryGLImpl.hpp" +#include "RenderPassGLImpl.hpp" +#include "FramebufferGLImpl.hpp" #include "EngineMemory.h" #include "StringTools.hpp" @@ -75,7 +77,9 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, sizeof(PipelineStateGLImpl), sizeof(ShaderResourceBindingGLImpl), sizeof(FenceGLImpl), - sizeof(QueryGLImpl) + sizeof(QueryGLImpl), + sizeof(RenderPassGLImpl), + sizeof(FramebufferGLImpl) } }, // Device caps must be filled in before the constructor of Pipeline Cache is called! @@ -515,6 +519,34 @@ void RenderDeviceGLImpl::CreateQuery(const QueryDesc& Desc, IQuery** ppQuery) ); } +void RenderDeviceGLImpl::CreateRenderPass(const RenderPassDesc& Desc, IRenderPass** ppRenderPass) +{ + CreateDeviceObject( + "RenderPass", Desc, ppRenderPass, + [&]() // + { + RenderPassGLImpl* pRenderPassOGL(NEW_RC_OBJ(m_RenderPassAllocator, "RenderPassGLImpl instance", RenderPassGLImpl)(this, Desc)); + pRenderPassOGL->QueryInterface(IID_RenderPass, reinterpret_cast<IObject**>(ppRenderPass)); + OnCreateDeviceObject(pRenderPassOGL); + } // + ); +} + +void RenderDeviceGLImpl::CreateFramebuffer(const FramebufferDesc& Desc, IFramebuffer** ppFramebuffer) +{ + CreateDeviceObject("Framebuffer", Desc, ppFramebuffer, + [&]() // + { + auto spDeviceContext = GetImmediateContext(); + VERIFY(spDeviceContext, "Immediate device context has been destroyed"); + auto& GLState = spDeviceContext.RawPtr<DeviceContextGLImpl>()->GetContextState(); + + FramebufferGLImpl* pFramebufferGL(NEW_RC_OBJ(m_FramebufferAllocator, "FramebufferGLImpl instance", FramebufferGLImpl)(this, GLState, Desc)); + pFramebufferGL->QueryInterface(IID_Framebuffer, reinterpret_cast<IObject**>(ppFramebuffer)); + OnCreateDeviceObject(pFramebufferGL); + }); +} + bool RenderDeviceGLImpl::CheckExtension(const Char* ExtensionString) { return m_ExtensionStrings.find(ExtensionString) != m_ExtensionStrings.end(); diff --git a/Graphics/GraphicsEngineOpenGL/src/RenderPassGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/RenderPassGLImpl.cpp new file mode 100644 index 00000000..2a9d0609 --- /dev/null +++ b/Graphics/GraphicsEngineOpenGL/src/RenderPassGLImpl.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" + +#include "RenderPassGLImpl.hpp" +#include "EngineMemory.h" + +namespace Diligent +{ + +RenderPassGLImpl::RenderPassGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDevice, + const RenderPassDesc& Desc) : + TRenderPassBase{pRefCounters, pDevice, Desc} +{ +} + +RenderPassGLImpl::~RenderPassGLImpl() +{ +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp b/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp index 06e49cd6..86b5ef40 100644 --- a/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp @@ -579,7 +579,10 @@ void TextureBaseGL::CopyData(DeviceContextGLImpl* pDeviceCtxGL, } #if GL_ARB_copy_image - if (glCopyImageSubData) + const bool IsDefaultBackBuffer = GetGLHandle() == 0; + // We can't use glCopyImageSubData with the proxy texture of a default framebuffer + // because we don't have the texture handle. Resort to quad rendering in this case. + if (glCopyImageSubData && !IsDefaultBackBuffer) { GLint SrcSliceY = (SrcTexDesc.Type == RESOURCE_DIM_TEX_1D_ARRAY) ? SrcSlice : 0; GLint SrcSliceZ = (SrcTexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY) ? SrcSlice : 0; |
