Skip to content

Commit

Permalink
libgui|GL: Resolving multisampled framebuffer contents
Browse files Browse the repository at this point in the history
GLTextureFramebuffer now has methods for controlling multisampling.
The idea is to render normally into a multisampled FBO, then resolve
samples, and finally use the output textures for further read/write
operations until the next frame.
  • Loading branch information
skyjake committed Oct 7, 2016
1 parent db3ae43 commit a6d5a62
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 98 deletions.
2 changes: 1 addition & 1 deletion doomsday/sdk/libgui/include/de/graphics/glframebuffer.h
Expand Up @@ -263,7 +263,7 @@ class LIBGUI_PUBLIC GLFramebuffer : public Asset
* @param attachment Which attachment.
* @return
*/
GLTexture *attachedTexture(Flags const &attachment) const;
virtual GLTexture *attachedTexture(Flags const &attachment) const;

/**
* Replaces a currently attached texture with another.
Expand Down
12 changes: 12 additions & 0 deletions doomsday/sdk/libgui/include/de/graphics/gltextureframebuffer.h
Expand Up @@ -54,6 +54,8 @@ class LIBGUI_PUBLIC GLTextureFramebuffer : public GLFramebuffer
Size const &initialSize = Size(),
int sampleCount = 0 /*default*/);

bool areTexturesReady() const;

void glInit();
void glDeinit();

Expand All @@ -68,11 +70,21 @@ class LIBGUI_PUBLIC GLTextureFramebuffer : public GLFramebuffer
*/
void resize(Size const &newSize);

/**
* Updates the color and depth textures by blitting from the multisampled
* renderbuffers.
*/
void resolveSamples();

GLFramebuffer &resolvedFramebuffer();

Size size() const;
GLTexture &colorTexture() const;
GLTexture &depthStencilTexture() const;
int sampleCount() const;

GLTexture *attachedTexture(Flags const &attachment) const override;

public:
/**
* Sets the default sample count for all frame buffers.
Expand Down
168 changes: 71 additions & 97 deletions doomsday/sdk/libgui/src/graphics/gltextureframebuffer.cpp
Expand Up @@ -37,6 +37,7 @@ DENG2_PIMPL(GLTextureFramebuffer)
GLTexture color;
GLTexture depthStencil;
//GLFramebuffer framebuf;
GLFramebuffer resolvedFbo;
Asset texFboState;

/*Drawable bufSwap;
Expand Down Expand Up @@ -122,31 +123,14 @@ DENG2_PIMPL(GLTextureFramebuffer)
color.clear();
depthStencil.clear();
self.deinit();
resolvedFbo.deinit();
//multisampleTarget.configure();

texFboState.setState(NotReady);
}

void reconfigure()
void configureTexturesWithFallback(GLFramebuffer &fbo)
{
if (!texFboState.isReady() || size == Size()) return;

LOGDEV_GL_VERBOSE("Reconfiguring framebuffer: %s ms:%i")
<< size.asText() << sampleCount();

// Configure textures for the framebuffer.
color.setUndefinedImage(size, colorFormat);
color.setWrap(gl::ClampToEdge, gl::ClampToEdge);
color.setFilter(gl::Nearest, gl::Linear, gl::MipNone);

DENG2_ASSERT(color.isReady());

depthStencil.setDepthStencilContent(size);
depthStencil.setWrap(gl::ClampToEdge, gl::ClampToEdge);
depthStencil.setFilter(gl::Nearest, gl::Nearest, gl::MipNone);

DENG2_ASSERT(depthStencil.isReady());

// Try a couple of different ways to set up the FBO.
for (int attempt = 0; ; ++attempt)
{
Expand All @@ -160,34 +144,34 @@ DENG2_PIMPL(GLTextureFramebuffer)
// Allows shaders to access contents of the entire framebuffer.
failMsg = "Texture-based framebuffer failed: %s\n"
"Trying again without depth/stencil texture";
self.configure(&color, &depthStencil);
fbo.configure(&color, &depthStencil);
break;

case 1:
failMsg = "Color texture with unified depth/stencil renderbuffer failed: %s\n"
"Trying again without stencil";
self.configure(GLFramebuffer::Color, color, GLFramebuffer::DepthStencil);
fbo.configure(GLFramebuffer::Color, color, GLFramebuffer::DepthStencil);
LOG_GL_WARNING("Renderer feature unavailable: lensflare depth");
break;

case 2:
failMsg = "Color texture with depth renderbuffer failed: %s\n"
"Trying again without texture buffers";
self.configure(GLFramebuffer::Color, color, GLFramebuffer::Depth);
fbo.configure(GLFramebuffer::Color, color, GLFramebuffer::Depth);
LOG_GL_WARNING("Renderer features unavailable: sky mask, lensflare depth");
break;

case 3:
failMsg = "Renderbuffer-based framebuffer failed: %s\n"
"Trying again without stencil";
self.configure(size, GLFramebuffer::ColorDepthStencil);
fbo.configure(size, GLFramebuffer::ColorDepthStencil);
LOG_GL_WARNING("Renderer features unavailable: postfx, lensflare depth");
break;

case 4:
// Final fallback: simple FBO with just color+depth renderbuffers.
// No postfx, no access from shaders, no sky mask.
self.configure(size, GLFramebuffer::ColorDepth);
fbo.configure(size, GLFramebuffer::ColorDepth);
LOG_GL_WARNING("Renderer features unavailable: postfx, sky mask, lensflare depth");
break;

Expand All @@ -202,6 +186,37 @@ DENG2_PIMPL(GLTextureFramebuffer)
LOG_GL_NOTE(failMsg) << er.asText();
}
}
}

void reconfigure()
{
if (!texFboState.isReady() || size == Size()) return;

LOGDEV_GL_VERBOSE("Reconfiguring framebuffer: %s ms:%i")
<< size.asText() << sampleCount();

// Configure textures for the framebuffer.
color.setUndefinedImage(size, colorFormat);
color.setWrap(gl::ClampToEdge, gl::ClampToEdge);
color.setFilter(gl::Nearest, gl::Linear, gl::MipNone);

DENG2_ASSERT(color.isReady());

depthStencil.setDepthStencilContent(size);
depthStencil.setWrap(gl::ClampToEdge, gl::ClampToEdge);
depthStencil.setFilter(gl::Nearest, gl::Nearest, gl::MipNone);

DENG2_ASSERT(depthStencil.isReady());

if (isMultisampled())
{
self.configure(size, ColorDepthStencil, sampleCount());
configureTexturesWithFallback(resolvedFbo);
}
else
{
configureTexturesWithFallback(self);
}

self.clear(GLFramebuffer::ColorDepthStencil);

Expand Down Expand Up @@ -239,79 +254,6 @@ DENG2_PIMPL(GLTextureFramebuffer)
reconfigure();
}
}

/* void drawSwap()
{
if (isMultisampled())
{
target.updateFromProxy();
}
bufSwap.draw();
}*/

