From db498c7e634fa999cf4b4a8b67c49813009b1790 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 8 Sep 2012 17:16:55 +0300 Subject: [PATCH] Notify Renderables about the start and end of a frame 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 | 3 +++ source/instancescene.cpp | 14 ++++++++++++++ source/instancescene.h | 3 +++ source/orderedscene.cpp | 12 ++++++++++++ source/orderedscene.h | 3 +++ source/pipeline.cpp | 24 +++++++++++++++++++++++- source/pipeline.h | 4 ++++ source/renderable.h | 12 ++++++++++++ source/simplescene.cpp | 12 ++++++++++++ source/simplescene.h | 3 +++ 10 files changed, 89 insertions(+), 1 deletion(-) diff --git a/source/effect.h b/source/effect.h index 7c943ae6..e99bc257 100644 --- a/source/effect.h +++ b/source/effect.h @@ -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 diff --git a/source/instancescene.cpp b/source/instancescene.cpp index 6ddfa0d2..7b0979c8 100644 --- a/source/instancescene.cpp +++ b/source/instancescene.cpp @@ -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) diff --git a/source/instancescene.h b/source/instancescene.h index 021a2b3f..ecbd63df 100644 --- a/source/instancescene.h +++ b/source/instancescene.h @@ -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; }; diff --git a/source/orderedscene.cpp b/source/orderedscene.cpp index 40149b34..e738cad7 100644 --- a/source/orderedscene.cpp +++ b/source/orderedscene.cpp @@ -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) diff --git a/source/orderedscene.h b/source/orderedscene.h index bb49c9cb..340eceda 100644 --- a/source/orderedscene.h +++ b/source/orderedscene.h @@ -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; }; diff --git a/source/pipeline.cpp b/source/pipeline.cpp index 2dd178f2..466aa23c 100644 --- a/source/pipeline.cpp +++ b/source/pipeline.cpp @@ -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::const_iterator i=renderables.begin(); i!=renderables.end(); ++i) + i->renderable->setup_frame(); +} + +void Pipeline::finish_frame() const +{ + in_frame = false; + for(vector::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) diff --git a/source/pipeline.h b/source/pipeline.h index f8fdb545..2c5b6c64 100644 --- a/source/pipeline.h +++ b/source/pipeline.h @@ -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; diff --git a/source/renderable.h b/source/renderable.h index 3432a87e..b53fa9ac 100644 --- a/source/renderable.h +++ b/source/renderable.h @@ -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. */ diff --git a/source/simplescene.cpp b/source/simplescene.cpp index 9e0623d8..f866f678 100644 --- a/source/simplescene.cpp +++ b/source/simplescene.cpp @@ -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) diff --git a/source/simplescene.h b/source/simplescene.h index db93e169..be86285b 100644 --- a/source/simplescene.h +++ b/source/simplescene.h @@ -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; }; -- 2.45.2