]> git.tdb.fi Git - libs/gl.git/commitdiff
Redesign framebuffer attachment management
authorMikko Rasa <tdb@tdb.fi>
Mon, 13 Sep 2021 16:42:24 +0000 (19:42 +0300)
committerMikko Rasa <tdb@tdb.fi>
Mon, 13 Sep 2021 16:54:38 +0000 (19:54 +0300)
Framebuffers now have an immutable format to which attachments must
conform.

17 files changed:
source/core/deviceinfo.cpp
source/core/deviceinfo.h
source/core/framebuffer.cpp
source/core/framebuffer.h
source/core/frameformat.cpp [new file with mode: 0644]
source/core/frameformat.h [new file with mode: 0644]
source/core/texture.h
source/core/texture2dmultisample.h
source/effects/ambientocclusion.cpp
source/effects/bloom.cpp
source/effects/environmentmap.cpp
source/effects/shadowmap.cpp
source/effects/sky.cpp
source/materials/pbrmaterial.cpp
source/render/rendertarget.cpp
source/render/rendertarget.h
source/render/sequence.cpp

index 54cb88b43182b616b41a569d73c8306092da260c..93297a790974b23479c165b9b576d6fdf6220576 100644 (file)
@@ -12,6 +12,7 @@ Limits::Limits()
        glGetIntegerv(GL_MAX_CLIP_PLANES, reinterpret_cast<int *>(&max_clip_planes));
        glGetIntegerv(GL_MAX_SAMPLES, reinterpret_cast<int *>(&max_samples));
        glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, reinterpret_cast<int *>(&uniform_buffer_alignment));
+       glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, reinterpret_cast<int *>(&max_color_attachments));
 }
 
 const Limits &Limits::get_global()
index 9ea239b17402d5afda4654d3dd7063d328ac3cc6..1eb120ff2ec509921ed2dfa84fbcbce92393953d 100644 (file)
@@ -12,6 +12,7 @@ struct Limits
        unsigned max_clip_planes;
        unsigned max_samples;
        unsigned uniform_buffer_alignment;
+       unsigned max_color_attachments;
 
        Limits();
 
index 93a726868c040d6464382ead82c148d58ed20c08..05cd27f0395947fab9465c313b25db1a7ff09bd1 100644 (file)
@@ -77,14 +77,32 @@ Framebuffer::Framebuffer(unsigned i):
        height = view[3];
 }
 
-Framebuffer::Framebuffer():
-       width(0),
-       height(0),
-       status(FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
-       dirty(0)
+Framebuffer::Framebuffer()
+{
+       init();
+}
+
+Framebuffer::Framebuffer(FrameAttachment fa)
+{
+       init();
+       set_format(fa);
+}
+
+Framebuffer::Framebuffer(const FrameFormat &f)
+{
+       init();
+       set_format(f);
+}
+
+void Framebuffer::init()
 {
        static Require _req(EXT_framebuffer_object);
 
+       width = 0;
+       height = 0;
+       status = FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+       dirty = 0;
+
        if(ARB_direct_state_access)
                glCreateFramebuffers(1, &id);
        else
@@ -97,44 +115,57 @@ Framebuffer::~Framebuffer()
                glDeleteFramebuffers(1, &id);
 }
 
+void Framebuffer::set_format(const FrameFormat &fmt)
+{
+       if(!format.empty())
+               throw invalid_operation("Framebuffer::set_format");
+       if(fmt.empty())
+               throw invalid_argument("Framebuffer::set_format");
+
+       format = fmt;
+       attachments.resize(format.size());
+}
+
 void Framebuffer::update() const
 {
        vector<GLenum> color_bufs;
-       color_bufs.reserve(attachments.size());
-       for(unsigned i=0; i<attachments.size(); ++i)
+       color_bufs.reserve(format.size());
+       unsigned i = 0;
+       for(const UInt16 *j=format.begin(); j!=format.end(); ++j, ++i)
        {
-               const Attachment &attch = attachments[i];
+               GLenum gl_attach_point = get_gl_attachment(static_cast<FrameAttachment>(*j));
                if(dirty&(1<<i))
                {
+                       const Attachment &attch = attachments[i];
                        if(attch.tex)
                        {
                                GLenum type = attch.tex->get_target();
                                if(ARB_direct_state_access)
                                {
                                        if(type==GL_TEXTURE_2D || type==GL_TEXTURE_2D_MULTISAMPLE || attch.layer<0)
-                                               glNamedFramebufferTexture(id, attch.attachment, attch.tex->get_id(), attch.level);
+                                               glNamedFramebufferTexture(id, gl_attach_point, attch.tex->get_id(), attch.level);
                                        else
-                                               glNamedFramebufferTextureLayer(id, attch.attachment, attch.tex->get_id(), attch.level, attch.layer);
+                                               glNamedFramebufferTextureLayer(id, gl_attach_point, attch.tex->get_id(), attch.level, attch.layer);
                                }
                                else if(type==GL_TEXTURE_2D || type==GL_TEXTURE_2D_MULTISAMPLE)
-                                       glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, type, attch.tex->get_id(), attch.level);
+                                       glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, type, attch.tex->get_id(), attch.level);
                                else if(attch.layer<0)
-                                       glFramebufferTexture(GL_FRAMEBUFFER, attch.attachment, attch.tex->get_id(), attch.level);
+                                       glFramebufferTexture(GL_FRAMEBUFFER, gl_attach_point, attch.tex->get_id(), attch.level);
                                else if(type==GL_TEXTURE_2D_ARRAY)
-                                       glFramebufferTextureLayer(GL_FRAMEBUFFER, attch.attachment, attch.tex->get_id(), attch.level, attch.layer);
+                                       glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attach_point, attch.tex->get_id(), attch.level, attch.layer);
                                else if(type==GL_TEXTURE_3D)
-                                       glFramebufferTexture3D(GL_FRAMEBUFFER, attch.attachment, type, attch.tex->get_id(), attch.level, attch.layer);
+                                       glFramebufferTexture3D(GL_FRAMEBUFFER, gl_attach_point, type, attch.tex->get_id(), attch.level, attch.layer);
                                else if(type==GL_TEXTURE_CUBE_MAP)
-                                       glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, TextureCube::enumerate_faces(attch.layer), attch.tex->get_id(), attch.level);
+                                       glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, TextureCube::enumerate_faces(attch.layer), attch.tex->get_id(), attch.level);
                        }
                        else if(ARB_direct_state_access)
