summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineOpenGL
diff options
context:
space:
mode:
authorazhirnov <zh1dron@gmail.com>2020-08-19 15:02:00 +0000
committerazhirnov <zh1dron@gmail.com>2020-08-19 15:02:00 +0000
commit0703251a71c8cea898358abb9ecb7460c8655718 (patch)
tree7f429c6e9871790fc9491c31bac0c1ca90e96873 /Graphics/GraphicsEngineOpenGL
parentformatting (diff)
parentUpdated description of indirect draw/dispatch commands to specify the argumen... (diff)
downloadDiligentCore-0703251a71c8cea898358abb9ecb7460c8655718.tar.gz
DiligentCore-0703251a71c8cea898358abb9ecb7460c8655718.zip
Merge branch 'master' into mesh_shader
# Conflicts: # Graphics/GraphicsEngine/include/PipelineStateBase.hpp # Graphics/GraphicsEngine/interface/PipelineState.h # Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp # Graphics/GraphicsEngineD3D12/include/CommandContext.hpp
Diffstat (limited to 'Graphics/GraphicsEngineOpenGL')
-rw-r--r--Graphics/GraphicsEngineOpenGL/CMakeLists.txt4
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp20
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/FBOCache.hpp7
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/FramebufferGLImpl.hpp78
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp8
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/RenderPassGLImpl.hpp54
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp201
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/FBOCache.cpp213
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/FramebufferGLImpl.cpp138
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp34
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/RenderPassGLImpl.cpp47
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp5
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 54eff631..205c62b7 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.
@@ -255,6 +270,9 @@ private:
__forceinline void PrepareForIndirectDraw(IBuffer* pAttribsBuffer);
__forceinline void PostDraw();
+ void BeginSubpass();
+ void EndSubpass();
+
Uint32 m_CommitedResourcesTentativeBarriers = 0;
std::vector<class TextureBaseGL*> m_BoundWritableTextures;
@@ -265,6 +283,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 7728de7b..d7a95033 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());
}
@@ -893,7 +1042,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
@@ -920,10 +1069,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);
@@ -969,7 +1118,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);
}
@@ -982,8 +1131,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)
@@ -1022,7 +1169,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);
@@ -1030,6 +1177,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();
}
@@ -1054,7 +1206,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);
}
@@ -1087,7 +1239,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
@@ -1095,13 +1247,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
@@ -1124,26 +1276,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
@@ -1383,12 +1535,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;