]> git.tdb.fi Git - libs/gl.git/commitdiff
Convert framebuffers and related functionality to new state management
authorMikko Rasa <tdb@tdb.fi>
Fri, 27 Aug 2021 13:26:26 +0000 (16:26 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 27 Aug 2021 23:55:59 +0000 (02:55 +0300)
21 files changed:
source/builders/sequencetemplate.cpp
source/core/framebuffer.cpp
source/core/framebuffer.h
source/core/pipelinestate.cpp
source/core/pipelinestate.h
source/core/rect.h [new file with mode: 0644]
source/core/tests.cpp [deleted file]
source/core/tests.h [deleted file]
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/renderer.cpp
source/render/renderer.h
source/render/rendertarget.cpp
source/render/rendertarget.h
source/render/sequence.cpp
source/render/view.cpp
source/render/windowview.cpp

index 18a328e1b270775a77b2686a7471addcf3faa64a..13534d75d28e99f61d648e35f57f5c744dcb0676 100644 (file)
@@ -9,7 +9,6 @@
 #include "resources.h"
 #include "scene.h"
 #include "sequencetemplate.h"
-#include "tests.h"
 
 using namespace std;
 
index 23b39f2d691c8de06aeaf378be10c25fe39db601..4dbb30929e05dc38ff822c981b51e251613f61bb 100644 (file)
@@ -1,6 +1,5 @@
 #include <msp/gl/extensions/arb_draw_buffers.h>
 #include <msp/gl/extensions/arb_direct_state_access.h>
-#include <msp/gl/extensions/ext_framebuffer_blit.h>
 #include <msp/gl/extensions/ext_framebuffer_object.h>
 #include <msp/gl/extensions/ext_texture_array.h>
 #include <msp/gl/extensions/ext_texture3d.h>
@@ -12,6 +11,7 @@
 #include "renderbuffer.h"
 #include "texture2d.h"
 #include "texture3d.h"
+#include "windowview.h"
 
 using namespace std;
 
@@ -65,19 +65,22 @@ framebuffer_incomplete::framebuffer_incomplete(FramebufferStatus status):
 
 Framebuffer::Framebuffer(unsigned i):
        id(i),
+       status(FRAMEBUFFER_COMPLETE),
        dirty(0)
 {
        if(id)
                throw invalid_argument("System framebuffer must have id 0");
 
-       glGetIntegerv(GL_VIEWPORT, &view.left);
-       width = view.width;
-       height = view.height;
+       int view[4];
+       glGetIntegerv(GL_VIEWPORT, view);
+       width = view[2];
+       height = view[3];
 }
 
 Framebuffer::Framebuffer():
        width(0),
        height(0),
+       status(FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
        dirty(0)
 {
        static Require _req(EXT_framebuffer_object);
@@ -92,24 +95,16 @@ Framebuffer::~Framebuffer()
 {
        if(id)
                glDeleteFramebuffers(1, &id);
-       if(current()==this)
-               unbind();
 }
 
-void Framebuffer::update_attachment(unsigned mask) const
+void Framebuffer::update() const
 {
-       if(!ARB_direct_state_access && current()!=this)
-       {
-               dirty |= mask;
-               return;
-       }
-
        vector<GLenum> color_bufs;
        color_bufs.reserve(attachments.size());
        for(unsigned i=0; i<attachments.size(); ++i)
        {
                const Attachment &attch = attachments[i];
-               if(mask&(1<<i))
+               if(dirty&(1<<i))
                {
                        if(attch.type==GL_RENDERBUFFER)
                        {
@@ -169,11 +164,17 @@ void Framebuffer::update_attachment(unsigned mask) const
                if(MSP_buffer_control)
                        glReadBuffer(first_buffer);
        }
+
+       if(ARB_direct_state_access)
+               status = static_cast<FramebufferStatus>(glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER));
+       else
+               status = static_cast<FramebufferStatus>(glCheckFramebufferStatus(GL_FRAMEBUFFER));
+
+       dirty = 0;
 }
 
 void Framebuffer::check_size()
 {
-       bool full_viewport = (view.left==0 && view.bottom==0 && view.width==width && view.height==height);
        for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
                if(i->type)
                {
@@ -199,8 +200,6 @@ void Framebuffer::check_size()
                                width = max(static_cast<TextureCube *>(i->tex)->get_size()>>i->level, 1U);
                                height = width;
                        }
-                       if(full_viewport)
-                               reset_viewport();
                        break;
                }
 }
@@ -221,7 +220,7 @@ void Framebuffer::set_texture_attachment(FramebufferAttachment attch, Texture &t
 
        unsigned i = get_attachment_index(attch);
        attachments[i].set(tex, level, layer);
-       update_attachment(1<<i);
+       dirty |= 1<<i;
        check_size();
 }
 
@@ -232,7 +231,7 @@ void Framebuffer::attach(FramebufferAttachment attch, Renderbuffer &rbuf)
 
        unsigned i = get_attachment_index(attch);
        attachments[i].set(rbuf);
-       update_attachment(1<<i);
+       dirty |= 1<<i;
        check_size();
 }
 
@@ -275,125 +274,25 @@ void Framebuffer::detach(FramebufferAttachment attch)
 
        unsigned i = get_attachment_index(attch);
        attachments[i].clear();
-       update_attachment(1<<i);
+       dirty |= 1<<i;
        check_size();
 }
 
-FramebufferStatus Framebuffer::check_status() const
+void Framebuffer::resize(const WindowView &view)
 {
-       if(ARB_direct_state_access)
-               return static_cast<FramebufferStatus>(glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER));
-       else
-       {
-               BindRestore _bind(this);
-               return static_cast<FramebufferStatus>(glCheckFramebufferStatus(GL_FRAMEBUFFER));
-       }
+       if(id)
+               throw invalid_operation("Framebuffer::resize");
+
+       width = view.get_width();
+       height = view.get_height();
 }
 
 void Framebuffer::require_complete() const
 {
-       FramebufferStatus status = check_status();
        if(status!=FRAMEBUFFER_COMPLETE)
                throw framebuffer_incomplete(status);
 }
 
