Added RenderBuffer class (Usables with RenderTexture)

Former-commit-id: f32a2d5e5018ce3b1d41db87aec6fa910c8183a3
This commit is contained in:
Lynix 2013-12-07 23:48:21 +01:00
parent f7990e4521
commit 9357079e1d
4 changed files with 272 additions and 59 deletions

View File

@ -0,0 +1,48 @@
// Copyright (C) 2013 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_RENDERBUFFER_HPP
#define NAZARA_RENDERBUFFER_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/NonCopyable.hpp>
#include <Nazara/Core/Resource.hpp>
#include <Nazara/Core/ResourceRef.hpp>
#include <Nazara/Utility/Enums.hpp>
class NzRenderBuffer;
using NzRenderBufferConstRef = NzResourceRef<const NzRenderBuffer>;
using NzRenderBufferRef = NzResourceRef<NzRenderBuffer>;
class NAZARA_API NzRenderBuffer : public NzResource, NzNonCopyable
{
public:
NzRenderBuffer();
~NzRenderBuffer();
bool Create(nzPixelFormat format, unsigned int width, unsigned int height);
void Destroy();
unsigned int GetHeight() const;
nzPixelFormat GetFormat() const;
unsigned int GetWidth() const;
// Fonctions OpenGL
unsigned int GetOpenGLID() const;
bool IsValid() const;
static bool IsSupported();
private:
nzPixelFormat m_pixelFormat;
unsigned int m_height;
unsigned int m_id;
unsigned int m_width;
};
#endif // NAZARA_RENDERBUFFER_HPP

View File

@ -16,6 +16,8 @@
///TODO: Faire fonctionner les RenderTexture indépendamment du contexte (un FBO par classe et par contexte l'utilisant) ///TODO: Faire fonctionner les RenderTexture indépendamment du contexte (un FBO par classe et par contexte l'utilisant)
class NzRenderBuffer;
struct NzRenderTextureImpl; struct NzRenderTextureImpl;
class NAZARA_API NzRenderTexture : public NzRenderTarget, NzResourceListener, NzNonCopyable class NAZARA_API NzRenderTexture : public NzRenderTarget, NzResourceListener, NzNonCopyable
@ -24,6 +26,7 @@ class NAZARA_API NzRenderTexture : public NzRenderTarget, NzResourceListener, Nz
NzRenderTexture() = default; NzRenderTexture() = default;
~NzRenderTexture(); ~NzRenderTexture();
bool AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzRenderBuffer* buffer);
bool AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 index, nzPixelFormat format, unsigned int width, unsigned int height); bool AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 index, nzPixelFormat format, unsigned int width, unsigned int height);
bool AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzTexture* texture, unsigned int z = 0); bool AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzTexture* texture, unsigned int z = 0);
@ -42,14 +45,15 @@ class NAZARA_API NzRenderTexture : public NzRenderTarget, NzResourceListener, Nz
bool Lock() const; bool Lock() const;
void SetColorTarget(nzUInt8 target); void SetColorTarget(nzUInt8 target) const;
void SetColorTargets(const nzUInt8* targets, unsigned int targetCount); void SetColorTargets(const nzUInt8* targets, unsigned int targetCount) const;
void SetColorTargets(const std::initializer_list<nzUInt8>& targets); void SetColorTargets(const std::initializer_list<nzUInt8>& targets) const;
void Unlock() const; void Unlock() const;
// Fonctions OpenGL // Fonctions OpenGL
bool HasContext() const; unsigned int GetOpenGLID() const;
bool HasContext() const override;
static bool IsSupported(); static bool IsSupported();

View File

