|
|
@@ -1,5 +1,6 @@
|
|
|
#include "anki/gl/Fbo.h"
|
|
|
#include "anki/gl/Texture.h"
|
|
|
+#include "anki/gl/GlState.h"
|
|
|
#include "anki/util/Array.h"
|
|
|
|
|
|
namespace anki {
|
|
|
@@ -9,18 +10,56 @@ namespace anki {
|
|
|
thread_local const Fbo* Fbo::currentRead = nullptr;
|
|
|
thread_local const Fbo* Fbo::currentDraw = nullptr;
|
|
|
|
|
|
-static const Array<GLenum, 8> colorAttachments = {{
|
|
|
- GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
|
|
|
- GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5,
|
|
|
- GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7}};
|
|
|
+static const Array<GLenum, Fbo::MAX_COLOR_ATTACHMENTS + 1>
|
|
|
+ ATTACHMENT_TOKENS = {{
|
|
|
+ GL_DEPTH_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
|
|
|
+ GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3}};
|
|
|
|
|
|
//==============================================================================
|
|
|
-void Fbo::create()
|
|
|
+void Fbo::create(const std::initializer_list<Attachment>& attachments)
|
|
|
{
|
|
|
ANKI_ASSERT(!isCreated());
|
|
|
crateNonSharable();
|
|
|
+
|
|
|
+ // Create name
|
|
|
glGenFramebuffers(1, &glId);
|
|
|
ANKI_ASSERT(glId != 0);
|
|
|
+
|
|
|
+ // Bind
|
|
|
+ bind(false, ALL_TARGETS);
|
|
|
+
|
|
|
+ // Attach textures
|
|
|
+ colorAttachmentsCount = 0;
|
|
|
+ for(const Attachment& attachment : attachments)
|
|
|
+ {
|
|
|
+ // Set some values
|
|
|
+ const GLenum max = GL_COLOR_ATTACHMENT0 + MAX_COLOR_ATTACHMENTS;
|
|
|
+ if(attachment.attachmentPoint >= GL_COLOR_ATTACHMENT0
|
|
|
+ && attachment.attachmentPoint < max)
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(colorAttachmentsCount ==
|
|
|
+ attachment.attachmentPoint - GL_COLOR_ATTACHMENT0);
|
|
|
+
|
|
|
+ ++colorAttachmentsCount;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(
|
|
|
+ attachment.attachmentPoint == GL_DEPTH_STENCIL_ATTACHMENT
|
|
|
+ || attachment.attachmentPoint == GL_DEPTH_ATTACHMENT
|
|
|
+ || attachment.attachmentPoint == GL_STENCIL_ATTACHMENT);
|
|
|
+ }
|
|
|
+
|
|
|
+ attachTextureInternal(attachment.attachmentPoint, *attachment.texture,
|
|
|
+ attachment.layer);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check completeness
|
|
|
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
|
+ if(status != GL_FRAMEBUFFER_COMPLETE)
|
|
|
+ {
|
|
|
+ throw ANKI_EXCEPTION("FBO is incomplete");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
|
@@ -29,157 +68,81 @@ void Fbo::destroy()
|
|
|
checkNonSharable();
|
|
|
if(isCreated())
|
|
|
{
|
|
|
- bindDefault();
|
|
|
+ bindDefault(false, ALL_TARGETS);
|
|
|
glDeleteFramebuffers(1, &glId);
|
|
|
glId = 0;
|
|
|
+ colorAttachmentsCount = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
|
-void Fbo::bind(const FboTarget target, Bool noReadbacks) const
|
|
|
+void Fbo::bindInternal(const Fbo* fbo, Bool invalidate, const Target target)
|
|
|
{
|
|
|
- ANKI_ASSERT(isCreated());
|
|
|
- checkNonSharable();
|
|
|
+ GLenum glTarget = GL_FRAMEBUFFER;
|
|
|
+ GLuint name = fbo != nullptr ? fbo->glId : 0;
|
|
|
|
|
|
- if(target == FT_ALL)
|
|
|
+ // Bind
|
|
|
+ if(target == ALL_TARGETS)
|
|
|
{
|
|
|
- if(currentDraw != this || currentRead != this)
|
|
|
+ if(currentDraw != fbo || currentRead != fbo)
|
|
|
{
|
|
|
- glBindFramebuffer(GL_FRAMEBUFFER, glId);
|
|
|
- currentDraw = currentRead = this;
|
|
|
+ glBindFramebuffer(glTarget, name);
|
|
|
+ currentDraw = currentRead = fbo;
|
|
|
}
|
|
|
-
|
|
|
-#if ANKI_GL == ANKI_GL_ES
|
|
|
- if(noReadbacks)
|
|
|
- {
|
|
|
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
|
|
|
- | GL_STENCIL_BUFFER_BIT);
|
|
|
- }
|
|
|
-#endif
|
|
|
}
|
|
|
- else if(target == FT_DRAW)
|
|
|
+ else if(target == DRAW_TARGET)
|
|
|
{
|
|
|
- if(currentDraw != this)
|
|
|
+ glTarget = GL_DRAW_FRAMEBUFFER;
|
|
|
+ if(currentDraw != fbo)
|
|
|
{
|
|
|
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, glId);
|
|
|
- currentDraw = this;
|
|
|
+ glBindFramebuffer(glTarget, name);
|
|
|
+ currentDraw = fbo;
|
|
|
}
|
|
|
-
|
|
|
-#if ANKI_GL == ANKI_GL_ES
|
|
|
- if(noReadbacks)
|
|
|
- {
|
|
|
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
|
|
|
- | GL_STENCIL_BUFFER_BIT);
|
|
|
- }
|
|
|
-#endif
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- ANKI_ASSERT(target == FT_READ);
|
|
|
- if(currentRead != this)
|
|
|
- {
|
|
|
- glBindFramebuffer(GL_READ_FRAMEBUFFER, glId);
|
|
|
- currentRead = this;
|
|
|
- }
|
|
|
-
|
|
|
- ANKI_ASSERT(noReadbacks == false && "Doesn't make sense");
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//==============================================================================
|
|
|
-void Fbo::bindDefault(const FboTarget target, Bool noReadbacks)
|
|
|
-{
|
|
|
- if(target == FT_ALL)
|
|
|
- {
|
|
|
- if(currentDraw != nullptr || currentRead != nullptr)
|
|
|
- {
|
|
|
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
- currentDraw = currentRead = nullptr;
|
|
|
- }
|
|
|
+ ANKI_ASSERT(target == READ_TARGET);
|
|
|
|
|
|
-#if ANKI_GL == ANKI_GL_ES
|
|
|
- if(noReadbacks)
|
|
|
+ glTarget = GL_READ_FRAMEBUFFER;
|
|
|
+ if(currentRead != fbo)
|
|
|
{
|
|
|
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
|
|
|
- | GL_STENCIL_BUFFER_BIT);
|
|
|
+ glBindFramebuffer(glTarget, name);
|
|
|
+ currentRead = fbo;
|
|
|
}
|
|
|
-#endif
|
|
|
}
|
|
|
- else if(target == FT_DRAW)
|
|
|
+
|
|
|
+ // Set the drawbuffers
|
|
|
+ if(name != 0)
|
|
|
{
|
|
|
- if(currentDraw != nullptr)
|
|
|
- {
|
|
|
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
- currentDraw = nullptr;
|
|
|
- }
|
|
|
+ glDrawBuffers(fbo->colorAttachmentsCount,
|
|
|
+ &ATTACHMENT_TOKENS[1]);
|
|
|
|
|
|
-#if ANKI_GL == ANKI_GL_ES
|
|
|
- if(noReadbacks)
|
|
|
+ // Invalidate
|
|
|
+ if(invalidate)
|
|
|
{
|
|
|
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
|
|
|
+ glInvalidateFramebuffer(
|
|
|
+ glTarget, ATTACHMENT_TOKENS.size(), &ATTACHMENT_TOKENS[0]);
|
|
|
+
|
|
|
+ if(name == 0
|
|
|
+ && GlStateCommonSingleton::get().getGpu() ==
|
|
|
+ GlStateCommon::GPU_ARM)
|
|
|
+ {
|
|
|
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
|
|
|
+ | GL_STENCIL_BUFFER_BIT);
|
|
|
+ }
|
|
|
+
|
|
|
+#if ANKI_DEBUG == 1
|
|
|
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
|
|
|
| GL_STENCIL_BUFFER_BIT);
|
|
|
- }
|
|
|
#endif
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- ANKI_ASSERT(target == FT_READ);
|
|
|
- if(currentRead != nullptr)
|
|
|
- {
|
|
|
- glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
|
|
- currentRead = nullptr;
|
|
|
}
|
|
|
-
|
|
|
- ANKI_ASSERT(noReadbacks == false && "Doesn't make sense");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
|
-Bool Fbo::isComplete() const
|
|
|
+void Fbo::attachTextureInternal(GLenum attachment, const Texture& tex,
|
|
|
+ const I32 layer)
|
|
|
{
|
|
|
- bind();
|
|
|
-
|
|
|
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
|
- return status == GL_FRAMEBUFFER_COMPLETE;
|
|
|
-}
|
|
|
-
|
|
|
-//==============================================================================
|
|
|
-void Fbo::setColorAttachments(const std::initializer_list<const Texture*>&
|
|
|
- textures)
|
|
|
-{
|
|
|
- ANKI_ASSERT(textures.size() > 0);
|
|
|
-
|
|
|
- bind();
|
|
|
-
|
|
|
- // Set number of color attachments
|
|
|
- glDrawBuffers(textures.size(), &colorAttachments[0]);
|
|
|
-
|
|
|
- // Set attachments
|
|
|
- U i = 0;
|
|
|
- for(const Texture* tex : textures)
|
|
|
- {
|
|
|
-#if ANKI_GL == ANKI_GL_DESKTOP
|
|
|
- ANKI_ASSERT(tex->getTarget() == GL_TEXTURE_2D
|
|
|
- || tex->getTarget() == GL_TEXTURE_2D_MULTISAMPLE);
|
|
|
-#else
|
|
|
- ANKI_ASSERT(tex->getTarget() == GL_TEXTURE_2D);
|
|
|
-#endif
|
|
|
-
|
|
|
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
|
|
|
- tex->getTarget(), tex->getGlId(), 0);
|
|
|
-
|
|
|
- attachments[attachmentsCount++] = GL_COLOR_ATTACHMENT0 + i;
|
|
|
-
|
|
|
- ++i;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//==============================================================================
|
|
|
-void Fbo::setOtherAttachment(GLenum attachment, const Texture& tex,
|
|
|
- const I32 layer, const I32 face)
|
|
|
-{
|
|
|
- bind();
|
|
|
-
|
|
|
const GLenum target = GL_FRAMEBUFFER;
|
|
|
switch(tex.getTarget())
|
|
|
{
|
|
|
@@ -187,18 +150,18 @@ void Fbo::setOtherAttachment(GLenum attachment, const Texture& tex,
|
|
|
#if ANKI_GL == ANKI_GL_DESKTOP
|
|
|
case GL_TEXTURE_2D_MULTISAMPLE:
|
|
|
#endif
|
|
|
- ANKI_ASSERT(layer < 0 && face < 0);
|
|
|
+ ANKI_ASSERT(layer < 0);
|
|
|
glFramebufferTexture2D(target, attachment,
|
|
|
tex.getTarget(), tex.getGlId(), 0);
|
|
|
break;
|
|
|
case GL_TEXTURE_CUBE_MAP:
|
|
|
- ANKI_ASSERT(layer < 0 && face >= 0);
|
|
|
+ ANKI_ASSERT(layer >= 0 && layer < 6);
|
|
|
glFramebufferTexture2D(target, attachment,
|
|
|
- GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, tex.getGlId(), 0);
|
|
|
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, tex.getGlId(), 0);
|
|
|
break;
|
|
|
case GL_TEXTURE_2D_ARRAY:
|
|
|
case GL_TEXTURE_3D:
|
|
|
- ANKI_ASSERT(layer >= 0 && face < 0);
|
|
|
+ ANKI_ASSERT(layer >= 0);
|
|
|
ANKI_ASSERT((GLuint)layer < tex.getDepth());
|
|
|
glFramebufferTextureLayer(target, attachment,
|
|
|
tex.getGlId(), 0, layer);
|
|
|
@@ -207,8 +170,6 @@ void Fbo::setOtherAttachment(GLenum attachment, const Texture& tex,
|
|
|
ANKI_ASSERT(0);
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
- attachments[attachmentsCount++] = attachment;
|
|
|
}
|
|
|
|
|
|
} // end namespace anki
|