Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix MSAA FBO and fix MSAA MRT FBO #3601

Merged
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
147 changes: 95 additions & 52 deletions libs/openFrameworks/gl/ofFbo.cpp
Expand Up @@ -221,7 +221,6 @@ fbo(0),
fboTextures(0),
depthBuffer(0),
stencilBuffer(0),
savedFramebuffer(0),
dirty(false),
defaultTextureIndex(0),
bIsAllocated(false)
Expand Down Expand Up @@ -274,8 +273,6 @@ ofFbo::ofFbo(const ofFbo & mom){
stencilBuffer = mom.stencilBuffer;
retainRB(stencilBuffer);

savedFramebuffer = mom.savedFramebuffer;

colorBuffers = mom.colorBuffers;
for(int i=0;i<(int)colorBuffers.size();i++){
retainRB(colorBuffers[i]);
Expand Down Expand Up @@ -306,8 +303,6 @@ ofFbo & ofFbo::operator=(const ofFbo & mom){
stencilBuffer = mom.stencilBuffer;
retainRB(stencilBuffer);

savedFramebuffer = mom.savedFramebuffer;

colorBuffers = mom.colorBuffers;
for(int i=0;i<(int)colorBuffers.size();i++){
retainRB(colorBuffers[i]);
Expand Down Expand Up @@ -552,7 +547,8 @@ void ofFbo::allocate(Settings _settings) {
ofLogWarning("ofFbo") << "allocate(): no color buffers specified for frame buffer object " << fbo;
}
settings.internalformat = _settings.internalformat;


dirty.resize(_settings.colorFormats.size(), true); // we start with all color buffers dirty.

// if textures are attached to a different fbo (e.g. if using MSAA) check it's status
if(fbo != fboTextures) {
Expand All @@ -577,31 +573,51 @@ bool ofFbo::isAllocated() const {
return bIsAllocated;
}

//----------------------------------------------------------

GLuint ofFbo::createAndAttachRenderbuffer(GLenum internalFormat, GLenum attachmentPoint) {
GLuint buffer;
glGenRenderbuffers(1, &buffer);
glBindRenderbuffer(GL_RENDERBUFFER, buffer);
#ifndef TARGET_OPENGLES
if(settings.numSamples==0) glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, settings.width, settings.height);
else glRenderbufferStorageMultisample(GL_RENDERBUFFER, settings.numSamples, internalFormat, settings.width, settings.height);
if (settings.numSamples==0) {
glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, settings.width, settings.height);
} else {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, settings.numSamples, internalFormat, settings.width, settings.height);
}
#else
glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, ofNextPow2(settings.width), ofNextPow2(settings.height));
#endif
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentPoint, GL_RENDERBUFFER, buffer);
return buffer;
}

//----------------------------------------------------------

void ofFbo::createAndAttachTexture(GLenum internalFormat, GLenum attachmentPoint) {

ofTextureData texData;

texData.textureTarget = settings.textureTarget;
texData.width = settings.width;
texData.height = settings.height;
texData.glTypeInternal = internalFormat;
texData.bFlipTexture = false;
texData.wrapModeHorizontal = settings.wrapModeHorizontal;
texData.wrapModeVertical = settings.wrapModeVertical;
texData.magFilter = settings.maxFilter;
texData.minFilter = settings.minFilter;

ofTexture tex;
tex.allocate(settings.width, settings.height, internalFormat, settings.textureTarget == GL_TEXTURE_2D ? false : true);
tex.texData.bFlipTexture = false;
tex.setTextureWrap(settings.wrapModeHorizontal, settings.wrapModeVertical);
tex.setTextureMinMagFilter(settings.minFilter, settings.maxFilter);
tex.allocate(texData);

attachTexture(tex, internalFormat, attachmentPoint);
dirty.push_back(true);
activeDrawBuffers.push_back(GL_COLOR_ATTACHMENT0 + attachmentPoint);
}

//----------------------------------------------------------

