]> git.tdb.fi Git - libs/gl.git/commitdiff
Notify Renderables about the start and end of a frame
authorMikko Rasa <tdb@tdb.fi>
Sat, 8 Sep 2012 14:16:55 +0000 (17:16 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sat, 8 Sep 2012 14:16:55 +0000 (17:16 +0300)
This makes it possible for Renderables to do certain things only once per
frame.  This is particularly useful for Effects which need expensive
preparation.

source/effect.h
source/instancescene.cpp
source/instancescene.h
source/orderedscene.cpp
source/orderedscene.h
source/pipeline.cpp
source/pipeline.h
source/renderable.h
source/simplescene.cpp
source/simplescene.h

index 7c943ae6ef297f2a80cef9fc8d640fedd19b721e..e99bc2576d9eb97220faed58f214b790779ab085 100644 (file)
@@ -26,6 +26,9 @@ public:
        void disable_for_pass(const Tag &);
 
        virtual const Matrix *get_matrix() const { return renderable.get_matrix(); }
+
+       virtual void setup_frame() const { renderable.setup_frame(); }
+       virtual void finish_frame() const { renderable.finish_frame(); }
 };
 
 } // namespace GL
index 6ddfa0d2c5a2dd44cf2e33e6980b98466a15caa5..7b0979c8f5c0923d523e09a614a5acd977914fc9 100644 (file)
@@ -22,6 +22,20 @@ void InstanceScene::remove(const Renderable &r)
        }
 }
 
