OpenGLRenderer: Implement texture blit/copy if glCopyImageSubData is not supported
This commit is contained in:
parent
4933a389a2
commit
7ab4d91900
|
|
@ -26,6 +26,8 @@ namespace Nz
|
|||
|
||||
namespace Nz::GL
|
||||
{
|
||||
class Texture;
|
||||
|
||||
enum class BufferTarget
|
||||
{
|
||||
Array,
|
||||
|
|
@ -107,7 +109,9 @@ namespace Nz::GL
|
|||
friend SymbolLoader;
|
||||
|
||||
public:
|
||||
inline Context(const OpenGLDevice* device);
|
||||
Context(const OpenGLDevice* device);
|
||||
Context(const Context&) = delete;
|
||||
Context(Context&&) = delete;
|
||||
virtual ~Context();
|
||||
|
||||
void BindBuffer(BufferTarget target, GLuint buffer, bool force = false) const;
|
||||
|
|
@ -120,8 +124,14 @@ namespace Nz::GL
|
|||
void BindUniformBuffer(UInt32 uboUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const;
|
||||
void BindVertexArray(GLuint vertexArray, bool force = false) const;
|
||||
|
||||
bool BlitTexture(const Texture& source, const Texture& destination, const Boxui& srcBox, const Vector3ui& dstPos, SamplerFilter filter) const;
|
||||
|
||||
bool ClearErrorStack() const;
|
||||
|
||||
bool CopyTexture(const Texture& source, const Texture& destination, const Boxui& srcBox, const Vector3ui& dstPos) const;
|
||||
|
||||
inline bool DidLastCallSucceed() const;
|
||||
|
||||
virtual void EnableVerticalSync(bool enabled) = 0;
|
||||
|
||||
inline const OpenGLDevice* GetDevice() const;
|
||||
|
|
@ -160,6 +170,9 @@ namespace Nz::GL
|
|||
NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_FUNC)
|
||||
#undef NAZARA_OPENGLRENDERER_FUNC
|
||||
|
||||
Context& operator=(const Context&) = delete;
|
||||
Context& operator=(Context&&) = delete;
|
||||
|
||||
static const Context* GetCurrentContext();
|
||||
static bool SetCurrentContext(const Context* context);
|
||||
|
||||
|
|
@ -176,7 +189,8 @@ namespace Nz::GL
|
|||
ContextParams m_params;
|
||||
|
||||
private:
|
||||
void GL_APIENTRY HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const;
|
||||
void HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const;
|
||||
bool InitializeBlitFramebuffers() const;
|
||||
|
||||
enum class FunctionIndex
|
||||
{
|
||||
|
|
@ -187,6 +201,8 @@ namespace Nz::GL
|
|||
Count
|
||||
};
|
||||
|
||||
struct BlitFramebuffers;
|
||||
|
||||
struct State
|
||||
{
|
||||
struct Box
|
||||
|
|
@ -223,10 +239,13 @@ namespace Nz::GL
|
|||
|
||||
std::array<ExtensionStatus, UnderlyingCast(Extension::Max) + 1> m_extensionStatus;
|
||||
std::array<GLFunction, UnderlyingCast(FunctionIndex::Count)> m_originalFunctionPointer;
|
||||
mutable std::unique_ptr<BlitFramebuffers> m_blitFramebuffers;
|
||||
std::unordered_set<std::string> m_supportedExtensions;
|
||||
OpenGLVaoCache m_vaoCache;
|
||||
const OpenGLDevice* m_device;
|
||||
mutable State m_state;
|
||||
mutable bool m_didCollectErrors;
|
||||
mutable bool m_hadAnyError;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@
|
|||
|
||||
namespace Nz::GL
|
||||
{
|
||||
inline Context::Context(const OpenGLDevice* device) :
|
||||
m_vaoCache(*this),
|
||||
m_device(device)
|
||||
inline bool Context::DidLastCallSucceed() const
|
||||
{
|
||||
if (!m_didCollectErrors)
|
||||
ProcessErrorStack();
|
||||
|
||||
return !m_hadAnyError;
|
||||
}
|
||||
|
||||
inline const OpenGLDevice* Context::GetDevice() const
|
||||
|
|
|
|||
|
|
@ -64,25 +64,7 @@ namespace Nz
|
|||
const OpenGLTexture& glTexture = static_cast<const OpenGLTexture&>(source);
|
||||
|
||||
const GL::Context& context = m_texture.EnsureDeviceContext();
|
||||
|
||||
// Use glCopyImageSubData if available
|
||||
if (context.glCopyImageSubData)
|
||||
{
|
||||
GLuint srcImage = glTexture.GetTexture().GetObjectId();
|
||||
GLenum srcTarget = ToOpenGL(ToTextureTarget(glTexture.GetType()));
|
||||
|
||||
GLuint dstImage = m_texture.GetObjectId();
|
||||
GLenum dstTarget = ToOpenGL(ToTextureTarget(m_params.type));
|
||||
|
||||
context.glCopyImageSubData(srcImage, srcTarget, 0, GLint(srcBox.x), GLint(srcBox.y), GLint(srcBox.z), dstImage, dstTarget, 0, GLint(dstPos.x), GLint(dstPos.y), GLint(dstPos.z), GLsizei(srcBox.width), GLsizei(srcBox.height), GLsizei(srcBox.depth));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: Blit using framebuffers
|
||||
}
|
||||
|
||||
return false;
|
||||
return context.CopyTexture(glTexture.GetTexture(), m_texture, srcBox, dstPos);
|
||||
}
|
||||
|
||||
PixelFormat OpenGLTexture::GetFormat() const
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/OpenGLRenderer/Wrapper/Context.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/StringExt.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLDevice.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLTexture.hpp>
|
||||
#include <Nazara/OpenGLRenderer/Utils.hpp>
|
||||
#include <Nazara/OpenGLRenderer/Wrapper/Loader.hpp>
|
||||
#include <Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
|
@ -56,6 +58,12 @@ namespace Nz::GL
|
|||
};
|
||||
}
|
||||
|
||||
struct Context::BlitFramebuffers
|
||||
{
|
||||
GL::Framebuffer drawFBO;
|
||||
GL::Framebuffer readFBO;
|
||||
};
|
||||
|
||||
struct Context::SymbolLoader
|
||||
{
|
||||
SymbolLoader(Context& parent) :
|
||||
|
|
@ -99,6 +107,15 @@ namespace Nz::GL
|
|||
Context& context;
|
||||
};
|
||||
|
||||
|
||||
Context::Context(const OpenGLDevice* device) :
|
||||
m_vaoCache(*this),
|
||||
m_device(device),
|
||||
m_didCollectErrors(false),
|
||||
m_hadAnyError(false)
|
||||
{
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
if (m_device)
|
||||
|
|
@ -235,15 +252,71 @@ namespace Nz::GL
|
|||
}
|
||||
}
|
||||
|
||||
bool Context::BlitTexture(const Texture& source, const Texture& destination, const Boxui& srcBox, const Vector3ui& dstPos, SamplerFilter filter) const
|
||||
{
|
||||
if (!m_blitFramebuffers && !InitializeBlitFramebuffers())
|
||||
return false;
|
||||
|
||||
//TODO: handle other textures types
|
||||
assert(source.GetTarget() == TextureTarget::Target2D);
|
||||
assert(destination.GetTarget() == TextureTarget::Target2D);
|
||||
|
||||
// Bind framebuffers before configuring them (so they won't override each other)
|
||||
BindFramebuffer(FramebufferTarget::Draw, m_blitFramebuffers->drawFBO.GetObjectId());
|
||||
BindFramebuffer(FramebufferTarget::Read, m_blitFramebuffers->readFBO.GetObjectId());
|
||||
|
||||
// Attach textures to color attachment
|
||||
m_blitFramebuffers->drawFBO.Texture2D(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destination.GetObjectId());
|
||||
if (GLenum checkResult = m_blitFramebuffers->drawFBO.Check(); checkResult != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
NazaraError("Blit draw FBO is incomplete: " + TranslateOpenGLError(checkResult));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_blitFramebuffers->readFBO.Texture2D(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, source.GetObjectId());
|
||||
if (GLenum checkResult = m_blitFramebuffers->readFBO.Check(); checkResult != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
NazaraError("Blit read FBO is incomplete: " + TranslateOpenGLError(checkResult));
|
||||
return false;
|
||||
}
|
||||
|
||||
glBlitFramebuffer(srcBox.x, srcBox.y, srcBox.x + srcBox.width, srcBox.y + srcBox.height, dstPos.x, dstPos.y, dstPos.x + srcBox.width, dstPos.y + srcBox.height, GL_COLOR_BUFFER_BIT, ToOpenGL(filter));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Context::ClearErrorStack() const
|
||||
{
|
||||
assert(GetCurrentContext() == this);
|
||||
|
||||
while (glGetError() != GL_NO_ERROR);
|
||||
|
||||
m_didCollectErrors = false;
|
||||
m_hadAnyError = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Context::CopyTexture(const Texture& source, const Texture& destination, const Boxui& srcBox, const Vector3ui& dstPos) const
|
||||
{
|
||||
// Use glCopyImageSubData if available
|
||||
if (glCopyImageSubData && false)
|
||||
{
|
||||
GLuint srcImage = source.GetObjectId();
|
||||
GLenum srcTarget = ToOpenGL(source.GetTarget());
|
||||
|
||||
GLuint dstImage = destination.GetObjectId();
|
||||
GLenum dstTarget = ToOpenGL(destination.GetTarget());
|
||||
|
||||
glCopyImageSubData(srcImage, srcTarget, 0, GLint(srcBox.x), GLint(srcBox.y), GLint(srcBox.z), dstImage, dstTarget, 0, GLint(dstPos.x), GLint(dstPos.y), GLint(dstPos.z), GLsizei(srcBox.width), GLsizei(srcBox.height), GLsizei(srcBox.depth));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If glCopyImageSubData is not available, fallback to framebuffer blit
|
||||
return BlitTexture(source, destination, srcBox, dstPos, SamplerFilter::Nearest);
|
||||
}
|
||||
}
|
||||
|
||||
bool Context::Initialize(const ContextParams& params)
|
||||
{
|
||||
if (!SetCurrentContext(this))
|
||||
|
|
@ -397,8 +470,8 @@ namespace Nz::GL
|
|||
glGetIntegerv(GL_VIEWPORT, res.data());
|
||||
m_state.viewport = { res[0], res[1], res[2], res[3] };
|
||||
|
||||
m_state.renderStates.frontFace = FrontFace::CounterClockwise; //< OpenGL default front face is counter-clockwise
|
||||
m_state.renderStates.depthCompare = RendererComparison::Less; //< OpenGL default depth mode is GL_LESS
|
||||
m_state.renderStates.frontFace = FrontFace::CounterClockwise; //< OpenGL default front face is counter-clockwise
|
||||
|
||||
EnableVerticalSync(false);
|
||||
|
||||
|
|
@ -419,6 +492,9 @@ namespace Nz::GL
|
|||
NazaraError("OpenGL error: " + TranslateOpenGLError(lastError));
|
||||
}
|
||||
|
||||
m_didCollectErrors = true;
|
||||
m_hadAnyError = hasAnyError;
|
||||
|
||||
return hasAnyError;
|
||||
}
|
||||
|
||||
|
|
@ -707,6 +783,7 @@ namespace Nz::GL
|
|||
|
||||
void Context::OnContextRelease()
|
||||
{
|
||||
m_blitFramebuffers.reset();
|
||||
m_vaoCache.Clear();
|
||||
}
|
||||
|
||||
|
|
@ -840,4 +917,22 @@ namespace Nz::GL
|
|||
|
||||
NazaraNotice(ss.str());
|
||||
}
|
||||
|
||||
bool Context::InitializeBlitFramebuffers() const
|
||||
{
|
||||
m_blitFramebuffers = std::make_unique<BlitFramebuffers>();
|
||||
if (!m_blitFramebuffers->drawFBO.Create(*this))
|
||||
{
|
||||
NazaraError("failed to initialize draw FBO");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_blitFramebuffers->readFBO.Create(*this))
|
||||
{
|
||||
NazaraError("failed to initialize read FBO");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue