From ce3658993ce2f6b7527a04a36a5e1af349c6f2e9 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 27 Aug 2021 16:26:26 +0300 Subject: [PATCH] Convert framebuffers and related functionality to new state management --- source/builders/sequencetemplate.cpp | 1 - source/core/framebuffer.cpp | 159 +++++---------------------- source/core/framebuffer.h | 52 ++------- source/core/pipelinestate.cpp | 49 +++++++++ source/core/pipelinestate.h | 13 ++- source/core/rect.h | 21 ++++ source/core/tests.cpp | 36 ------ source/core/tests.h | 35 ------ source/effects/ambientocclusion.cpp | 10 +- source/effects/bloom.cpp | 3 +- source/effects/environmentmap.cpp | 10 +- source/effects/shadowmap.cpp | 6 +- source/effects/sky.cpp | 4 +- source/materials/pbrmaterial.cpp | 2 +- source/render/renderer.cpp | 63 +++++++++++ source/render/renderer.h | 15 +++ source/render/rendertarget.cpp | 7 -- source/render/rendertarget.h | 1 - source/render/sequence.cpp | 25 ++--- source/render/view.cpp | 6 +- source/render/windowview.cpp | 2 +- 21 files changed, 225 insertions(+), 295 deletions(-) create mode 100644 source/core/rect.h delete mode 100644 source/core/tests.cpp delete mode 100644 source/core/tests.h diff --git a/source/builders/sequencetemplate.cpp b/source/builders/sequencetemplate.cpp index 18a328e1..13534d75 100644 --- a/source/builders/sequencetemplate.cpp +++ b/source/builders/sequencetemplate.cpp @@ -9,7 +9,6 @@ #include "resources.h" #include "scene.h" #include "sequencetemplate.h" -#include "tests.h" using namespace std; diff --git a/source/core/framebuffer.cpp b/source/core/framebuffer.cpp index 23b39f2d..4dbb3092 100644 --- a/source/core/framebuffer.cpp +++ b/source/core/framebuffer.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -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 color_bufs; color_bufs.reserve(attachments.size()); for(unsigned i=0; i(glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER)); + else + status = static_cast(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::iterator i=attachments.begin(); i!=attachments.end(); ++i) if(i->type) { @@ -199,8 +200,6 @@ void Framebuffer::check_size() width = max(static_cast(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<(glCheckNamedFramebufferStatus(id, GL_FRAMEBUFFER)); - else - { - BindRestore _bind(this); - return static_cast(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 diff --git a/source/core/framebuffer.h b/source/core/framebuffer.h index ca97ed17..2e1b3677 100644 --- a/source/core/framebuffer.h +++ b/source/core/framebuffer.h @@ -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 +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 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 &); diff --git a/source/core/pipelinestate.cpp b/source/core/pipelinestate.cpp index 7a38eab5..167e7de0 100644 --- a/source/core/pipelinestate.cpp +++ b/source/core/pipelinestate.cpp @@ -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 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); diff --git a/source/core/pipelinestate.h b/source/core/pipelinestate.h index a931e25c..9f6795f1 100644 --- a/source/core/pipelinestate.h +++ b/source/core/pipelinestate.h @@ -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 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 index 00000000..333dbc25 --- /dev/null +++ b/source/core/rect.h @@ -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 index 0bbec053..00000000 --- a/source/core/tests.cpp +++ /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 index 7e38e81e..00000000 --- a/source/core/tests.h +++ /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 -{ -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 diff --git a/source/effects/ambientocclusion.cpp b/source/effects/ambientocclusion.cpp index 21271acf..6ba51853 100644 --- a/source/effects/ambientocclusion.cpp +++ b/source/effects/ambientocclusion.cpp @@ -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); } diff --git a/source/effects/bloom.cpp b/source/effects/bloom.cpp index 6e630115..8b973b30 100644 --- a/source/effects/bloom.cpp +++ b/source/effects/bloom.cpp @@ -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); diff --git a/source/effects/environmentmap.cpp b/source/effects/environmentmap.cpp index 465e4fee..1cefde1b 100644 --- a/source/effects/environmentmap.cpp +++ b/source/effects/environmentmap.cpp @@ -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::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(i+1)/specular_fbos.size())); - specular_fbos[i].bind(); + renderer.set_framebuffer(&specular_fbos[i]); fullscreen_mesh.draw(renderer); } } diff --git a/source/effects/shadowmap.cpp b/source/effects/shadowmap.cpp index cf73e810..35e851cd 100644 --- a/source/effects/shadowmap.cpp +++ b/source/effects/shadowmap.cpp @@ -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); diff --git a/source/effects/sky.cpp b/source/effects/sky.cpp index 19fb526b..a210efc9 100644 --- a/source/effects/sky.cpp +++ b/source/effects/sky.cpp @@ -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); diff --git a/source/materials/pbrmaterial.cpp b/source/materials/pbrmaterial.cpp index f50baf9b..5dc1b55c 100644 --- a/source/materials/pbrmaterial.cpp +++ b/source/materials/pbrmaterial.cpp @@ -54,8 +54,8 @@ const Texture2D &PbrMaterial::get_or_create_fresnel_lookup() const Mesh &mesh = resources.get("_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); diff --git a/source/render/renderer.cpp b/source/render/renderer.cpp index 68b7927d..52edc249 100644 --- a/source/render/renderer.cpp +++ b/source/render/renderer.cpp @@ -1,3 +1,6 @@ +#include +#include +#include #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), diff --git a/source/render/renderer.h b/source/render/renderer.h index 23ced9e4..23f7c5cc 100644 --- a/source/render/renderer.h +++ b/source/render/renderer.h @@ -3,6 +3,7 @@ #include #include +#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(); }; diff --git a/source/render/rendertarget.cpp b/source/render/rendertarget.cpp index 7bdac670..34a08535 100644 --- a/source/render/rendertarget.cpp +++ b/source/render/rendertarget.cpp @@ -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 diff --git a/source/render/rendertarget.h b/source/render/rendertarget.h index 6577cdcf..030e4577 100644 --- a/source/render/rendertarget.h +++ b/source/render/rendertarget.h @@ -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 &); }; diff --git a/source/render/sequence.cpp b/source/render/sequence.cpp index 2c32db86..89d475e3 100644 --- a/source/render/sequence.cpp +++ b/source/render/sequence.cpp @@ -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::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; iget_framebuffer().bind(); - else - out_fbo->bind(); + renderer.set_framebuffer(i+1get_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); diff --git a/source/render/view.cpp b/source/render/view.cpp index db06bb33..ba4b9469 100644 --- a/source/render/view.cpp +++ b/source/render/view.cpp @@ -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); diff --git a/source/render/windowview.cpp b/source/render/windowview.cpp index 2cce075c..b32a0b67 100644 --- a/source/render/windowview.cpp +++ b/source/render/windowview.cpp @@ -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(w)/h; if(camera) camera->set_aspect_ratio(aspect); -- 2.43.0