@ -0,0 +1,116 @@
// Copyright (C) 2013 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/RenderBuffer.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Context.hpp>
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Utility/PixelFormat.hpp>
#include <Nazara/Renderer/Debug.hpp>
NzRenderBuffer::NzRenderBuffer() :
m_id(0)
{
}
NzRenderBuffer::~NzRenderBuffer()
{
Destroy();
}
bool NzRenderBuffer::Create(nzPixelFormat format, unsigned int width, unsigned int height)
{
Destroy();
#if NAZARA_RENDERER_SAFE
if (width == 0 || height == 0)
{
NazaraError("Invalid size");
return false;
}
if (!NzPixelFormat::IsValid(format))
{
NazaraError("Invalid pixel format");
return false;
}
#endif
NzOpenGL::Format openglFormat;
if (!NzOpenGL::TranslateFormat(format, &openglFormat, NzOpenGL::FormatType_RenderBuffer))
{
NazaraError("Failed to translate pixel format \"" + NzPixelFormat::ToString(format) + "\" into OpenGL format");
return false;
}
GLuint renderBuffer = 0;
glGenRenderbuffers(1, &renderBuffer);
if (!renderBuffer)
{
NazaraError("Failed to create renderbuffer");
return false;
}
GLint previous;
glGetIntegerv(GL_RENDERBUFFER_BINDING, &previous);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, openglFormat.internalFormat, width, height);
if (previous != 0)
glBindRenderbuffer(GL_RENDERBUFFER, previous);
m_pixelFormat = format;
m_height = height;
m_id = renderBuffer;
m_width = width;
NotifyCreated();
return true;
}
void NzRenderBuffer::Destroy()
{
if (m_id)
{
NotifyDestroy();
NzContext::EnsureContext();
GLuint renderBuffer = m_id;
glDeleteRenderbuffers(1, &renderBuffer); // Les Renderbuffers sont partagés entre les contextes: Ne posera pas de problème
m_id = 0;
}
}
unsigned int NzRenderBuffer::GetHeight() const
{
return m_height;
}
nzPixelFormat NzRenderBuffer::GetFormat() const
{
return m_pixelFormat;
}
unsigned int NzRenderBuffer::GetWidth() const
{
return m_width;
}
unsigned int NzRenderBuffer::GetOpenGLID() const
{
return m_id;
}
bool NzRenderBuffer::IsValid() const
{
return m_id != 0;
}
bool NzRenderBuffer::IsSupported()
{
return NzOpenGL::IsSupported(nzOpenGLExtension_FrameBufferObject);
}

View File

