From b94d3423de1e61f46c22b421f4b293d2d094b89f Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 3 Dec 2016 18:03:12 +0200 Subject: [PATCH] Add a RenderTarget class to manage and annotate FBOs I want to have deferred lighting support at some point, and it requires multiple outputs from the geometry rasterization stage. There needs to be some way to annotate which buffer holds which information. --- source/pipeline.cpp | 45 ++-------- source/pipeline.h | 21 +---- source/rendertarget.cpp | 183 ++++++++++++++++++++++++++++++++++++++++ source/rendertarget.h | 85 +++++++++++++++++++ 4 files changed, 279 insertions(+), 55 deletions(-) create mode 100644 source/rendertarget.cpp create mode 100644 source/rendertarget.h diff --git a/source/pipeline.cpp b/source/pipeline.cpp index e4688257..a5d7436a 100644 --- a/source/pipeline.cpp +++ b/source/pipeline.cpp @@ -183,7 +183,7 @@ void Pipeline::render(Renderer &renderer, const Tag &tag) const if(target[0]) { - Framebuffer &fbo = (samples ? target_ms->fbo : target[0]->fbo); + Framebuffer &fbo = (samples ? target_ms : target[0])->get_framebuffer(); fbo.bind(); fbo.clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT); } @@ -218,16 +218,18 @@ void Pipeline::render(Renderer &renderer, const Tag &tag) const Blend::unbind(); if(samples) - target[0]->fbo.blit_from(target_ms->fbo, COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT, false); + target[0]->blit_from(*target_ms); for(unsigned i=0; ifbo.bind(); + target[1-j]->get_framebuffer().bind(); else out_fbo->bind(); - postproc[i]->render(renderer, target[j]->color, target[j]->depth); + const Texture2D &color = target[j]->get_target_texture(RENDER_COLOR); + const Texture2D &depth = target[j]->get_target_texture(RENDER_DEPTH); + postproc[i]->render(renderer, color, depth); } } @@ -250,7 +252,8 @@ void Pipeline::create_targets(unsigned recreate) target_ms = 0; } - PixelFormat fmt = (hdr ? RGB16F : RGB); + PixelFormat color_pf = (hdr ? RGB16F : RGB); + RenderTargetFormat fmt = (RENDER_COLOR,color_pf, RENDER_DEPTH); if(!postproc.empty() || samples) { if(!target[0]) @@ -260,7 +263,7 @@ void Pipeline::create_targets(unsigned recreate) } if(!target_ms && samples) - target_ms = new MultisampleTarget(width, height, samples, fmt); + target_ms = new RenderTarget(width, height, samples, fmt); } @@ -298,35 +301,5 @@ Pipeline::Slot::Slot(const Renderable *r): renderable(r) { } - -Pipeline::RenderTarget::RenderTarget(unsigned w, unsigned h, PixelFormat f) -{ - color.set_min_filter(NEAREST); - color.set_mag_filter(NEAREST); - color.set_wrap(CLAMP_TO_EDGE); - color.storage(f, w, h); - fbo.attach(COLOR_ATTACHMENT0, color, 0); - - depth.set_min_filter(NEAREST); - depth.set_mag_filter(NEAREST); - depth.set_wrap(CLAMP_TO_EDGE); - depth.storage(DEPTH_COMPONENT, w, h); - fbo.attach(DEPTH_ATTACHMENT, depth, 0); - - fbo.require_complete(); -} - - -Pipeline::MultisampleTarget::MultisampleTarget(unsigned w, unsigned h, unsigned s, PixelFormat f) -{ - color.storage_multisample(s, f, w, h); - fbo.attach(COLOR_ATTACHMENT0, color); - - depth.storage_multisample(s, DEPTH_COMPONENT, w, h); - fbo.attach(DEPTH_ATTACHMENT, depth); - - fbo.require_complete(); -} - } // namespace GL } // namespace Msp diff --git a/source/pipeline.h b/source/pipeline.h index d07e6431..e3f95994 100644 --- a/source/pipeline.h +++ b/source/pipeline.h @@ -6,6 +6,7 @@ #include "framebuffer.h" #include "renderable.h" #include "renderbuffer.h" +#include "rendertarget.h" #include "texture2d.h" namespace Msp { @@ -78,24 +79,6 @@ private: Slot(const Renderable *); }; - struct RenderTarget - { - Framebuffer fbo; - Texture2D color; - Texture2D depth; - - RenderTarget(unsigned, unsigned, PixelFormat); - }; - - struct MultisampleTarget - { - Framebuffer fbo; - Renderbuffer color; - Renderbuffer depth; - - MultisampleTarget(unsigned, unsigned, unsigned, PixelFormat); - }; - typedef std::list PassList; PassList passes; @@ -107,7 +90,7 @@ private: bool hdr; unsigned samples; RenderTarget *target[2]; - MultisampleTarget *target_ms; + RenderTarget *target_ms; mutable bool in_frame; public: diff --git a/source/rendertarget.cpp b/source/rendertarget.cpp new file mode 100644 index 00000000..376af048 --- /dev/null +++ b/source/rendertarget.cpp @@ -0,0 +1,183 @@ +#include +#include "error.h" +#include "renderbuffer.h" +#include "rendertarget.h" + +using namespace std; + +namespace Msp { +namespace GL { + +RenderTargetFormat::RenderTargetFormat(): + count(0) +{ } + +RenderTargetFormat::RenderTargetFormat(RenderOutput o): + count(1) +{ + outputs[0] = o; +} + +RenderTargetFormat RenderTargetFormat::operator,(RenderOutput o) const +{ + if(count>=MAX_OUTPUTS) + throw invalid_operation("RenderTargetFormat::operator,"); + + RenderTargetFormat result = *this; + result.outputs[result.count++] = o; + + return result; +} + +RenderTargetFormat RenderTargetFormat::operator,(PixelFormat f) const +{ + if(!count) + throw invalid_operation("RenderTargetFormat::operator,"); + + PixelFormat unsized = get_unsized_pixelformat(f); + unsigned size = get_component_size(f); + unsigned char out = outputs[count-1]; + if(get_output_type(out)>=get_output_type(RENDER_DEPTH)) + { + if(unsized!=DEPTH_COMPONENT) + throw invalid_argument("RenderTargetformat::operator,"); + if(size>1) + --size; + } + else + { + if(unsized!=RGB && unsized!=RGBA) + throw invalid_argument("RenderTargetformat::operator,"); + if(size>3) + --size; + } + + out = (out&~15) | (size<<2) | (get_component_count(f)-1); + RenderTargetFormat result = *this; + result.outputs[result.count-1] = out; + + return result; +} + +int RenderTargetFormat::index(RenderOutput o) +{ + unsigned type = get_output_type(o); + unsigned i = 0; + for(const unsigned char *j=begin(); j!=end(); ++j, ++i) + if(get_output_type(*j)==type) + return i; + return -1; +} + + +PixelFormat get_output_pixelformat(unsigned char o) +{ + unsigned ncomp = (o&3)+1; + unsigned size = ((o>>2)&3); + PixelFormat base; + if(get_output_type(o)>=get_output_type(RENDER_DEPTH)) + { + base = DEPTH_COMPONENT; + if(size) + ++size; + } + else + { + base = (ncomp==4 ? RGBA : RGB); + if(size==3) + ++size; + } + + if(size) + return get_sized_pixelformat(base, size); + else + return base; +} + + +RenderTarget::RenderTarget(unsigned w, unsigned h, const RenderTargetFormat &f) +{ + init(w, h, 0, f); +} + +RenderTarget::RenderTarget(unsigned w, unsigned h, unsigned s, const RenderTargetFormat &f) +{ + init(w, h, s, f); +} + +void RenderTarget::init(unsigned w, unsigned h, unsigned s, const RenderTargetFormat &f) +{ + width = w; + height = h; + samples = s; + format = f; + + for(const unsigned char *i=format.begin(); i!=format.end(); ++i) + { + unsigned type = get_output_type(*i); + FramebufferAttachment att; + if(type>=get_output_type(RENDER_DEPTH)) + att = DEPTH_ATTACHMENT; + else + att = static_cast(COLOR_ATTACHMENT0+type); + + PixelFormat pf = get_output_pixelformat(*i); + + TargetBuffer tgt; + if(samples) + { + tgt.buffer = new Renderbuffer; + tgt.buffer->storage_multisample(samples, pf, width, height); + fbo.attach(att, *tgt.buffer); + } + else + { + tgt.texture = new Texture2D; + tgt.texture->storage(pf, width, height); + tgt.texture->set_filter(NEAREST); + tgt.texture->set_wrap(CLAMP_TO_EDGE); + fbo.attach(att, *tgt.texture); + } + buffers.push_back(tgt); + } + + fbo.require_complete(); +} + +RenderTarget::~RenderTarget() +{ + for(vector::iterator i=buffers.begin(); i!=buffers.end(); ++i) + { + if(samples) + delete i->buffer; + else + delete i->texture; + } +} + +const Texture2D &RenderTarget::get_target_texture(unsigned i) +{ + if(i>=buffers.size()) + throw out_of_range("RenderTarget::get_target_texture"); + if(samples) + throw invalid_operation("RenderTarget::get_target_texture"); + + return *buffers[i].texture; +} + +const Texture2D &RenderTarget::get_target_texture(RenderOutput o) +{ + int index = format.index(o); + if(index<0) + throw key_error(o); + + return get_target_texture(index); +} + +void RenderTarget::blit_from(const RenderTarget &other) +{ + fbo.blit_from(other.fbo, COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT, false); +} + +} // namespace GL +} // namespace Msp diff --git a/source/rendertarget.h b/source/rendertarget.h new file mode 100644 index 00000000..e38f6f51 --- /dev/null +++ b/source/rendertarget.h @@ -0,0 +1,85 @@ +#ifndef RENDERTARGET_H_ +#define RENDERTARGET_H_ + +#include "framebuffer.h" +#include "texture2d.h" + +namespace Msp { +namespace GL { + +enum RenderOutput +{ + RENDER_COLOR = 0|3, + RENDER_DEPTH = 192|12 +}; + +class RenderTargetFormat +{ +private: + enum { MAX_OUTPUTS = 7 }; + + unsigned char count; + unsigned char outputs[MAX_OUTPUTS]; + +public: + RenderTargetFormat(); + RenderTargetFormat(RenderOutput); + + RenderTargetFormat operator,(RenderOutput) const; + RenderTargetFormat operator,(PixelFormat) const; + + bool empty() const { return !count; } + const unsigned char *begin() const { return outputs; } + const unsigned char *end() const { return outputs+count; } + int index(RenderOutput); +}; + +inline RenderTargetFormat operator,(RenderOutput o1, RenderOutput o2) +{ return (RenderTargetFormat(o1), o2); } + +inline RenderTargetFormat operator,(RenderOutput o, PixelFormat f) +{ return (RenderTargetFormat(o), f); } + +inline unsigned get_output_type(unsigned char o) +{ return o>>4; } + +PixelFormat get_output_pixelformat(unsigned char); + + +class RenderTarget +{ +private: + union TargetBuffer + { + Texture2D *texture; + Renderbuffer *buffer; + }; + + unsigned width; + unsigned height; + unsigned samples; + RenderTargetFormat format; + std::vector buffers; + Framebuffer fbo; + +public: + RenderTarget(unsigned, unsigned, const RenderTargetFormat & = (RENDER_COLOR, RENDER_DEPTH)); + RenderTarget(unsigned, unsigned, unsigned, const RenderTargetFormat & = (RENDER_COLOR, RENDER_DEPTH)); +private: + RenderTarget(const RenderTarget &); + RenderTarget &operator=(const RenderTarget &); + void init(unsigned, unsigned, unsigned, const RenderTargetFormat &); +public: + ~RenderTarget(); + + const RenderTargetFormat &get_format() const { return format; } + Framebuffer &get_framebuffer() { return fbo; } + const Texture2D &get_target_texture(unsigned); + const Texture2D &get_target_texture(RenderOutput); + void blit_from(const RenderTarget &); +}; + +} // namespace GL +} // namespace Msp + +#endif -- 2.43.0