-                               glNamedFramebufferTexture(id, attch.attachment, 0, 0);
+                               glNamedFramebufferTexture(id, gl_attach_point, 0, 0);
                        else
-                               glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, GL_TEXTURE_2D, 0, 0);
+                               glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, GL_TEXTURE_2D, 0, 0);
                }
 
-               if(attch.attachment>=COLOR_ATTACHMENT0 && attch.attachment<=COLOR_ATTACHMENT3)
-                       color_bufs.push_back(attch.attachment);
+               if(gl_attach_point!=GL_DEPTH_ATTACHMENT && gl_attach_point!=GL_STENCIL_ATTACHMENT)
+                       color_bufs.push_back(gl_attach_point);
        }
 
        if(color_bufs.size()>1)
@@ -198,74 +229,79 @@ void Framebuffer::check_size()
                        }
                        break;
                }
-}
 
-unsigned Framebuffer::get_attachment_index(FramebufferAttachment attch)
-{
-       for(unsigned i=0; i<attachments.size(); ++i)
-               if(attachments[i].attachment==attch)
-                       return i;
-       attachments.push_back(Attachment(attch));
-       return attachments.size()-1;
 }
 
-void Framebuffer::set_attachment(FrameAttachment attch, Texture &tex, unsigned level, int layer)
+void Framebuffer::set_attachment(FrameAttachment attch, Texture &tex, unsigned level, int layer, unsigned samples)
 {
-       if(!id)
+       if(format.empty() || !id)
                throw invalid_operation("Framebuffer::attach");
 
-       unsigned i = get_attachment_index(attch);
-       attachments[i].set(tex, level, layer);
-       dirty |= 1<<i;
-       check_size();
+       if((format.get_samples()>1 && samples!=format.get_samples()) || (format.get_samples()==1 && samples))
+               throw incompatible_data("Framebuffer::attach");
+
+       unsigned i = 0;
+       for(const UInt16 *j=format.begin(); j!=format.end(); ++j, ++i)
+               if(*j==attch)
+               {
+                       attachments[i].set(tex, level, layer);
+                       dirty |= 1<<i;
+                       check_size();
+                       return;
+               }
+
+       throw incompatible_data("Framebuffer::attach");
 }
 
-void Framebuffer::attach(FramebufferAttachment attch, Texture2D &tex, unsigned level)
+void Framebuffer::attach(FrameAttachment attch, Texture2D &tex, unsigned level)
 {
        tex.allocate(level);
-       set_attachment(attch, tex, level, 0);
+       set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, 0, 0);
 }
 
-void Framebuffer::attach(FramebufferAttachment attch, Texture2DMultisample &tex)
+void Framebuffer::attach(FrameAttachment attch, Texture2DMultisample &tex)
 {
-       set_attachment(attch, tex, 0, 0);
+       set_attachment(make_typed_attachment(attch, tex.get_format()), tex, 0, 0, tex.get_samples());
 }
 
-void Framebuffer::attach(FramebufferAttachment attch, Texture3D &tex, unsigned layer, unsigned level)
+void Framebuffer::attach(FrameAttachment attch, Texture3D &tex, unsigned layer, unsigned level)
 {
        tex.allocate(level);
-       set_attachment(attch, tex, level, layer);
+       set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, layer, 0);
 }
 
-void Framebuffer::attach(FramebufferAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level)
+void Framebuffer::attach(FrameAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level)
 {
        tex.allocate(level);
-       set_attachment(attch, tex, level, TextureCube::get_face_index(face));
+       set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, TextureCube::get_face_index(face), 0);
 }
 
-void Framebuffer::attach_layered(FramebufferAttachment attch, Texture3D &tex, unsigned level)
+void Framebuffer::attach_layered(FrameAttachment attch, Texture3D &tex, unsigned level)
 {
        static Require _req(ARB_geometry_shader4);
        tex.allocate(level);
-       set_attachment(attch, tex, level, -1);
+       set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0);
 }
 