@ -7,7 +7,9 @@
#include <Nazara/Renderer/Context.hpp> #include <Nazara/Renderer/Context.hpp>
#include <Nazara/Renderer/OpenGL.hpp> #include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/Renderer.hpp> #include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/RenderBuffer.hpp>
#include <limits> #include <limits>
#include <memory>
#include <vector> #include <vector>
#include <Nazara/Renderer/Debug.hpp> #include <Nazara/Renderer/Debug.hpp>
@ -15,9 +17,10 @@ namespace
{ {
struct Attachment struct Attachment
{ {
GLuint buffer; NzRenderBufferRef buffer;
NzTextureRef texture; NzTextureRef texture;
nzAttachmentPoint attachmentPoint;
bool isBuffer; bool isBuffer;
bool isUsed = false; bool isUsed = false;
unsigned int height; unsigned int height;
@ -65,7 +68,7 @@ NzRenderTexture::~NzRenderTexture()
Destroy(); Destroy();
} }
bool NzRenderTexture::AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 index, nzPixelFormat format, unsigned int width, unsigned int height) bool NzRenderTexture::AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzRenderBuffer* buffer)
{ {
#if NAZARA_RENDERER_SAFE #if NAZARA_RENDERER_SAFE
if (!m_impl) if (!m_impl)
@ -86,11 +89,17 @@ bool NzRenderTexture::AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 in
{ {
if (index >= NzRenderer::GetMaxColorAttachments()) if (index >= NzRenderer::GetMaxColorAttachments())
{ {
NazaraError("Color index is over max color attachments (" + NzString::Number(index) + ", " + NzString::Number(NzRenderer::GetMaxColorAttachments()) + ")"); NazaraError("Color index is over max color attachments (" + NzString::Number(index) + " >= " + NzString::Number(NzRenderer::GetMaxColorAttachments()) + ")");
return false; return false;
} }
} }
if (!buffer || !buffer->IsValid())
{
NazaraError("Invalid render buffer");
return false;
}
unsigned int depthStencilIndex = attachmentIndex[nzAttachmentPoint_DepthStencil]; unsigned int depthStencilIndex = attachmentIndex[nzAttachmentPoint_DepthStencil];
if (m_impl->attachments.size() > depthStencilIndex && m_impl->attachments[depthStencilIndex].isUsed) if (m_impl->attachments.size() > depthStencilIndex && m_impl->attachments[depthStencilIndex].isUsed)
{ {
@ -106,28 +115,15 @@ bool NzRenderTexture::AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 in
} }
} }
nzAttachmentPoint targetAttachmentPoint = formatTypeToAttachment[NzPixelFormat::GetType(format)]; nzAttachmentPoint targetAttachmentPoint = formatTypeToAttachment[NzPixelFormat::GetType(buffer->GetFormat())];
if (targetAttachmentPoint != attachmentPoint && targetAttachmentPoint != nzAttachmentPoint_DepthStencil && if (targetAttachmentPoint != attachmentPoint && targetAttachmentPoint != nzAttachmentPoint_DepthStencil &&
attachmentPoint != nzAttachmentPoint_Depth && attachmentPoint != nzAttachmentPoint_Stencil) attachmentPoint != nzAttachmentPoint_Depth && attachmentPoint != nzAttachmentPoint_Stencil)
{ {
NazaraError("Pixel format type does not match attachment point type"); NazaraError("Pixel format type does not match attachment point type");
return false; return false;
} }
if (width == 0 || height == 0)
{
NazaraError("Invalid size");
return false;
}
#endif #endif
NzOpenGL::Format openglFormat;
if (!NzOpenGL::TranslateFormat(format, &openglFormat, NzOpenGL::FormatType_RenderBuffer))
{
NazaraError("Failed to translate pixel format into OpenGL format");
return false;
}
if (!Lock()) if (!Lock())
{ {
NazaraError("Failed to lock render texture"); NazaraError("Failed to lock render texture");
@ -137,37 +133,23 @@ bool NzRenderTexture::AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 in
// Détachement de l'attache précédente (Si il y a) // Détachement de l'attache précédente (Si il y a)
Detach(attachmentPoint, index); Detach(attachmentPoint, index);
GLuint renderBuffer = 0; glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, buffer->GetOpenGLID());
glGenRenderbuffers(1, &renderBuffer);
if (!renderBuffer)
{
NazaraError("Failed to create renderbuffer");
return false;
}
GLint previous;
glGetIntegerv(GL_RENDERBUFFER_BINDING, &previous);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, openglFormat.internalFormat, width, height);
if (previous != 0)
glBindRenderbuffer(GL_RENDERBUFFER, previous);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, renderBuffer);
Unlock(); Unlock();
unsigned int minSize = attachmentIndex[attachmentPoint]+index+1; unsigned int attachIndex = attachmentIndex[attachmentPoint]+index;
if (m_impl->attachments.size() < minSize) if (m_impl->attachments.size() <= attachIndex)
m_impl->attachments.resize(minSize); m_impl->attachments.resize(attachIndex+1);
Attachment& attachment = m_impl->attachments[minSize-1]; Attachment& attachment = m_impl->attachments[attachIndex];
attachment.buffer = renderBuffer; attachment.attachmentPoint = attachmentPoint;
attachment.buffer = buffer;
attachment.isBuffer = true; attachment.isBuffer = true;
attachment.isUsed = true; attachment.isUsed = true;
attachment.height = height; attachment.height = buffer->GetHeight();
attachment.width = width; attachment.width = buffer->GetWidth();
buffer->AddResourceListener(this, attachIndex);
m_impl->checked = false; m_impl->checked = false;
@ -181,6 +163,27 @@ bool NzRenderTexture::AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 in
return true; return true;
} }
bool NzRenderTexture::AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 index, nzPixelFormat format, unsigned int width, unsigned int height)
{
std::unique_ptr<NzRenderBuffer> renderBuffer(new NzRenderBuffer);
renderBuffer->SetPersistent(false);
if (!renderBuffer->Create(format, width, height))
{
NazaraError("Failed to create RenderBuffer");
return false;
}
if (!AttachBuffer(attachmentPoint, index, renderBuffer.get()))
{
NazaraError("Failed to attach buffer");
return false;
}
renderBuffer.release();
return true;
}
bool NzRenderTexture::AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzTexture* texture, unsigned int z) bool NzRenderTexture::AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzTexture* texture, unsigned int z)
{ {
#if NAZARA_RENDERER_SAFE #if NAZARA_RENDERER_SAFE
@ -202,7 +205,7 @@ bool NzRenderTexture::AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 i
{ {
if (index >= NzRenderer::GetMaxColorAttachments()) if (index >= NzRenderer::GetMaxColorAttachments())
{ {
NazaraError("Color index is over max color attachments (" + NzString::Number(index) + ", " + NzString::Number(NzRenderer::GetMaxColorAttachments()) + ")"); NazaraError("Color index is over max color attachments (" + NzString::Number(index) + " >= " + NzString::Number(NzRenderer::GetMaxColorAttachments()) + ")");
return false; return false;
} }
} }
@ -278,18 +281,19 @@ bool NzRenderTexture::AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 i
Unlock(); Unlock();
unsigned int minSize = attachmentIndex[attachmentPoint]+index+1; unsigned int attachIndex = attachmentIndex[attachmentPoint]+index;
if (m_impl->attachments.size() < minSize) if (m_impl->attachments.size() <= attachIndex)
m_impl->attachments.resize(minSize); m_impl->attachments.resize(attachIndex+1);
Attachment& attachment = m_impl->attachments[minSize-1]; Attachment& attachment = m_impl->attachments[attachIndex];
attachment.attachmentPoint = attachmentPoint;
attachment.isBuffer = false; attachment.isBuffer = false;
attachment.isUsed = true; attachment.isUsed = true;
attachment.height = texture->GetHeight(); attachment.height = texture->GetHeight();
attachment.texture = texture; attachment.texture = texture;
attachment.width = texture->GetWidth(); attachment.width = texture->GetWidth();
texture->AddResourceListener(this); texture->AddResourceListener(this, attachIndex);
m_impl->checked = false; m_impl->checked = false;
@ -377,7 +381,7 @@ void NzRenderTexture::Destroy()
if (attachment.isUsed) if (attachment.isUsed)
{ {
if (attachment.isBuffer) if (attachment.isBuffer)
glDeleteRenderbuffers(1, &attachment.buffer); // Les Renderbuffers sont partagés entre les contextes: Ne posera pas de problème attachment.buffer->RemoveResourceListener(this);
else else
attachment.texture->RemoveResourceListener(this); attachment.texture->RemoveResourceListener(this);
} }
@ -426,7 +430,9 @@ void NzRenderTexture::Detach(nzAttachmentPoint attachmentPoint, nzUInt8 index)
if (attachement.isBuffer) if (attachement.isBuffer)
{ {
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, 0); glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(1, &attachement.buffer);
attachement.buffer->RemoveResourceListener(this);
attachement.buffer = nullptr;
} }
else else
{ {
@ -437,7 +443,10 @@ void NzRenderTexture::Detach(nzAttachmentPoint attachmentPoint, nzUInt8 index)
attachement.texture->RemoveResourceListener(this); attachement.texture->RemoveResourceListener(this);
attachement.texture = nullptr; attachement.texture = nullptr;
}
if (attachement.attachmentPoint == nzAttachmentPoint_Color)
{
m_impl->drawBuffersUpdated = false; m_impl->drawBuffersUpdated = false;
m_impl->targetsUpdated = false; m_impl->targetsUpdated = false;
} }
@ -600,12 +609,12 @@ bool NzRenderTexture::Lock() const
return true; return true;
} }
void NzRenderTexture::SetColorTarget(nzUInt8 target) void NzRenderTexture::SetColorTarget(nzUInt8 target) const
{ {
SetColorTargets(&target, 1); SetColorTargets(&target, 1);
} }
void NzRenderTexture::SetColorTargets(const nzUInt8* targets, unsigned int targetCount) void NzRenderTexture::SetColorTargets(const nzUInt8* targets, unsigned int targetCount) const
{ {
#if NAZARA_RENDERER_SAFE #if NAZARA_RENDERER_SAFE
if (!m_impl) if (!m_impl)
@ -633,7 +642,7 @@ void NzRenderTexture::SetColorTargets(const nzUInt8* targets, unsigned int targe
m_impl->userDefinedTargets = true; m_impl->userDefinedTargets = true;
} }
void NzRenderTexture::SetColorTargets(const std::initializer_list<nzUInt8>& targets) void NzRenderTexture::SetColorTargets(const std::initializer_list<nzUInt8>& targets) const
{ {
#if NAZARA_RENDERER_SAFE #if NAZARA_RENDERER_SAFE
if (!m_impl) if (!m_impl)
@ -690,6 +699,25 @@ void NzRenderTexture::Unlock() const
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, lockedPrevious); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, lockedPrevious);
} }
unsigned int NzRenderTexture::GetOpenGLID() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return 0;
}
if (NzContext::GetCurrent() != m_impl->context)
{
NazaraError("RenderTexture cannot be used with this context");
return 0;
}
#endif
return m_impl->fbo;
}
bool NzRenderTexture::HasContext() const bool NzRenderTexture::HasContext() const
{ {
return false; return false;
@ -703,6 +731,12 @@ bool NzRenderTexture::IsSupported()
bool NzRenderTexture::Activate() const bool NzRenderTexture::Activate() const
{ {
#if NAZARA_RENDERER_SAFE #if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return false;
}
if (NzContext::GetCurrent() != m_impl->context) if (NzContext::GetCurrent() != m_impl->context)
{ {
NazaraError("RenderTexture cannot be used with this context"); NazaraError("RenderTexture cannot be used with this context");
@ -720,6 +754,12 @@ bool NzRenderTexture::Activate() const
void NzRenderTexture::Desactivate() const void NzRenderTexture::Desactivate() const
{ {
#if NAZARA_RENDERER_SAFE #if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return;
}
if (NzContext::GetCurrent() != m_impl->context) if (NzContext::GetCurrent() != m_impl->context)
{ {
NazaraError("RenderTexture cannot be used with this context"); NazaraError("RenderTexture cannot be used with this context");
@ -753,8 +793,13 @@ bool NzRenderTexture::OnResourceDestroy(const NzResource* resource, int index)
else // Sinon, c'est une texture else // Sinon, c'est une texture
{ {
// La ressource n'est plus, du coup nous mettons à jour // La ressource n'est plus, du coup nous mettons à jour
Attachment& attachement = m_impl->attachments[index]; Attachment& attachment = m_impl->attachments[index];
attachement.isUsed = false; if (attachment.isBuffer)
attachment.buffer = nullptr;
else
attachment.texture = nullptr;
attachment.isUsed = false;
m_impl->checked = false; m_impl->checked = false;
m_impl->targetsUpdated = false; m_impl->targetsUpdated = false;