void ofFbo::attachTexture(ofTexture & tex, GLenum internalFormat, GLenum attachmentPoint) {
// bind fbo for textures (if using MSAA this is the newly created fbo, otherwise its the same fbo as before)
GLint temp;
Expand Down Expand Up @@ -629,6 +645,9 @@ void ofFbo::attachTexture(ofTexture & tex, GLenum internalFormat, GLenum attachm
glBindFramebuffer(GL_FRAMEBUFFER, temp);

}

//----------------------------------------------------------

void ofFbo::createAndAttachDepthStencilTexture(GLenum target, GLint internalformat, GLenum attachment, GLenum transferFormat, GLenum transferType){


Expand All @@ -644,6 +663,8 @@ void ofFbo::createAndAttachDepthStencilTexture(GLenum target, GLint internalform
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, target, depthBufferTex.texData.textureID, 0);
}

//----------------------------------------------------------

void ofFbo::createAndAttachDepthStencilTexture(GLenum target, GLint internalformat, GLenum attachment){

// allocate depthBufferTex as depth buffer;
Expand All @@ -658,91 +679,116 @@ void ofFbo::createAndAttachDepthStencilTexture(GLenum target, GLint internalform
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, target, depthBufferTex.texData.textureID, 0);
}

//----------------------------------------------------------

void ofFbo::begin(bool setupScreen) const{
if(ofGetGLRenderer()){
ofGetGLRenderer()->bind(*this,setupScreen);
ofGetGLRenderer()->begin(*this,setupScreen);
}
}

//----------------------------------------------------------

void ofFbo::end() const{
if(ofGetGLRenderer()){
ofGetGLRenderer()->unbind(*this);
ofGetGLRenderer()->end(*this);
}
}

//----------------------------------------------------------

void ofFbo::bind() const{
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &savedFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);

ofGetGLRenderer()->bind(*this);

}

//----------------------------------------------------------

void ofFbo::unbind() const{
glBindFramebuffer(GL_FRAMEBUFFER, savedFramebuffer);
savedFramebuffer = 0;

ofGetGLRenderer()->unbind(*this);

if (fbo != fboTextures){
// ---------| if fbo != fboTextures, we are dealing with an MSAA enabled FBO.
// all currently active draw buffers need to be flagged dirty
// if a draw buffer has been activated and then de-activated, it has been
// flagged dirty at activation, so we can be sure all buffers which have
// been rendered to are flagged dirty.
int numBuffersToFlag = min(dirty.size(), activeDrawBuffers.size());
for(int i=0; i < numBuffersToFlag; i++){
dirty[i] = true;
}
}
}

//----------------------------------------------------------

int ofFbo::getNumTextures() const {
return textures.size();
}

//TODO: Should we also check against card's max attachments or can we assume that's taken care of in texture setup? Still need to figure out MSAA in conjunction with MRT
//----------------------------------------------------------

void ofFbo::setActiveDrawBuffer(int i){
if(!bIsAllocated) return;
#ifndef TARGET_OPENGLES
if (i < getNumTextures()){
GLenum e = GL_COLOR_ATTACHMENT0 + i;
glDrawBuffer(e);
}else{
ofLogWarning("ofFbo") << "setActiveDrawBuffer(): fbo " << fbo << " couldn't set texture " << i << ", only " << getNumTextures() << "allocated";
}
vector<int> activebuffers(1, i);
setActiveDrawBuffers(activebuffers);
#endif
}

//----------------------------------------------------------

void ofFbo::setActiveDrawBuffers(const vector<int>& ids){
if(!bIsAllocated) return;
#ifndef TARGET_OPENGLES
vector<GLenum> attachments;
int numBuffers = activeDrawBuffers.size();
activeDrawBuffers.clear();
activeDrawBuffers.resize(numBuffers, GL_NONE); // we initialise the vector with GL_NONE, so a buffer will not be written to unless activated.
for(int i=0; i < (int)ids.size(); i++){
int id = ids[i];
if (id < getNumTextures()){
GLenum e = GL_COLOR_ATTACHMENT0 + id;
attachments.push_back(e);
activeDrawBuffers[id] = e; // activate requested buffers
dirty[id] = true; // dirty activated draw buffers.
}else{
ofLogWarning("ofFbo") << "setActiveDrawBuffers(): fbo " << fbo << " couldn't set texture " << i << ", only " << getNumTextures() << "allocated";
}
}
glDrawBuffers(attachments.size(),&attachments[0]);
glDrawBuffers(activeDrawBuffers.size(),&activeDrawBuffers[0]);
#endif
}