+void InstanceScene::setup_frame() const
+{
+       for(InstanceMap::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
+               for(RenderableSet::const_iterator j=i->second.begin(); j!=i->second.end(); ++j)
+                       (*j)->setup_frame();
+}
+
+void InstanceScene::finish_frame() const
+{
+       for(InstanceMap::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
+               for(RenderableSet::const_iterator j=i->second.begin(); j!=i->second.end(); ++j)
+                       (*j)->finish_frame();
+}
+
 void InstanceScene::render(Renderer &renderer, const Tag &tag) const
 {
        for(InstanceMap::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
index 021a2b3f94e69ccbd41c298a11da1b6e7559eec7..ecbd63df8d1413cfa1e8669672624f92000fd320 100644 (file)
@@ -25,6 +25,9 @@ public:
        virtual void add(const Renderable &);
        virtual void remove(const Renderable &);
 
+       virtual void setup_frame() const;
+       virtual void finish_frame() const;
+
        using Scene::render;
        virtual void render(Renderer &, const Tag &tag = Tag()) const;
 };
index 40149b3477f9dc3e4a1de60cf7d759dc66f2cfd7..e738cad7ace50fb84a096aea52c6eafde68cbb2a 100644 (file)
@@ -35,6 +35,18 @@ void OrderedScene::insert_after(const Renderable &after, const Renderable &r)
        renderables.insert(i, &r);
 }
 
+void OrderedScene::setup_frame() const
+{
+       for(RenderableList::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
+               (*i)->setup_frame();
+}
+
+void OrderedScene::finish_frame() const
+{
+       for(RenderableList::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
+               (*i)->finish_frame();
+}
+
 void OrderedScene::render(Renderer &renderer, const Tag &tag) const
 {
        for(RenderableList::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
index bb49c9cbb0b9e5dae223cbf06c7b60c3e851cddd..340ecedab3b52c5cd307119ec104b6a5a37436ae 100644 (file)
@@ -25,6 +25,9 @@ public:
        void insert(unsigned, const Renderable &);
        void insert_after(const Renderable &, const Renderable &);
 
+       virtual void setup_frame() const;
+       virtual void finish_frame() const;
+
        using Scene::render;
        virtual void render(Renderer &, const Tag & = Tag()) const;
 };
index 2dd178f247a53b97d26f74bbfe526292e21ae4d2..466aa23c69b6b3107457817f8efea8f33aa829ac 100644 (file)
@@ -21,7 +21,8 @@ Pipeline::Pipeline(unsigned w, unsigned h, bool d):
        height(h),
        hdr(d),
        samples(0),
-       target_ms(0)
+       target_ms(0),
+       in_frame(false)
 {
        target[0] = 0;
        target[1] = 0;
@@ -98,6 +99,20 @@ void Pipeline::add_postprocessor(PostProcessor &pp)
        create_targets(false);
 }
 
+void Pipeline::setup_frame() const
+{
+       in_frame = true;
+       for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
+               i->renderable->setup_frame();
+}
+
+void Pipeline::finish_frame() const
+{
+       in_frame = false;
+       for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
+               i->renderable->finish_frame();
+}
+
 void Pipeline::render(const Tag &tag) const
 {
        if(tag.id)
@@ -112,6 +127,10 @@ void Pipeline::render(Renderer &renderer, const Tag &tag) const
        if(tag.id)
                return;
 
+       bool was_in_frame = in_frame;
+       if(!in_frame)
+               setup_frame();
+
        if(target[0])
        {
                Framebuffer &fbo = (samples ? target_ms->fbo : target[0]->fbo);
@@ -148,6 +167,9 @@ void Pipeline::render(Renderer &renderer, const Tag &tag) const
 
                Framebuffer::unbind();
        }
+
+       if(!was_in_frame)
+               finish_frame();
 }
 
 void Pipeline::create_targets(bool recreate)
index f8fdb5450b18d42eb621ff0fb80141918b9ecbc8..2c5b6c6490fac43a85ce054cfdd78f69fe186f83 100644 (file)
@@ -102,6 +102,7 @@ private:
        unsigned samples;
        RenderTarget *target[2];
        MultisampleTarget *target_ms;
+       mutable bool in_frame;
 
 public:
        Pipeline(unsigned, unsigned, bool = false);
@@ -118,6 +119,9 @@ public:
        void remove_renderable(const Renderable &);
        void add_postprocessor(PostProcessor &);
 
+       virtual void setup_frame() const;
+       virtual void finish_frame() const;
+
        virtual void render(const Tag &tag = Tag()) const;
        virtual void render(Renderer &, const Tag &tag = Tag()) const;
 
index 3432a87ee77ed4db3c72600061127bef767c768d..b53fa9ac839307347bb614db7052dcfbe5a7a8cb 100644 (file)
@@ -16,6 +16,12 @@ a Renderer, and may optionally provide support for standalone rendering.
 
 The render methods take a Tag to identify a render pass.  It is most commonly
 used together with Techniques and Pipelines to implement multipass rendering.
+
+The setup_frame and finish_frame methods provide a mechanism for performing
+once-per-frame operations.  This is most useful for effects, which may need to
+do auxiliary rendering.  With complex rendering hierarchies, these methods may
+be called multiple times for one frame, but it's guaranteed that no rendering
+will occur before a setup_frame call or after a finish_frame call.
 */
 class Renderable
 {
@@ -32,6 +38,12 @@ public:
        matrix exists. */
        virtual const Matrix *get_matrix() const { return 0; }
 
+       /** Called when starting to render a new frame. */
+       virtual void setup_frame() const { }
+
+       /** Called when a complete frame has been rendered. */
+       virtual void finish_frame() const { }
+
        /** Renders the renderable without a renderer.  This can be convenient in
        some simple cases, but most renderables don't need to implement this
        method. */
index 9e0623d860f0dbd0a87dad795ceac2bd25112e76..f866f678280b2b4b2786aa2f5920fb9b816472fc 100644 (file)
@@ -14,6 +14,18 @@ void SimpleScene::remove(const Renderable &r)
        renderables.erase(&r);
 }
 
+void SimpleScene::setup_frame() const
+{
+       for(RenderableSet::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
+               (*i)->setup_frame();
+}
+
+void SimpleScene::finish_frame() const
+{
+       for(RenderableSet::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
+               (*i)->finish_frame();
+}
+
 void SimpleScene::render(Renderer &renderer, const Tag &tag) const
 {
        for(RenderableSet::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
index db93e169d3b82bae5903fccc8c81ff155d6ff3d9..be86285bba84b21ea25f98aad1d3f51954a165b1 100644 (file)
@@ -21,6 +21,9 @@ public:
        virtual void add(const Renderable &);
        virtual void remove(const Renderable &);
 
+       virtual void setup_frame() const;
+       virtual void finish_frame() const;
+
        using Scene::render;
        virtual void render(Renderer &, const Tag & = Tag()) const;
 };