-void Framebuffer::viewport(int l, int b, unsigned w, unsigned h)
-{
-       view.left = l;
-       view.bottom = b;
-       view.width = w;
-       view.height = h;
-
-       if(current()==this)
-               glViewport(view.left, view.bottom, view.width, view.height);
-}
-
-void Framebuffer::reset_viewport()
-{
-       viewport(0, 0, width, height);
-}
-
-void Framebuffer::clear()
-{
-       clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT|STENCIL_BUFFER_BIT);
-}
-
-void Framebuffer::clear(BufferBits bits)
-{
-       BindRestore _bind(this);
-       glClear(bits);
-}
-
-void Framebuffer::blit_from(const Framebuffer &other, int sx0, int sy0, int sx1, int sy1, int dx0, int dy0, int dx1, int dy1, BufferBits bits, bool filter)
-{
-       static Require _req(EXT_framebuffer_blit);
-
-       if(ARB_direct_state_access)
-       {
-               glBlitNamedFramebuffer(other.id, id, sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1, bits, (filter ? GL_LINEAR : GL_NEAREST));
-               return;
-       }
-
-       const Framebuffer *old = current();
-       if(set_current(this))
-       {
-               glBindFramebuffer(GL_DRAW_FRAMEBUFFER, id);
-               if(dirty)
-               {
-                       update_attachment(dirty);
-                       dirty = 0;
-               }
-       }
-       if(old!=&other)
-               glBindFramebuffer(GL_READ_FRAMEBUFFER, other.id);
-
-       glBlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1, bits, (filter ? GL_LINEAR : GL_NEAREST));
-
-       set_current(old);
-       glBindFramebuffer(GL_FRAMEBUFFER, (old ? old->id : 0));
-}
-
-void Framebuffer::blit_from(const Framebuffer &other, int sx, int sy, unsigned wd, unsigned ht, int dx, int dy, BufferBits bits)
-{
-       blit_from(other, sx, sy, sx+wd, sy+ht, dx, dy, dx+wd, dy+ht, bits, false);
-}
-
-void Framebuffer::blit_from(const Framebuffer &other, BufferBits bits, bool filter)
-{
-       blit_from(other, 0, 0, other.width, other.height, 0, 0, width, height, bits, filter);
-}
-
-void Framebuffer::bind() const
-{
-       if(id && attachments.empty())
-               throw invalid_operation("Framebuffer::bind");
-
-       if(set_current(this))
-       {
-               glBindFramebuffer(GL_FRAMEBUFFER, id);
-               if(dirty)
-               {
-                       update_attachment(dirty);
-                       dirty = 0;
-               }
-
-               if(width && height)
-                       glViewport(view.left, view.bottom, view.width, view.height);
-       }
-}
-
-const Framebuffer *Framebuffer::current()
-{
-       if(!cur_obj)
-               cur_obj = &system();
-       return cur_obj;
-}
-
-void Framebuffer::unbind()
-{
-       system().bind();
-}
-
 void Framebuffer::set_debug_name(const string &name)
 {
 #ifdef DEBUG
@@ -439,13 +338,5 @@ void Framebuffer::Attachment::clear()
        type = 0;
 }
 