-void Framebuffer::attach_layered(FramebufferAttachment attch, TextureCube &tex, unsigned level)
+void Framebuffer::attach_layered(FrameAttachment attch, TextureCube &tex, unsigned level)
 {
        static Require _req(ARB_geometry_shader4);
        tex.allocate(level);
-       set_attachment(attch, tex, level, -1);
+       set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0);
 }
 
-void Framebuffer::detach(FramebufferAttachment attch)
+void Framebuffer::detach(FrameAttachment attch)
 {
        if(!id)
                throw invalid_operation("Framebuffer::detach");
 
-       unsigned i = get_attachment_index(attch);
-       attachments[i].clear();
-       dirty |= 1<<i;
-       check_size();
+       int i = format.index(attch);
+       if(i>=0)
+       {
+               attachments[i].clear();
+               dirty |= 1<<i;
+               check_size();
+       }
 }
 
 void Framebuffer::resize(const WindowView &view)
@@ -300,8 +336,7 @@ Framebuffer &Framebuffer::system()
 }
 
 
-Framebuffer::Attachment::Attachment(FramebufferAttachment a):
-       attachment(a),
+Framebuffer::Attachment::Attachment():
        tex(0),
        level(0),
        layer(0)
index 9fe59bf774b929474869cb2f5ba60b3970ba6804..f2fbfea40e19bca9577cd97a540d6bfcfb3b1673 100644 (file)
@@ -2,6 +2,7 @@
 #define MSP_GL_FRAMEBUFFER_H_
 
 #include <vector>
+#include "frameformat.h"
 #include "gl.h"
 #include "texturecube.h"
 #include <msp/gl/extensions/arb_geometry_shader4.h>
@@ -18,16 +19,6 @@ class Texture2DMultisample;
 class Texture3D;
 class WindowView;
 
