Skip to content

Commit

Permalink
OpenGL backend: use glBlitFramebuffer to copy depth textures in GLES
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Nov 5, 2023
1 parent 95aa211 commit 00cd1a7
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 18 deletions.
4 changes: 2 additions & 2 deletions Graphics/GraphicsEngineOpenGL/include/FBOCache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
#include "SpinLock.hpp"
#include "HashUtils.hpp"
#include "GLObjectWrapper.hpp"
#include "TextureBaseGL.hpp"

namespace Diligent
{

class TextureBaseGL;
class TextureViewGLImpl;
class GLContextState;

Expand Down Expand Up @@ -68,7 +68,7 @@ class FBOCache
const GLObjectWrappers::GLFrameBufferObj& GetFBO(Uint32 Width, Uint32 Height, GLContextState& ContextState);

// NOTE: the function may bind a framebuffer, so the FBO in the GL context state must be invalidated.
const GLObjectWrappers::GLFrameBufferObj& GetReadFBO(TextureBaseGL* pTex, Uint32 ArraySlice, Uint32 MipLevel);
const GLObjectWrappers::GLFrameBufferObj& GetFBO(TextureBaseGL* pTex, Uint32 ArraySlice, Uint32 MipLevel, TextureBaseGL::FRAMEBUFFER_TARGET_FLAGS Targets);

void OnReleaseTexture(ITexture* pTexture);

Expand Down
25 changes: 19 additions & 6 deletions Graphics/GraphicsEngineOpenGL/src/FBOCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,10 @@ inline GLenum GetFramebufferAttachmentPoint(TEXTURE_FORMAT Format)
}
}

const GLObjectWrappers::GLFrameBufferObj& FBOCache::GetReadFBO(TextureBaseGL* pTex, Uint32 ArraySlice, Uint32 MipLevel)
const GLObjectWrappers::GLFrameBufferObj& FBOCache::GetFBO(TextureBaseGL* pTex,
Uint32 ArraySlice,
Uint32 MipLevel,
TextureBaseGL::FRAMEBUFFER_TARGET_FLAGS Targets)
{
const auto& TexDesc = pTex->GetDesc();

Expand All @@ -357,8 +360,10 @@ const GLObjectWrappers::GLFrameBufferObj& FBOCache::GetReadFBO(TextureBaseGL* pT
auto& RTV0{Key.RTVDescs[0]};
RTV0.Format = TexDesc.Format;
RTV0.TextureDim = TexDesc.Type;
// Use SRV to make AttachToFramebuffer only attach to read framebuffer
RTV0.ViewType = TEXTURE_VIEW_SHADER_RESOURCE;
RTV0.ViewType = (Targets & TextureBaseGL::FRAMEBUFFER_TARGET_FLAG_DRAW) ?
TEXTURE_VIEW_RENDER_TARGET : // Also OK for depth attachments
TEXTURE_VIEW_SHADER_RESOURCE;

RTV0.FirstArraySlice = ArraySlice;
RTV0.MostDetailedMip = MipLevel;
RTV0.NumArraySlices = 1;
Expand All @@ -373,10 +378,18 @@ const GLObjectWrappers::GLFrameBufferObj& FBOCache::GetReadFBO(TextureBaseGL* pT
// Create a new FBO
GLObjectWrappers::GLFrameBufferObj NewFBO{true};

glBindFramebuffer(GL_READ_FRAMEBUFFER, NewFBO);
DEV_CHECK_GL_ERROR("Failed to bind new FBO as read framebuffer");
if (Targets & TextureBaseGL::FRAMEBUFFER_TARGET_FLAG_READ)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, NewFBO);
DEV_CHECK_GL_ERROR("Failed to bind new FBO as read framebuffer");
}
if (Targets & TextureBaseGL::FRAMEBUFFER_TARGET_FLAG_DRAW)
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, NewFBO);
DEV_CHECK_GL_ERROR("Failed to bind new FBO as draw framebuffer");
}

pTex->AttachToFramebuffer(RTV0, GetFramebufferAttachmentPoint(TexDesc.Format), TextureBaseGL::FRAMEBUFFER_TARGET_FLAG_READ);
pTex->AttachToFramebuffer(RTV0, GetFramebufferAttachmentPoint(TexDesc.Format), Targets);