-
-Framebuffer::Viewport::Viewport():
-       left(0),
-       bottom(0),
-       width(0),
-       height(0)
-{ }
-
 } // namespace GL
 } // namespace Msp
index ca97ed17e45d021f9b9b779aa7579754640949ef..2e1b367791f7f7065d0634df1845a1854876b050 100644 (file)
@@ -17,6 +17,7 @@ class Renderbuffer;
 class Texture;
 class Texture2D;
 class Texture3D;
+class WindowView;
 
 enum FramebufferAttachment
 {
@@ -69,7 +70,7 @@ least one image must be attached for the framebuffer to be usable.
 Requires the GL_EXT_framebuffer_object extension.  The blit functions require
 the GL_EXT_framebuffer_blit extension.
 */
-class Framebuffer: public Bindable<Framebuffer>
+class Framebuffer
 {
 private:
        struct Attachment
@@ -90,21 +91,11 @@ private:
                void clear();
        };
 
-       struct Viewport
-       {
-               int left;
-               int bottom;
-               unsigned width;
-               unsigned height;
-
-               Viewport();
-       };
-
        unsigned id;
        std::vector<Attachment> attachments;
        unsigned width;
        unsigned height;
-       Viewport view;
+       mutable FramebufferStatus status;
        mutable unsigned dirty;
 
        Framebuffer(unsigned);
@@ -116,7 +107,7 @@ public:
        unsigned get_height() const { return height; }
 
 private:
-       void update_attachment(unsigned) const;
+       void update() const;
        void check_size();
        unsigned get_attachment_index(FramebufferAttachment);
        void set_texture_attachment(FramebufferAttachment, Texture &, unsigned, int);
@@ -129,40 +120,19 @@ public:
        void attach_layered(FramebufferAttachment attch, TextureCube &tex, unsigned level = 0);
        void detach(FramebufferAttachment attch);
 
-       /** Checks the completeness of the framebuffer.  Returns
-       FRAMEBUFFER_COMPLETE if the framebuffer is complete and can be rendered to,
-       or one of the error status codes otherwise. */
-       FramebufferStatus check_status() const;
+       void resize(const WindowView &);
+
+       /** Returns FRAMEBUFFER_COMPLETE if the framebuffer is complete and can be
+       rendered to, or one of the error status codes otherwise. */
+       FramebufferStatus get_status() const { return status; }
 
        /** Ensures that the framebuffer is complete, throwing an exception if it
        isn't. */
        void require_complete() const;
 
-       void viewport(int, int, unsigned, unsigned);
-       void reset_viewport();
-
-       void clear();
-       void clear(BufferBits);
-
-       /** Blits a region from another framebuffer into this one.  If the source
-       and destination regions have different dimensions, the contents will be
-       stretched.  If filter is true, linear interpolation will be used, otherwise
-       no interpolation is done. */
-       void blit_from(const Framebuffer &other, int sx0, int sy0, int sx1, int sy1,
-               int dx0, int dy0, int dx1, int dy1, BufferBits bits, bool filter);
-
-       /** Blits a region from another framebuffer into this one, retaining its
-       dimensions. */
-       void blit_from(const Framebuffer & other, int sx, int sy,
-               unsigned wd, unsigned ht, int dx, int dy, BufferBits bits);
-
-       /** Blits the entire contents of another framebuffer into this one. */
-       void blit_from(const Framebuffer &other, BufferBits bits, bool filter);
-
-       void bind() const;
+       void refresh() const { if(dirty) update(); }
 
-       static const Framebuffer *current();
-       static void unbind();
+       unsigned get_id() const { return id; }
 
        void set_debug_name(const std::string &);
 
index 7a38eab5e4136a12e490e4bdcbb079872e181de1..167e7de05bfb0c629ba08327b72c5a7d3085317d 100644 (file)
@@ -9,8 +9,10 @@
 #include "buffer.h"
 #include "deviceinfo.h"
 #include "depthtest.h"
+#include "framebuffer.h"
 #include "pipelinestate.h"
 #include "program.h"
+#include "rect.h"
 #include "stenciltest.h"
 #include "texture.h"
 #include "uniformblock.h"
@@ -25,6 +27,9 @@ const PipelineState *PipelineState::last_applied = 0;
 vector<int> PipelineState::bound_tex_targets;
 
 PipelineState::PipelineState():
+       framebuffer(0),
+       viewport(0),
+       scissor(0),
        shprog(0),
        vertex_setup(0),
        front_face(COUNTERCLOCKWISE),
@@ -55,6 +60,21 @@ void PipelineState::set(T &target, T value, unsigned flag)
        }
 }
 