-enum FramebufferAttachment
-{
-       COLOR_ATTACHMENT0  = GL_COLOR_ATTACHMENT0,
-       COLOR_ATTACHMENT1  = GL_COLOR_ATTACHMENT1,
-       COLOR_ATTACHMENT2  = GL_COLOR_ATTACHMENT2,
-       COLOR_ATTACHMENT3  = GL_COLOR_ATTACHMENT3,
-       DEPTH_ATTACHMENT   = GL_DEPTH_ATTACHMENT,
-       STENCIL_ATTACHMENT = GL_STENCIL_ATTACHMENT
-};
-
 enum FramebufferStatus
 {
        FRAMEBUFFER_INCOMPLETE_ATTACHMENT         = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
@@ -74,17 +65,17 @@ class Framebuffer
 private:
        struct Attachment
        {
-               FramebufferAttachment attachment;
                Texture *tex;
                unsigned level;
                int layer;
 
-               Attachment(FramebufferAttachment);
+               Attachment();
                void set(Texture &, unsigned, int);
                void clear();
        };
 
        unsigned id;
+       FrameFormat format;
        std::vector<Attachment> attachments;
        unsigned width;
        unsigned height;
@@ -93,25 +84,48 @@ private:
 
        Framebuffer(unsigned);
 public:
+       /** Creates an empty framebuffer.  Format must be set before textures can
+       be attached. */
        Framebuffer();
+
+       /** Creates a framebuffer and sets its format to a single attachment. */
+       Framebuffer(FrameAttachment);
+
+       /** Creates a framebuffer and sets its format. */
+       Framebuffer(const FrameFormat &);
+
+private:
+       void init();
+public:
        ~Framebuffer();
 
+       /** Sets the format of the framebuffer.  Once the format is set, it can't
+       be changed. */
+       void set_format(const FrameFormat &);
+
+       const FrameFormat &get_format() const { return format; }
+
        unsigned get_width() const { return width; }
        unsigned get_height() const { return height; }
 
 private:
        void update() const;
        void check_size();
-       unsigned get_attachment_index(FramebufferAttachment);
-       void set_attachment(FramebufferAttachment, Texture &, unsigned, int);
+       void set_attachment(FrameAttachment, Texture &, unsigned, int, unsigned);
 public:
-       void attach(FramebufferAttachment attch, Texture2D &tex, unsigned level = 0);
-       void attach(FramebufferAttachment attch, Texture2DMultisample &tex);
-       void attach(FramebufferAttachment attch, Texture3D &tex, unsigned layer, unsigned level = 0);
-       void attach(FramebufferAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level = 0);
-       void attach_layered(FramebufferAttachment attch, Texture3D &tex, unsigned level = 0);
-       void attach_layered(FramebufferAttachment attch, TextureCube &tex, unsigned level = 0);
-       void detach(FramebufferAttachment attch);
+
+       /** Attaches a texture to the framebuffer.  Only the attachment point
+       portion of attch is considered; pixel format is ignored.  The framebuffer
+       must have a format and the format of the texture must match that defined
+       in the framebuffer for this attachment point. */
+       void attach(FrameAttachment attch, Texture2D &tex, unsigned level = 0);
+
+       void attach(FrameAttachment attch, Texture2DMultisample &tex);
+       void attach(FrameAttachment attch, Texture3D &tex, unsigned layer, unsigned level = 0);
+       void attach(FrameAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level = 0);
+       void attach_layered(FrameAttachment attch, Texture3D &tex, unsigned level = 0);
+       void attach_layered(FrameAttachment attch, TextureCube &tex, unsigned level = 0);
+       void detach(FrameAttachment attch);
 
        void resize(const WindowView &);
 
diff --git a/source/core/frameformat.cpp b/source/core/frameformat.cpp
new file mode 100644 (file)
index 0000000..30d7a47
--- /dev/null
@@ -0,0 +1,137 @@
+#include "deviceinfo.h"
+#include "error.h"
+#include "frameformat.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+FrameFormat::FrameFormat():
+       count(0),
+       samples(1)
+{ }
+
+FrameFormat::FrameFormat(FrameAttachment fa):
+       count(1),
+       samples(1)
+{
+       attachments[0] = fa;
+}
+
+FrameFormat FrameFormat::operator,(FrameAttachment fa) const
+{
+       if(count>=MAX_ATTACHMENTS)
+               throw invalid_operation("FrameFormat::operator,");
+
+       FrameFormat result = *this;
+       result.attachments[result.count++] = fa;
+
+       return result;
+}
+
+FrameFormat FrameFormat::operator,(PixelFormat pf) const
+{
+       if(!count)
+               throw invalid_operation("FrameFormat::operator,");
+
+       FrameFormat r = *this;
+       UInt16 &fa = r.attachments[r.count-1];
+       fa = make_typed_attachment(static_cast<FrameAttachment>(fa), pf);
+
+       return r;
+}
+
+FrameFormat FrameFormat::operator,(unsigned index) const
+{
+       if(!count)
+               throw invalid_operation("FrameFormat::operator,");
+
+       FrameFormat r = *this;
+       UInt16 &fa = r.attachments[r.count-1];
+       fa = make_indexed_attachment(static_cast<FrameAttachment>(fa), index);
+
+       return r;
+}
+
+FrameFormat &FrameFormat::set_samples(unsigned s)
+{
+       samples = s;
+       return *this;
+}
+
+int FrameFormat::index(FrameAttachment fa) const
+{
+       for(unsigned i=0; i<count; ++i)
+               if(get_attach_point(attachments[i])==get_attach_point(fa))
+                       return i;
+       return -1;
+}
+
+
+FrameAttachment make_typed_attachment(FrameAttachment fa, PixelFormat pf)
+{
+       PixelComponents comp = get_components(pf);
+       if(get_attach_point(fa)==get_attach_point(DEPTH_ATTACHMENT))
+       {
+               if(comp!=DEPTH_COMPONENT)
+                       throw invalid_argument("make_typed_attachment");
+       }
+       else if(get_attach_point(fa)==get_attach_point(STENCIL_ATTACHMENT))
+       {
+               if(comp!=STENCIL_INDEX)
+                       throw invalid_argument("make_typed_attachment");
+       }
+       else
+       {
+               if(comp!=RED && comp!=RG && comp!=RGB && comp!=RGBA)
+                       throw invalid_argument("make_typed_attachment");
+       }
+
+       DataType type = get_component_type(pf);
+       return static_cast<FrameAttachment>((fa&0xFC00) | (is_float(type)*0x80) | get_type_size(type)<<4 | get_component_count(comp));
+}
+
+FrameAttachment make_indexed_attachment(FrameAttachment fa, unsigned i)
+{
+       if(get_attach_point(fa)==get_attach_point(COLOR_ATTACHMENT))
+       {
+               if(i>61)
+                       throw out_of_range("make_indexed_attachment");
+               return static_cast<FrameAttachment>(fa+(i<<10));
+       }
+       else
+               throw invalid_argument("make_indexed_attachment");
+}
+
+PixelFormat get_attachment_pixelformat(UInt16 fa)
+{
+       PixelComponents comp;
+       if(get_attach_point(fa)==get_attach_point(DEPTH_ATTACHMENT))
+               comp = DEPTH_COMPONENT;
+       else if(get_attach_point(fa)==get_attach_point(STENCIL_ATTACHMENT))
+               comp = STENCIL_INDEX;
+       else
+               comp = static_cast<PixelComponents>(fa&7);
+
+       DataType type;
+       if(fa&0x80)
+               type = static_cast<DataType>((fa&0x70)>>4 | 0x300);
+       else
+               type = static_cast<DataType>((fa&0x70)>>4);
+
+       return make_pixelformat(comp, type);
+}
+
+GLenum get_gl_attachment(FrameAttachment fa)
+{
+       if(get_attach_point(fa)==get_attach_point(DEPTH_ATTACHMENT))
+               return GL_DEPTH_ATTACHMENT;
+       else if(get_attach_point(fa)==get_attach_point(STENCIL_ATTACHMENT))
+               return GL_STENCIL_ATTACHMENT;
+       else
+               return GL_COLOR_ATTACHMENT0+get_attach_point(fa);
+}
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/core/frameformat.h b/source/core/frameformat.h
new file mode 100644 (file)
index 0000000..45ea919
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef MSP_GL_FRAMEFORMAT_H_
+#define MSP_GL_FRAMEFORMAT_H_
+
+#include <msp/core/inttypes.h>
+#include "pixelformat.h"
+
+namespace Msp {
+namespace GL {
+
+/**
+Describes a single attachment of a framebuffer.  The values are bitfields laid
+as follows:
+
+nnnn nn__ fsss _ccc
+      â”‚   â”‚  â”‚    â””â•´Number of components
+      â”‚   â”‚  â””─────╴Size of one component
+      â”‚   â””────────╴Floating-point flag
+      â””────────────╴Attachment index
+
+This information is presented for internal documentation purposes only; it is
+inadvisable for programs to rely on it.
+*/
+enum FrameAttachment
+{
+       COLOR_ATTACHMENT = 0x0014,
+       DEPTH_ATTACHMENT = 0xF8C1,
+       STENCIL_ATTACHMENT = 0xFC11
+};
+
+/**
+Describes the complete format of a framebuffer.  It can hold multiple
+attachments (currently up to seven) as well as a sample count.
+*/
+class FrameFormat
+{
+private:
+       enum { MAX_ATTACHMENTS = 7 };
+
+       UInt8 count;
+       UInt8 samples;
+       UInt16 attachments[MAX_ATTACHMENTS];
+
+public:
+       FrameFormat();
+       FrameFormat(FrameAttachment);
+
+       FrameFormat operator,(FrameAttachment) const;
+       FrameFormat operator,(PixelFormat) const;
+       FrameFormat operator,(unsigned) const;
+
+       FrameFormat &set_samples(unsigned);
+       unsigned get_samples() const { return samples; }
+
+       unsigned size() const { return count; }
+       bool empty() const { return !count; }
+       const UInt16 *begin() const { return attachments; }
+       const UInt16 *end() const { return attachments+count; }
+       int index(FrameAttachment) const;
+};
+
+inline FrameFormat operator,(FrameAttachment fa1, FrameAttachment fa2)
+{ return (FrameFormat(fa1), fa2); }
+
+FrameAttachment make_typed_attachment(FrameAttachment, PixelFormat);
+
+inline FrameAttachment operator,(FrameAttachment fa, PixelFormat pf)
+{ return make_typed_attachment(fa, pf); }
+
+FrameAttachment make_indexed_attachment(FrameAttachment, unsigned);
+
+inline FrameAttachment operator,(FrameAttachment fa, unsigned i)
+{ return make_indexed_attachment(fa, i); }
+
+inline unsigned get_attach_point(UInt16 fa)
+{ return fa>>10; }
+
+PixelFormat get_attachment_pixelformat(UInt16);
+
+GLenum get_gl_attachment(FrameAttachment);
+
+} // namespace GL
+} // namespace Msp
+
+#endif
index 58e22d358a6a82f2f321b3ba553b9a5b2ce00fc6..e3697d2e712404940728085cce8b7ae0ea2818e5 100644 (file)
@@ -86,6 +86,8 @@ protected:
        void set_parameter_i(GLenum, int) const;
 
 public:
+       PixelFormat get_format() const { return format; }
+
        static bool can_generate_mipmap();
 
        void generate_mipmap();
index cb086f0d85dbecaade0d227441ad16bab3a1d838..1abacfaa6018bd3aafa9c49e9d0968fba7346f6d 100644 (file)
@@ -22,6 +22,7 @@ public:
 
        unsigned get_width() const { return width; }
        unsigned get_height() const { return height; }
+       unsigned get_samples() const { return samples; }
 
        virtual AsyncLoader *load(IO::Seekable &, const Resources * = 0) { return 0; }
        virtual UInt64 get_data_size() const;
index 6ba51853d6d288814bd716fbb76881d13e8185af..1b3626a9a82a69f45385fb914425247bcf812490 100644 (file)
@@ -13,7 +13,7 @@ namespace GL {
 
 AmbientOcclusion::AmbientOcclusion(unsigned w, unsigned h, float):
        rotate_lookup(get_or_create_rotate_lookup()),
-       occlude_target(w, h, (RENDER_COLOR,R8)),
+       occlude_target(w, h, (COLOR_ATTACHMENT,R8)),
        occlude_shader(Resources::get_global().get<Program>("_ambientocclusion_occlude.glsl.shader")),
        combine_shader(Resources::get_global().get<Program>("_ambientocclusion_combine.glsl.shader")),
        quad(Resources::get_global().get<Mesh>("_fullscreen_quad.mesh")),
@@ -104,7 +104,7 @@ void AmbientOcclusion::render(Renderer &renderer, const Texture2D &color, const
        Renderer::Push push(renderer);
        renderer.set_texture("source", &color, &nearest_clamp_sampler);
        renderer.set_texture("depth", &depth, &nearest_clamp_sampler);
-       renderer.set_texture("occlusion", &occlude_target.get_target_texture(RENDER_COLOR), &linear_sampler);
+       renderer.set_texture("occlusion", &occlude_target.get_target_texture(COLOR_ATTACHMENT), &linear_sampler);
        renderer.set_texture("rotate", &rotate_lookup, &nearest_sampler);
        renderer.set_shader_program(&occlude_shader, &shdata);
 
index 8b973b30fc3943af479720e14b86231642cf41a0..fc087d4ce19dbd5293dbdf53b40345ff52490dad 100644 (file)
@@ -23,7 +23,7 @@ Bloom::Bloom(unsigned w, unsigned h):
        blur_shdata[1].uniform("delta", 0.0f, 1.0f/h);
 
        for(unsigned i=0; i<2; ++i)
-               target[i] = new RenderTarget(w, h, (RENDER_COLOR,RGB16F));
+               target[i] = new RenderTarget(w, h, (COLOR_ATTACHMENT,RGB16F));
 
        set_radius(2.0f);
        set_strength(0.2f);
@@ -69,13 +69,13 @@ void Bloom::render(Renderer &renderer, const Texture2D &src, const Texture2D &)
        {
                Renderer::Push push2(renderer);
                renderer.set_framebuffer(&target[i]->get_framebuffer());
-               renderer.set_texture("source", (i ? &target[0]->get_target_texture(RENDER_COLOR) : &src), &nearest_sampler);
+               renderer.set_texture("source", (i ? &target[0]->get_target_texture(COLOR_ATTACHMENT) : &src), &nearest_sampler);
                renderer.add_shader_data(blur_shdata[i]);
                quad.draw(renderer);
        }
 
        renderer.set_texture("source", &src, &nearest_sampler);
-       renderer.set_texture("blurred", &target[1]->get_target_texture(RENDER_COLOR), &linear_sampler);
+       renderer.set_texture("blurred", &target[1]->get_target_texture(COLOR_ATTACHMENT), &linear_sampler);
        renderer.set_shader_program(&combine_shader);
        quad.draw(renderer);
 }
index 5002e0f88b786ae90440fb7e3e3b9a0aa487562e..ced4a1044d2bd4cbe33f388d2299c7fc4025e83e 100644 (file)
@@ -61,7 +61,8 @@ void EnvironmentMap::init(unsigned s, PixelFormat f, unsigned l)
        for(unsigned i=0; i<6; ++i)
        {
                TextureCubeFace face = TextureCube::enumerate_faces(i);
-               faces[i].fbo.attach(COLOR_ATTACHMENT0, env_tex, face, 0);
+               faces[i].fbo.set_format((COLOR_ATTACHMENT,f, DEPTH_ATTACHMENT,DEPTH_COMPONENT32F));
+               faces[i].fbo.attach(COLOR_ATTACHMENT, env_tex, face, 0);
                faces[i].fbo.attach(DEPTH_ATTACHMENT, depth_buf);
                faces[i].camera.set_look_direction(TextureCube::get_face_direction(face));
                faces[i].camera.set_up_direction(TextureCube::get_t_direction(face));
@@ -71,13 +72,17 @@ void EnvironmentMap::init(unsigned s, PixelFormat f, unsigned l)
        }
 
        irradiance.storage(f, size/4, 1);
-       irradiance_fbo.attach_layered(COLOR_ATTACHMENT0, irradiance);
+       irradiance_fbo.set_format((COLOR_ATTACHMENT,f));
+       irradiance_fbo.attach_layered(COLOR_ATTACHMENT, irradiance);
 
        if(l>1)
        {
                specular_fbos.resize(l-1);
                for(unsigned i=1; i<l; ++i)
-                       specular_fbos[i-1].attach_layered(COLOR_ATTACHMENT0, env_tex, i);
+               {
+                       specular_fbos[i-1].set_format((COLOR_ATTACHMENT,f));
+                       specular_fbos[i-1].attach_layered(COLOR_ATTACHMENT, env_tex, i);
+               }
 
                LinAl::Matrix<float, 3, 3> face_matrices[6];
                for(unsigned i=0; i<6; ++i)
index 35e851cd784ddae6a623f760e753979d106016a1..bcdb0c9f39ef6ec24ac5ac3121f8a8b3bd0be64b 100644 (file)
@@ -38,6 +38,7 @@ void ShadowMap::init(unsigned s)
        rendered = false;
 
        depth_buf.storage(DEPTH_COMPONENT32F, size, size, 1);
+       fbo.set_format((DEPTH_ATTACHMENT,DEPTH_COMPONENT32F));
        fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0);
 
        depth_test.enabled = true;
index 23819db36c006cb1f8cb8d53f67cb922686810f1..d9c95b3bd79839fed84d1ad3f06235a4f5ac626e 100644 (file)
@@ -15,10 +15,10 @@ namespace GL {
 Sky::Sky(Renderable &r, Light &s):
        Effect(r),
        sun(s),
-       transmittance_lookup(128, 64, (RENDER_COLOR, RGB16F)),
+       transmittance_lookup(128, 64, (COLOR_ATTACHMENT,RGB16F)),
        transmittance_shprog(Resources::get_global().get<Program>("_sky_transmittance.glsl.shader")),
        transmittance_lookup_dirty(true),
-       distant(256, 128, (RENDER_COLOR, RGB16F)),
+       distant(256, 128, (COLOR_ATTACHMENT,RGB16F)),
        distant_shprog(Resources::get_global().get<Program>("_sky_distant.glsl.shader")),
        fullscreen_mesh(Resources::get_global().get<Mesh>("_fullscreen_quad.mesh")),
        backdrop_shprog(Resources::get_global().get<Program>("_sky_backdrop.glsl.shader")),
index 5dc1b55c67f83b80779ae3e19f61dfe6523f845c..ad36159a6b12c744213d51cfa2605385e8e5d048 100644 (file)
@@ -52,8 +52,8 @@ const Texture2D &PbrMaterial::get_or_create_fresnel_lookup()
        shdata.uniform("roughness", 0.0f);
 
        const Mesh &mesh = resources.get<Mesh>("_fullscreen_quad.mesh");
-       Framebuffer fresnel_lookup_fbo;
-       fresnel_lookup_fbo.attach(COLOR_ATTACHMENT0, *fresnel_lookup);
+       Framebuffer fresnel_lookup_fbo((COLOR_ATTACHMENT,RG8));
+       fresnel_lookup_fbo.attach(COLOR_ATTACHMENT, *fresnel_lookup);
        Renderer renderer;
        renderer.set_framebuffer(&fresnel_lookup_fbo);
        renderer.set_shader_program(&shprog, &shdata);
index 426b2d5257d0ccebb770242f989ef75c45f38283..6a1142857492dce2fc1558f43c017eed6b003015 100644 (file)
@@ -10,146 +10,30 @@ 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
+RenderTarget::RenderTarget(unsigned w, unsigned h, const FrameFormat &f):
+       width(w),
+       height(h),
+       fbo(f)
 {
-       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,");
-
-       PixelComponents comp = get_components(f);
-       DataType type = get_component_type(f);
-       unsigned size = 0;
-       unsigned char out = outputs[count-1];
-       if(get_output_type(out)>=get_output_type(RENDER_DEPTH))
+       textures.reserve(f.size());
+       unsigned samples = f.get_samples();
+       for(const UInt16 *i=f.begin(); i!=f.end(); ++i)
        {
-               if(comp!=DEPTH_COMPONENT)
-                       throw invalid_argument("RenderTargetFormat::operator,");
-               switch(type)
-               {
-               case UNSIGNED_SHORT: size = 0; break;
-               case UNSIGNED_INT: size = 2; break;
-               case FLOAT: size = 3; break;
-               default: throw invalid_argument("RenderTargetFormat::operator,");
-               }
-       }
-       else
-       {
-               if(comp!=RED && comp!=RG && comp!=RGB && comp!=RGBA)
-                       throw invalid_argument("RenderTargetformat::operator,");
-               switch(type)
-               {
-               case UNSIGNED_BYTE: size = 0; break;
-               case HALF_FLOAT: size = 2; break;
-               case FLOAT: size = 3; break;
-               default: throw invalid_argument("RenderTargetFormat::operator,");
-               }
-       }
-
-       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) const
-{
-       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)
-{
-       PixelComponents comp;
-       DataType type;
-       if(get_output_type(o)>=get_output_type(RENDER_DEPTH))
-       {
-               static DataType types[4] = { UNSIGNED_SHORT, UNSIGNED_SHORT, UNSIGNED_INT, FLOAT };
-               comp = DEPTH_COMPONENT;
-               type = types[(o>>2)&3];
-       }
-       else
-       {
-               static PixelComponents components[4] = { RED, RG, RGB, RGBA };
-               static DataType types[4] = { UNSIGNED_BYTE, UNSIGNED_SHORT, HALF_FLOAT, FLOAT };
-               comp = components[o&3];
-               type = types[(o>>2)&3];
-       }
-
-       return make_pixelformat(comp, type);
-}
-
-
-RenderTarget::RenderTarget(unsigned w, unsigned h, RenderOutput o)
-{
-       init(w, h, 0, o);
-}
-
-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<FramebufferAttachment>(COLOR_ATTACHMENT0+type);
-
-               PixelFormat pf = get_output_pixelformat(*i);
+               FrameAttachment fa = static_cast<FrameAttachment>(*i);
+               PixelFormat pf = get_attachment_pixelformat(*i);
 
-               if(samples)
+               if(samples>1)
                {
                        Texture2DMultisample *tex2d_ms = new Texture2DMultisample;
                        tex2d_ms->storage(pf, width, height, samples);
-                       fbo.attach(att, *tex2d_ms);
+                       fbo.attach(fa, *tex2d_ms);
                        textures.push_back(tex2d_ms);
                }
                else
                {
                        Texture2D *tex2d = new Texture2D;
                        tex2d->storage(pf, width, height, 1);
-                       fbo.attach(att, *tex2d);
+                       fbo.attach(fa, *tex2d);
                        textures.push_back(tex2d);
                }
        }
@@ -165,17 +49,17 @@ const Texture2D &RenderTarget::get_target_texture(unsigned i) const
 {
        if(i>=textures.size())
                throw out_of_range("RenderTarget::get_target_texture");
-       if(samples)
+       if(fbo.get_format().get_samples()>1)
                throw invalid_operation("RenderTarget::get_target_texture");
 
        return *static_cast<const Texture2D *>(textures[i]);
 }
 
-const Texture2D &RenderTarget::get_target_texture(RenderOutput o) const
+const Texture2D &RenderTarget::get_target_texture(FrameAttachment fa) const
 {
-       int index = format.index(o);
+       int index = fbo.get_format().index(fa);
        if(index<0)
-               throw key_error(o);
+               throw key_error(fa);
 
        return get_target_texture(index);
 }
@@ -184,16 +68,19 @@ void RenderTarget::set_debug_name(const string &name)
 {
 #ifdef DEBUG
        fbo.set_debug_name(name+" [FBO]");
+       const FrameFormat &fmt = fbo.get_format();
        unsigned i = 0;
-       for(const unsigned char *j=format.begin(); j!=format.end(); ++i, ++j)
+       for(const UInt16 *j=fmt.begin(); j!=fmt.end(); ++i, ++j)
        {
-               unsigned type = get_output_type(*j);
+               unsigned attach_pt = get_attach_point(static_cast<FrameAttachment>(*j));
 
                string tex_name;
-               if(type>=get_output_type(RENDER_DEPTH))
+               if(attach_pt==get_attach_point(DEPTH_ATTACHMENT))
                        tex_name = name+"/depth";
+               else if(attach_pt==get_attach_point(STENCIL_ATTACHMENT))
+                       tex_name = name+"/stencil";
                else
-                       tex_name = Msp::format("%s/color%d", name, type);
+                       tex_name = Msp::format("%s/color%d", name, attach_pt);
 
                textures[i]->set_debug_name(tex_name+".tex2d");
        }
index f13d23d9683a12b2828272125a610570b52c28ca..bad7845c4064d1bb1c7993a97565a8aa071db81c 100644 (file)
@@ -9,72 +9,28 @@ namespace GL {
 class Texture;
 class Texture2D;
 
-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) const;
-};
-
-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:
        unsigned width;
        unsigned height;
-       unsigned samples;
-       RenderTargetFormat format;
        std::vector<Texture *> textures;
        Framebuffer fbo;
 
 public:
-       RenderTarget(unsigned, unsigned, RenderOutput);
-       RenderTarget(unsigned, unsigned, const RenderTargetFormat & = (RENDER_COLOR, RENDER_DEPTH));
-       RenderTarget(unsigned, unsigned, unsigned, const RenderTargetFormat & = (RENDER_COLOR, RENDER_DEPTH));
+       RenderTarget(unsigned, unsigned, const FrameFormat & = (COLOR_ATTACHMENT, DEPTH_ATTACHMENT));
 private:
        RenderTarget(const RenderTarget &);
        RenderTarget &operator=(const RenderTarget &);
-       void init(unsigned, unsigned, unsigned, const RenderTargetFormat &);
 public:
        ~RenderTarget();
 
        unsigned get_width() const { return width; }
        unsigned get_height() const { return height; }
-       const RenderTargetFormat &get_format() const { return format; }
+       const FrameFormat &get_format() const { return fbo.get_format(); }
        Framebuffer &get_framebuffer() { return fbo; }
        const Texture2D &get_target_texture(unsigned) const;
-       const Texture2D &get_target_texture(RenderOutput) const;
+       const Texture2D &get_target_texture(FrameAttachment) const;
 
        void set_debug_name(const std::string &);
 };
index aaa1ef12a2238e209973c708446672b3ba865ed6..e27ebf1888248695240a71a71179f4182e6d36db 100644 (file)
@@ -197,8 +197,8 @@ void Sequence::render(Renderer &renderer, Tag tag) const
                {
                        unsigned j = i%2;
                        renderer.set_framebuffer(i+1<postproc.size() ? &target[1-j]->get_framebuffer() : out_fbo);
-                       const Texture2D &color = target[j]->get_target_texture(RENDER_COLOR);
-                       const Texture2D &depth = target[j]->get_target_texture(RENDER_DEPTH);
+                       const Texture2D &color = target[j]->get_target_texture(COLOR_ATTACHMENT);
+                       const Texture2D &depth = target[j]->get_target_texture(DEPTH_ATTACHMENT);
                        postproc[i].postproc->render(renderer, color, depth);
                }
        }
@@ -220,7 +220,7 @@ void Sequence::create_targets(unsigned recreate)
        }
 
        PixelFormat color_pf = (hdr ? (alpha ? RGBA16F : RGB16F) : (alpha ? RGBA8 : RGB8));
-       RenderTargetFormat fmt = (RENDER_COLOR,color_pf, RENDER_DEPTH);
+       FrameFormat fmt = (COLOR_ATTACHMENT,color_pf, DEPTH_ATTACHMENT);
        if(!postproc.empty() || samples)
        {
                if(!target[0])
@@ -230,7 +230,7 @@ void Sequence::create_targets(unsigned recreate)
        }
 
        if(!target_ms && samples)
-               target_ms = new RenderTarget(width, height, samples, fmt);
+               target_ms = new RenderTarget(width, height, fmt.set_samples(samples));
 
 #ifdef DEBUG
        if(!debug_name.empty())