/*void swapBuffers(Canvas &canvas, gl::SwapBufferMode swapMode)
{
GLTarget defaultTarget;
GLState::push()
.setTarget(defaultTarget)
.setViewport(Rectangleui::fromSize(size))
.apply();
if (!color.isReady())
{
// If the frame buffer hasn't been configured yet, just clear the canvas.
glClear(GL_COLOR_BUFFER_BIT);
canvas.QGLWidget::swapBuffers();
GLState::pop().apply();
return;
}
switch (swapMode)
{
case gl::SwapMonoBuffer:
if (GLInfo::extensions().EXT_framebuffer_blit)
{
if (isMultisampled())
{
multisampleTarget.blit(defaultTarget); // resolve multisampling to system backbuffer
}
else
{
target.blit(defaultTarget); // copy to system backbuffer
}
}
else
{
// Fallback: draw the back buffer texture to the main framebuffer.
drawSwap();
}
canvas.QGLWidget::swapBuffers();
break;
case gl::SwapWithAlpha:
drawSwap();
break;
case gl::SwapStereoLeftBuffer:
glDrawBuffer(GL_BACK_LEFT);
drawSwap();
glDrawBuffer(GL_BACK);
break;
case gl::SwapStereoRightBuffer:
glDrawBuffer(GL_BACK_RIGHT);
drawSwap();
glDrawBuffer(GL_BACK);
break;
case gl::SwapStereoBuffers:
canvas.QGLWidget::swapBuffers();
break;
}
GLState::pop().apply();
}*/
};

GLTextureFramebuffer::GLTextureFramebuffer(Image::Format const &colorFormat, Size const &initialSize, int sampleCount)
Expand All @@ -322,6 +264,11 @@ GLTextureFramebuffer::GLTextureFramebuffer(Image::Format const &colorFormat, Siz
d->_samples = sampleCount;
}

bool GLTextureFramebuffer::areTexturesReady() const
{
return d->texFboState.isReady();
}

void GLTextureFramebuffer::glInit()
{
if (d->texFboState.isReady()) return;
Expand Down Expand Up @@ -404,6 +351,24 @@ void GLTextureFramebuffer::resize(Size const &newSize)
d->resize(newSize);
}

void GLTextureFramebuffer::resolveSamples()
{
if (d->isMultisampled())
{
// Copy the framebuffer contents to the textures (that have no multisampling).
blit(d->resolvedFbo, ColorDepthStencil);
}
}

GLFramebuffer &GLTextureFramebuffer::resolvedFramebuffer()
{
if (d->isMultisampled())
{
return d->resolvedFbo;
}
return *this;
}

GLTextureFramebuffer::Size GLTextureFramebuffer::size() const
{
return d->size;
Expand All @@ -424,6 +389,15 @@ int GLTextureFramebuffer::sampleCount() const
return d->sampleCount();
}

GLTexture *GLTextureFramebuffer::attachedTexture(Flags const &attachment) const
{
if (d->isMultisampled())
{
return d->resolvedFbo.attachedTexture(attachment);
}
return GLFramebuffer::attachedTexture(attachment);
}

/*void GLTextureFramebuffer::clear(GLFramebuffer::Flags const &attachments)
{
d->framebuf.clear(attachments);
Expand Down

0 comments on commit a6d5a62

Please sign in to comment.