//----------------------------------------------------------

void ofFbo::activateAllDrawBuffers(){
if(!bIsAllocated) return;
#ifndef TARGET_OPENGLES
vector<GLenum> attachments;
vector<int> activeBuffers(getNumTextures(),0);
for(int i=0; i < getNumTextures(); i++){
if (i < getNumTextures()){
GLenum e = GL_COLOR_ATTACHMENT0 + i;
attachments.push_back(e);
}else{
ofLogWarning("ofFbo") << "activateAllDrawBuffers(): fbo " << fbo << " couldn't set texture " << i << ", only " << getNumTextures() << "allocated";
}
activeBuffers[i] = i;
}
glDrawBuffers(attachments.size(),&attachments[0]);
setActiveDrawBuffers(activeBuffers);
#endif
}

//----------------------------------------------------------

void ofFbo::setDefaultTextureIndex(int defaultTexture)
{
defaultTextureIndex = defaultTexture;
}

//----------------------------------------------------------

int ofFbo::getDefaultTextureIndex() const
{
return defaultTextureIndex;
}

//----------------------------------------------------------

ofTexture& ofFbo::getTextureReference(){
return getTexture();
}
Expand Down Expand Up @@ -834,36 +880,33 @@ void ofFbo::readToPixels(ofFloatPixels & pixels, int attachmentPoint) const{
void ofFbo::updateTexture(int attachmentPoint) {
if(!bIsAllocated) return;
#ifndef TARGET_OPENGLES
if(fbo != fboTextures && dirty) {
glGetIntegerv( GL_FRAMEBUFFER_BINDING, &savedFramebuffer );
if(fbo != fboTextures && dirty[attachmentPoint]) {

// ---------| invariant: if fbo != fboTextures, we are dealing with an MSAA enabled FBO.

if (!ofIsGLProgrammableRenderer()){
// save current drawbuffer
glPushAttrib(GL_COLOR_BUFFER_BIT);
}
// save current readbuffer
GLint readBuffer;
glGetIntegerv(GL_READ_BUFFER, &readBuffer);

glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboTextures);
glDrawBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint);
bind();
glReadBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboTextures);
glDrawBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint);
glBlitFramebuffer(0, 0, settings.width, settings.height, 0, 0, settings.width, settings.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);

glBindFramebuffer(GL_READ_FRAMEBUFFER, savedFramebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, savedFramebuffer);
glBindFramebuffer( GL_FRAMEBUFFER, savedFramebuffer );

// restore readbuffer
glReadBuffer(readBuffer);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); // reset to defaults
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
unbind();

glReadBuffer(GL_BACK);

if(!ofIsGLProgrammableRenderer()){
// restore drawbuffer
// restore current drawbuffer
glPopAttrib();
}

dirty = false;
dirty[attachmentPoint] = false;

}
#endif
Expand Down
10 changes: 5 additions & 5 deletions libs/openFrameworks/gl/ofFbo.h
@@ -1,6 +1,7 @@
#pragma once

#include "ofTexture.h"
#include <stack>

class ofFbo : public ofBaseDraws, public ofBaseHasTexture {
public:
Expand Down Expand Up @@ -109,18 +110,17 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture {
GLuint depthBuffer;
GLuint stencilBuffer;

mutable GLint savedFramebuffer; // save bound framebuffer before switching

vector<GLuint> colorBuffers; // only used if using MSAA...maybe...what about MRT?
vector<ofTexture> textures;
vector<GLuint> colorBuffers;
vector<ofTexture> textures;

ofTexture depthBufferTex;

static int _maxColorAttachments;
static int _maxDrawBuffers;
static int _maxSamples;

mutable bool dirty;
vector<GLenum> activeDrawBuffers; ///< table of currently active color draw buffers, allocate() defaults it to size(textures), with GL_COLOR_ATTACHMENT0..n as members, in order of allocation
mutable vector<bool> dirty;

int defaultTextureIndex; //used for getTextureReference
bool bIsAllocated;
Expand Down