+void PipelineState::set_framebuffer(const Framebuffer *f)
+{
+       set(framebuffer, f, FRAMEBUFFER|VIEWPORT);
+}
+
+void PipelineState::set_viewport(const Rect *v)
+{
+       set(viewport, v, VIEWPORT);
+}
+
+void PipelineState::set_scissor(const Rect *s)
+{
+       set(scissor, s, SCISSOR);
+}
+
 void PipelineState::set_shader_program(const Program *p)
 {
        set(shprog, p, SHPROG);
@@ -142,6 +162,35 @@ void PipelineState::apply() const
 
 void PipelineState::apply(unsigned mask) const
 {
+       if(mask&FRAMEBUFFER)
+       {
+               glBindFramebuffer(GL_FRAMEBUFFER, framebuffer ? framebuffer->get_id() : 0);
+               if(framebuffer)
+               {
+                       framebuffer->refresh();
+                       framebuffer->require_complete();
+               }
+       }
+
+       if(mask&VIEWPORT)
+       {
+               if(viewport)
+                       glViewport(viewport->left, viewport->bottom, viewport->width, viewport->height);
+               else if(framebuffer)
+                       glViewport(0, 0, framebuffer->get_width(), framebuffer->get_height());
+       }
+
+       if(mask&SCISSOR)
+       {
+               if(scissor)
+               {
+                       glEnable(GL_SCISSOR_TEST);
+                       glScissor(scissor->left, scissor->bottom, scissor->width, scissor->height);
+               }
+               else
+                       glDisable(GL_SCISSOR_TEST);
+       }
+
        if(mask&SHPROG)
                glUseProgram(shprog ? shprog->get_id() : 0);
 
index a931e25c406808232cd07809c44d616d15c5a7d4..9f6795f16ec176d0cb4204354dcd7b4b7a4ad53e 100644 (file)
@@ -12,7 +12,9 @@ class Blend;
 class BufferBackedUniformBlock;
 class DefaultUniformBlock;
 class DepthTest;
+class Framebuffer;
 class Program;
+class Rect;
 class Sampler;
 class StencilTest;
 class Texture;
@@ -52,9 +54,15 @@ private:
                UNIFORMS = 32,
                DEPTH_TEST = 64,
                STENCIL_TEST = 128,
-               BLEND = 256
+               BLEND = 256,
+               FRAMEBUFFER = 512,
+               VIEWPORT = 1024,
+               SCISSOR = 2048
        };
 
+       const Framebuffer *framebuffer;
+       const Rect *viewport;
+       const Rect *scissor;
        const Program *shprog;
        const VertexSetup *vertex_setup;
        FaceWinding front_face;
@@ -78,6 +86,9 @@ private:
        template<typename T>
        void set(T &, T, unsigned);
 public:
+       void set_framebuffer(const Framebuffer *);
+       void set_viewport(const Rect *);
+       void set_scissor(const Rect *);
        void set_shader_program(const Program *);
        void set_vertex_setup(const VertexSetup *);
        void set_front_face(FaceWinding);
diff --git a/source/core/rect.h b/source/core/rect.h
new file mode 100644 (file)
index 0000000..333dbc2
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef MSP_GL_RECT_H_
+#define MSP_GL_RECT_H_
+
+namespace Msp {
+namespace GL {
+
+struct Rect
+{
+       int left;
+       int bottom;
+       unsigned width;
+       unsigned height;
+
+       Rect(): left(0), bottom(0), width(0), height(0) { }
+       Rect(int l, int b, unsigned w, unsigned h): left(l), bottom(b), width(w), height(h) { }
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
diff --git a/source/core/tests.cpp b/source/core/tests.cpp
deleted file mode 100644 (file)
index 0bbec05..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "tests.h"
-
-namespace Msp {
-namespace GL {
-
-ScissorTest::ScissorTest():
-       left(0),
-       bottom(0),
-       width(1),
-       height(1)
-{ }
-
-ScissorTest::ScissorTest(int l, int b, unsigned w, unsigned h):
-       left(l),
-       bottom(b),
-       width(w),
-       height(h)
-{ }
-
-void ScissorTest::bind() const
-{
-       if(set_current(this))
-       {
-               glEnable(GL_SCISSOR_TEST);
-               glScissor(left, bottom, width, height);
-       }
-}
-
-void ScissorTest::unbind()
-{
-       if(set_current(0))
-               glDisable(GL_SCISSOR_TEST);
-}
-
-} // namespace GL
-} // namespace Msp
diff --git a/source/core/tests.h b/source/core/tests.h
deleted file mode 100644 (file)
index 7e38e81..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef MSP_GL_TESTS_H_
-#define MSP_GL_TESTS_H_
-
-#include "bindable.h"
-#include "gl.h"
-#include "predicate.h"
-
-namespace Msp {
-namespace GL {
-
-/**
-Tests fragment coordinates against a rectangle.  Any fragments outside the
-rectangle are discarded.
-*/
-class ScissorTest: public Bindable<ScissorTest>
-{
-private:
-       int left;
-       int bottom;
-       unsigned width;
-       unsigned height;
-
-public:
-       ScissorTest();
-       ScissorTest(int, int, unsigned, unsigned);
-
-       void bind() const;
-
-       static void unbind();
-};
-
-} // namespace GL
-} // namespace Msp
-
-#endif
index 21271acf2555d8a7f6b474d9cf3657cc69dccdb9..6ba51853d6d288814bd716fbb76881d13e8185af 100644 (file)
@@ -5,7 +5,6 @@
 #include "renderer.h"
 #include "resources.h"
 #include "shader.h"
-#include "tests.h"
 
 using namespace std;
 
@@ -100,6 +99,8 @@ void AmbientOcclusion::set_edge_depth_threshold(float edt)
 
 void AmbientOcclusion::render(Renderer &renderer, const Texture2D &color, const Texture2D &depth)
 {
+       const Framebuffer *out_fbo = renderer.get_framebuffer();
+
        Renderer::Push push(renderer);
        renderer.set_texture("source", &color, &nearest_clamp_sampler);
        renderer.set_texture("depth", &depth, &nearest_clamp_sampler);
@@ -107,11 +108,10 @@ void AmbientOcclusion::render(Renderer &renderer, const Texture2D &color, const
        renderer.set_texture("rotate", &rotate_lookup, &nearest_sampler);
        renderer.set_shader_program(&occlude_shader, &shdata);
 
-       {
-               BindRestore bind_fbo(occlude_target.get_framebuffer());
-               quad.draw(renderer);
-       }
+       renderer.set_framebuffer(&occlude_target.get_framebuffer());
+       quad.draw(renderer);
 
+       renderer.set_framebuffer(out_fbo);
        renderer.set_shader_program(&combine_shader);
        quad.draw(renderer);
 }
index 6e6301151e87e02c00263b01d875d00ba8970d7d..8b973b30fc3943af479720e14b86231642cf41a0 100644 (file)
@@ -6,7 +6,6 @@
 #include "renderer.h"
 #include "resources.h"
 #include "shader.h"
-#include "tests.h"
 
 using namespace std;
 
@@ -68,8 +67,8 @@ void Bloom::render(Renderer &renderer, const Texture2D &src, const Texture2D &)
        renderer.set_shader_program(&blur_shader, &common_shdata);
        for(unsigned i=0; i<2; ++i)
        {
-               BindRestore bind_fbo(target[i]->get_framebuffer());
                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.add_shader_data(blur_shdata[i]);
                quad.draw(renderer);
index 465e4fee74fc65dd2ab462710c46ac2f6922d45e..1cefde1be840649cab8dab4059366299116d5a10 100644 (file)
@@ -63,7 +63,6 @@ void EnvironmentMap::init(unsigned s, PixelFormat f, unsigned l)
                TextureCubeFace face = TextureCube::enumerate_faces(i);
                faces[i].fbo.attach(COLOR_ATTACHMENT0, env_tex, face, 0);
                faces[i].fbo.attach(DEPTH_ATTACHMENT, depth_buf);
-               faces[i].fbo.require_complete();
                faces[i].camera.set_look_direction(TextureCube::get_face_direction(face));
                faces[i].camera.set_up_direction(TextureCube::get_t_direction(face));
                faces[i].camera.set_field_of_view(Geometry::Angle<float>::right());
@@ -143,17 +142,16 @@ void EnvironmentMap::setup_frame(Renderer &renderer)
 
        Vector3 center = matrix->column(3).slice<3>(0);
 
-       BindRestore bind_fbo(faces[0].fbo);
        for(unsigned i=0; i<6; ++i)
        {
                faces[i].camera.set_position(center);
-               faces[i].fbo.bind();
-               faces[i].fbo.clear();
+               renderer.set_framebuffer(&faces[i].fbo);
+               renderer.clear();
                renderer.set_camera(faces[i].camera);
                renderer.render(environment);
        }
 
-       irradiance_fbo.bind();
+       renderer.set_framebuffer(&irradiance_fbo);
        renderer.set_shader_program(&irradiance_shprog, &prefilter_shdata);
        renderer.set_texture("environment_map", &env_tex, &sampler);
        fullscreen_mesh.draw(renderer);
@@ -162,7 +160,7 @@ void EnvironmentMap::setup_frame(Renderer &renderer)
        for(unsigned i=0; i<specular_fbos.size(); ++i)
        {
                prefilter_shdata.uniform("roughness", 1.0f-sqrt(1.0f-static_cast<float>(i+1)/specular_fbos.size()));
-               specular_fbos[i].bind();
+               renderer.set_framebuffer(&specular_fbos[i]);
                fullscreen_mesh.draw(renderer);
        }
 }
index cf73e810070581d8c03c6e5f3c61391d127d1551..35e851cd784ddae6a623f760e753979d106016a1 100644 (file)
@@ -39,7 +39,6 @@ void ShadowMap::init(unsigned s)
 
        depth_buf.storage(DEPTH_COMPONENT32F, size, size, 1);
        fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0);
-       fbo.require_complete();
 
        depth_test.enabled = true;
        depth_test.compare = LEQUAL;
@@ -93,10 +92,9 @@ void ShadowMap::setup_frame(Renderer &renderer)
 
        shdata.uniform("shd_world_matrix", shadow_matrix);
 
-       BindRestore bind_fbo(fbo);
-       fbo.clear(DEPTH_BUFFER_BIT);
-
        Renderer::Push push(renderer);
+       renderer.set_framebuffer(&fbo);
+       renderer.clear(DEPTH_BUFFER_BIT);
        renderer.set_camera(shadow_camera);
        renderer.set_depth_test(&depth_test);
 
index 19fb526b1bdaa83b911954ef6f26b7c37c241c4b..a210efc94f578e35c7593fab4277d3150ac4575e 100644 (file)
@@ -104,12 +104,12 @@ void Sky::setup_frame(Renderer &renderer)
        if(transmittance_lookup_dirty)
        {
                transmittance_lookup_dirty = false;
-               Bind bind_fbo(transmittance_lookup.get_framebuffer());
+               renderer.set_framebuffer(&transmittance_lookup.get_framebuffer());
                renderer.set_shader_program(&transmittance_shprog, &shdata);
                fullscreen_mesh.draw(renderer);
        }
 
-       Bind bind_fbo(distant.get_framebuffer());
+       renderer.set_framebuffer(&distant.get_framebuffer());
        renderer.set_shader_program(&distant_shprog, &shdata);
        renderer.set_texture("transmittance_lookup", &transmittance_lookup.get_target_texture(0), &sampler);
        fullscreen_mesh.draw(renderer);
index f50baf9b7d4cdc019728315efb1a493fa19035d9..5dc1b55c67f83b80779ae3e19f61dfe6523f845c 100644 (file)
@@ -54,8 +54,8 @@ const Texture2D &PbrMaterial::get_or_create_fresnel_lookup()
        const Mesh &mesh = resources.get<Mesh>("_fullscreen_quad.mesh");
        Framebuffer fresnel_lookup_fbo;
        fresnel_lookup_fbo.attach(COLOR_ATTACHMENT0, *fresnel_lookup);
-       Bind bind_fbo(fresnel_lookup_fbo);
        Renderer renderer;
+       renderer.set_framebuffer(&fresnel_lookup_fbo);
        renderer.set_shader_program(&shprog, &shdata);
        mesh.draw(renderer);
 
index 68b7927dcb7067c0e3331c33f3f09bab1bf6a04a..52edc24924d73c262243fbd1226a296b5f8f2d0f 100644 (file)
@@ -1,3 +1,6 @@
+#include <msp/gl/extensions/arb_direct_state_access.h>
+#include <msp/gl/extensions/ext_framebuffer_blit.h>
+#include <msp/gl/extensions/ext_framebuffer_object.h>
 #include "batch.h"
 #include "buffer.h"
 #include "camera.h"
@@ -54,6 +57,21 @@ void Renderer::transform(const Matrix &matrix)
        changed |= MATRIX;
 }
 
+void Renderer::set_framebuffer(const Framebuffer *f)
+{
+       state->framebuffer = f;
+}
+
+void Renderer::set_viewport(const Rect *v)
+{
+       state->viewport = v;
+}
+
+void Renderer::set_scissor(const Rect *s)
+{
+       state->scissor = s;
+}
+
 void Renderer::set_texture(Tag tag, const Texture *tex, const Sampler *samp)
 {
        if(tex)
@@ -226,6 +244,18 @@ void Renderer::render(const Renderable &renderable, Tag tag)
                renderable.render(*this, tag);
 }
 
+void Renderer::clear()
+{
+       clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT|STENCIL_BUFFER_BIT);
+}
+
+void Renderer::clear(BufferBits buffers)
+{
+       pipeline_state.set_framebuffer(state->framebuffer);
+       pipeline_state.apply();
+       glClear(buffers);
+}
+
 void Renderer::draw(const Batch &batch)
 {
        apply_state();
@@ -240,6 +270,32 @@ void Renderer::draw_instanced(const Batch &batch, unsigned count)
        batch.draw_instanced(count);
 }
 
+void Renderer::resolve_multisample(Framebuffer &target, BufferBits buffers)
+{
+       if(!state->framebuffer)
+               throw invalid_operation("Renderer::resolve_multisample");
+
+       unsigned width = state->framebuffer->get_width();
+       unsigned height = state->framebuffer->get_height();
+       if(target.get_width()!=width || target.get_height()!=height)
+               throw incompatible_data("Renderer::resolve_multisample");
+
+       if(ARB_direct_state_access)
+               glBlitNamedFramebuffer(state->framebuffer->get_id(), target.get_id(), 0, 0, width, height, 0, 0, width, height, buffers, GL_NEAREST);
+       else
+       {
+               glBindFramebuffer(GL_READ_FRAMEBUFFER, state->framebuffer->get_id());
+               glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target.get_id());
+
+               target.refresh();
+
+               glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, buffers, GL_NEAREST);
+
+               glBindFramebuffer(GL_FRAMEBUFFER, 0);
+               pipeline_state.set_framebuffer(0);
+       }
+}
+
 void Renderer::apply_state()
 {
        if(!state->shprog)
@@ -254,6 +310,10 @@ void Renderer::apply_state()
                changed &= ~MATRIX;
        }
 