GLenum Status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
if (Status != GL_FRAMEBUFFER_COMPLETE)
Expand Down
49 changes: 39 additions & 10 deletions Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,9 +625,21 @@ void TextureBaseGL::CopyData(DeviceContextGLImpl* pDeviceCtxGL,
else
#endif
{
bool UseBlitFramebuffer = IsDefaultBackBuffer;
if (!UseBlitFramebuffer && m_pDevice->GetDeviceInfo().Type == RENDER_DEVICE_TYPE_GLES)
{
const auto& FmtAttribs = GetTextureFormatAttribs(m_Desc.Format);
if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH ||
FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL)
{
// glCopyTexSubImage* does not support depth formats in GLES
UseBlitFramebuffer = true;
}
}

auto& GLState = pDeviceCtxGL->GetContextState();

// Copy operations (glCopyTexSubImage2D and family, glBindFramebuffer) are affected by scissor test!
// Copy operations (glCopyTexSubImage* and glBindFramebuffer) are affected by scissor test!
GLboolean ScissorEnabled = GLState.GetScissorTestEnabled();
if (ScissorEnabled)
GLState.EnableScissorTest(false);
Expand All @@ -643,8 +655,8 @@ void TextureBaseGL::CopyData(DeviceContextGLImpl* pDeviceCtxGL,
VERIFY_EXPR(SrcSlice == 0 || SrcTexDesc.IsArray());
VERIFY_EXPR((pSrcBox->MinZ == 0 && DepthSlice == 0) || SrcTexDesc.Is3D());
const auto SrcFramebufferSlice = SrcSlice + pSrcBox->MinZ + DepthSlice;
// NOTE: GetReadFBO may bind a framebuffer.
const auto& ReadFBO = FBOCache.GetReadFBO(pSrcTextureGL, SrcFramebufferSlice, SrcMipLevel);
// NOTE: GetFBO may bind a framebuffer, so we need to invalidate it in the GL context state.
const auto& ReadFBO = FBOCache.GetFBO(pSrcTextureGL, SrcFramebufferSlice, SrcMipLevel, TextureBaseGL::FRAMEBUFFER_TARGET_FLAG_READ);

SrcFboHandle = ReadFBO;
}
Expand All @@ -654,8 +666,10 @@ void TextureBaseGL::CopyData(DeviceContextGLImpl* pDeviceCtxGL,
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, SrcFboHandle);
DEV_CHECK_GL_ERROR("Failed to bind read framebuffer");
DEV_CHECK_ERR(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
"Read framebuffer is incomplete: ", GetFramebufferStatusString(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER)));

if (!IsDefaultBackBuffer)
if (!UseBlitFramebuffer)
{
CopyTexSubimageAttribs CopyAttribs{*pSrcBox};
CopyAttribs.DstMip = DstMipLevel;
Expand All @@ -667,14 +681,29 @@ void TextureBaseGL::CopyData(DeviceContextGLImpl* pDeviceCtxGL,
}
else
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, pDeviceCtxGL->GetDefaultFBO());
GLenum Status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
if (Status != GL_FRAMEBUFFER_COMPLETE)
GLuint DstFboHandle = 0;
if (IsDefaultBackBuffer)
{
const Char* StatusString = GetFramebufferStatusString(Status);
LOG_ERROR("Draw framebuffer is incomplete. FB status: ", StatusString);
UNEXPECTED("Draw framebuffer is incomplete");
DstFboHandle = pDeviceCtxGL->GetDefaultFBO();
}
else
{
// Get draw framebuffer for the destination subimage

auto& FBOCache = m_pDevice->GetFBOCache(GLState.GetCurrentGLContext());
VERIFY_EXPR(DstSlice == 0 || m_Desc.IsArray());
VERIFY_EXPR((DstZ == 0 && DepthSlice == 0) || m_Desc.Is3D());
const auto DstFramebufferSlice = DstSlice + DstZ + DepthSlice;
// NOTE: GetFBO may bind a framebuffer, so we need to invalidate it in the GL context state.
const auto& DrawFBO = FBOCache.GetFBO(this, DstFramebufferSlice, DstMipLevel, TextureBaseGL::FRAMEBUFFER_TARGET_FLAG_DRAW);

DstFboHandle = DrawFBO;
}

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, DstFboHandle);
DEV_CHECK_GL_ERROR("Failed to bind draw framebuffer");
DEV_CHECK_ERR(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
"Draw framebuffer is incomplete: ", GetFramebufferStatusString(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)));

const auto CopyMask = GetFramebufferCopyMask(SrcTexDesc.Format);
DEV_CHECK_ERR(CopyMask == GetFramebufferCopyMask(m_Desc.Format),
Expand Down

0 comments on commit 00cd1a7

Please sign in to comment.