+       pipeline_state.set_framebuffer(state->framebuffer);
+       pipeline_state.set_viewport(state->viewport);
+       pipeline_state.set_scissor(state->scissor);
+
        bool shprog_changed = (state->shprog!=pipeline_state.get_shader_program());
        pipeline_state.set_shader_program(state->shprog);
 
@@ -321,6 +381,9 @@ Renderer::BoundProgramData::BoundProgramData(const ProgramData *d):
 
 Renderer::State::State():
        camera(0),
+       framebuffer(0),
+       viewport(0),
+       scissor(0),
        texture_count(0),
        lowest_effect_texunit(Limits::get_global().max_texture_bindings),
        clipping(0),
index 23ced9e4fc567bc124a80fefd70b330937f149cc..23f7c5cc9a3f132d6154b9e9241aedcf7d186322 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <set>
 #include <vector>
+#include "framebuffer.h"
 #include "matrix.h"
 #include "pipelinestate.h"
 #include "programdata.h"
@@ -87,6 +88,9 @@ private:
        {
                const Camera *camera;
                Matrix model_matrix;
+               const Framebuffer *framebuffer;
+               const Rect *viewport;
+               const Rect *scissor;
                unsigned texture_count;
                unsigned lowest_effect_texunit;
                const Clipping *clipping;
@@ -136,6 +140,12 @@ public:
        /** Returns the current model matrix. */
        const Matrix &get_matrix() const { return state->model_matrix; }
 
+       void set_framebuffer(const Framebuffer *);
+       void set_viewport(const Rect *);
+       void set_scissor(const Rect *);
+
+       const Framebuffer *get_framebuffer() const { return state->framebuffer; }
+
        void set_texture(Tag, const Texture *, const Sampler * = 0);
 private:
        void flush_textures();
@@ -185,10 +195,15 @@ public:
        void exclude(const Renderable &);
        void include(const Renderable &);
 
+       void clear();
+       void clear(BufferBits);
+
        void render(const Renderable &, Tag = Tag());
        void draw(const Batch &);
        void draw_instanced(const Batch &, unsigned);
 
+       void resolve_multisample(Framebuffer &, BufferBits);
+
 private:
        void apply_state();
 };
index 7bdac6703e3554e60162a90839139c1f4efba4f3..34a08535ca4ca8bddac0149ab374188cb76b1e7a 100644 (file)
@@ -152,8 +152,6 @@ void RenderTarget::init(unsigned w, unsigned h, unsigned s, const RenderTargetFo
                }
                buffers.push_back(tgt);
        }
-
-       fbo.require_complete();
 }
 
 RenderTarget::~RenderTarget()
@@ -186,11 +184,6 @@ const Texture2D &RenderTarget::get_target_texture(RenderOutput o) const
        return get_target_texture(index);
 }
 
-void RenderTarget::blit_from(const RenderTarget &other)
-{
-       fbo.blit_from(other.fbo, COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT, false);
-}
-
 void RenderTarget::set_debug_name(const string &name)
 {
 #ifdef DEBUG
index 6577cdcfb5dfa78ceb69b7842beb08ab9de3dbc8..030e45775f19898ef1e29914000e7e2ac8d1a660 100644 (file)
@@ -79,7 +79,6 @@ public:
        Framebuffer &get_framebuffer() { return fbo; }
        const Texture2D &get_target_texture(unsigned) const;
        const Texture2D &get_target_texture(RenderOutput) const;
-       void blit_from(const RenderTarget &);
 
        void set_debug_name(const std::string &);
 };
index 2c32db86518b14033c9452a64be2ed0fb0106397..89d475e3fe1121d83cc98f0f55b6cb372964ccdc 100644 (file)
@@ -7,7 +7,6 @@
 #include "renderbuffer.h"
 #include "renderer.h"
 #include "sequence.h"
-#include "tests.h"
 #include "texture2d.h"
 #include "view.h"
 
@@ -160,20 +159,19 @@ void Sequence::render(Renderer &renderer, Tag tag) const
        if(tag.id)
                return;
 
-       const Framebuffer *out_fbo = Framebuffer::current();
-       // These are no-ops but will ensure the related state gets restored
-       BindRestore restore_fbo(out_fbo);
+       Renderer::Push _push(renderer);
+
+       const Framebuffer *out_fbo = renderer.get_framebuffer();
 
        if(target[0])
        {
-               Framebuffer &fbo = (samples ? target_ms : target[0])->get_framebuffer();
-               fbo.bind();
-               fbo.clear();
+               renderer.set_framebuffer(&(samples ? target_ms : target[0])->get_framebuffer());
+               renderer.clear();
        }
 
        for(vector<Step>::const_iterator i=steps.begin(); i!=steps.end(); ++i)
        {
-               Renderer::Push push(renderer);
+               Renderer::Push _push2(renderer);
 
                renderer.set_depth_test(&i->get_depth_test());
                renderer.set_stencil_test(&i->get_stencil_test());
@@ -189,20 +187,17 @@ void Sequence::render(Renderer &renderer, Tag tag) const
 
        if(target[0])
        {
+               if(samples)
+                       renderer.resolve_multisample(target[0]->get_framebuffer(), COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
+
                renderer.set_depth_test(0);
                renderer.set_stencil_test(0);
                renderer.set_blend(0);
 
-               if(samples)
-                       target[0]->blit_from(*target_ms);
-
                for(unsigned i=0; i<postproc.size(); ++i)
                {
                        unsigned j = i%2;
-                       if(i+1<postproc.size())
-                               target[1-j]->get_framebuffer().bind();
-                       else
-                               out_fbo->bind();
+                       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);
                        postproc[i].postproc->render(renderer, color, depth);
index db06bb33fb51f8db7c0fd1a78055ff50ba4d9f42..ba4b9469e723db14c6adcb6b972e4e976c3bf1c4 100644 (file)
@@ -40,11 +40,11 @@ void View::render()
 
 void View::render(Renderer &renderer)
 {
-       Bind bind_fbo(target);
-       target.clear();
+       Renderer::Push _push(renderer);
+       renderer.set_framebuffer(&target);
+       renderer.clear();
        if(content)
        {
-               Renderer::Push push(renderer);
                if(camera)
                        renderer.set_camera(*camera);
                content->setup_frame(renderer);
index 2cce075c9b5f80509c5bc98e1fc889a4d63039ae..b32a0b67a68b826c4cbf9d635e161f59ac1be46b 100644 (file)
@@ -23,7 +23,7 @@ void WindowView::render(Renderer &renderer)
 
 void WindowView::window_resized(unsigned w, unsigned h)
 {
-       target.viewport(0, 0, w, h);
+       Framebuffer::system().resize(*this);
        float aspect = static_cast<float>(w)/h;
        if(camera)
                camera->set_aspect_ratio(aspect);