From 88e5cdfd8634789620fcf0ddcd8076ff064b0558 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 21 Dec 2015 17:59:48 +0100 Subject: [PATCH] More efficient clears for FBO --- panda/src/display/graphicsOutput.cxx | 2 +- panda/src/display/graphicsOutput.h | 2 +- panda/src/glstuff/glGraphicsBuffer_src.cxx | 117 ++++++++++++++++++ panda/src/glstuff/glGraphicsBuffer_src.h | 3 + .../glstuff/glGraphicsStateGuardian_src.cxx | 11 +- .../src/glstuff/glGraphicsStateGuardian_src.h | 6 + 6 files changed, 137 insertions(+), 4 deletions(-) diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index f27b7dbfee..6a63b77a7c 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/panda/src/display/graphicsOutput.cxx @@ -1262,7 +1262,7 @@ set_size_and_recalc(int x, int y) { //////////////////////////////////////////////////////////////////// // Function: GraphicsOutput::clear -// Access: Public +// Access: Public, Virtual // Description: Clears the entire framebuffer before rendering, // according to the settings of get_color_clear_active() // and get_depth_clear_active() (inherited from diff --git a/panda/src/display/graphicsOutput.h b/panda/src/display/graphicsOutput.h index 73b35a0e9a..c592b3a09d 100644 --- a/panda/src/display/graphicsOutput.h +++ b/panda/src/display/graphicsOutput.h @@ -274,7 +274,7 @@ public: // It is an error to call any of the following methods from any // thread other than the draw thread. These methods are normally // called by the GraphicsEngine. - void clear(Thread *current_thread); + virtual void clear(Thread *current_thread); virtual bool begin_frame(FrameMode mode, Thread *current_thread); virtual void end_frame(FrameMode mode, Thread *current_thread); diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index a41c9e7f6b..a3b07a33f6 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -12,6 +12,8 @@ // //////////////////////////////////////////////////////////////////// +#include "depthWriteAttrib.h" + TypeHandle CLP(GraphicsBuffer)::_type_handle; //////////////////////////////////////////////////////////////////// @@ -84,6 +86,121 @@ CLP(GraphicsBuffer):: } } +#ifndef OPENGLES +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsBuffer::clear +// Access: Public, Virtual +// Description: Clears the entire framebuffer before rendering, +// according to the settings of get_color_clear_active() +// and get_depth_clear_active() (inherited from +// DrawableRegion). +// +// This function is called only within the draw thread. +//////////////////////////////////////////////////////////////////// +void CLP(GraphicsBuffer):: +clear(Thread *current_thread) { + if (!is_any_clear_active()) { + return; + } + + CLP(GraphicsStateGuardian) *glgsg; + DCAST_INTO_V(glgsg, _gsg); + + if (glgsg->_glClearBufferfv == NULL) { + // We can't efficiently clear the buffer. Fall back to the + // inefficient default implementation for now. + GraphicsOutput::clear(current_thread); + return; + } + + if (display_cat.is_spam()) { + display_cat.spam() + << "clear(): " << get_type() << " " + << get_name() << " " << (void *)this << "\n"; + } + + PStatGPUTimer timer(glgsg, glgsg->_clear_pcollector); + + // Disable the scissor test, so we can clear the whole buffer. + glDisable(GL_SCISSOR_TEST); + glgsg->_scissor_enabled = false; + glgsg->_scissor_array.clear(); + glgsg->_scissor_attrib_active = false; + + if (GLCAT.is_spam()) { + GLCAT.spam() + << "glDisable(GL_SCISSOR_TEST)\n"; + } + + // Set the buffers into which we'll be indexing with glClearBuffer. + int draw_buffer_type = _draw_buffer_type & _fb_properties.get_buffer_mask(); + draw_buffer_type |= _fb_properties.get_aux_mask(); + glgsg->_color_write_mask = ColorWriteAttrib::C_all; + glgsg->set_draw_buffer(draw_buffer_type); + + int index = 0; + if (_fb_properties.get_color_bits() > 0) { + if (_fb_properties.is_stereo()) { + // Clear both left and right attachments. + if (get_clear_active(RTP_color)) { + LColorf v = LCAST(float, get_clear_value(RTP_color)); + glgsg->_glClearBufferfv(GL_COLOR, index, v.get_data()); + glgsg->_glClearBufferfv(GL_COLOR, index + 1, v.get_data()); + } + index += 2; + } else { + if (get_clear_active(RTP_color)) { + LColorf v = LCAST(float, get_clear_value(RTP_color)); + glgsg->_glClearBufferfv(GL_COLOR, index, v.get_data()); + } + ++index; + } + } + for (int i = 0; i < _fb_properties.get_aux_rgba(); ++i) { + int layerid = RTP_aux_rgba_0 + i; + if (get_clear_active(layerid)) { + LColorf v = LCAST(float, get_clear_value(layerid)); + glgsg->_glClearBufferfv(GL_COLOR, index, v.get_data()); + } + ++index; + } + for (int i = 0; i < _fb_properties.get_aux_hrgba(); ++i) { + int layerid = RTP_aux_hrgba_0 + i; + if (get_clear_active(layerid)) { + LColorf v = LCAST(float, get_clear_value(layerid)); + glgsg->_glClearBufferfv(GL_COLOR, index, v.get_data()); + } + ++index; + } + for (int i = 0; i < _fb_properties.get_aux_float(); ++i) { + int layerid = RTP_aux_float_0 + i; + if (get_clear_active(layerid)) { + LColorf v = LCAST(float, get_clear_value(layerid)); + glgsg->_glClearBufferfv(GL_COLOR, index, v.get_data()); + } + ++index; + } + + if (get_clear_depth_active()) { + glDepthMask(GL_TRUE); + glgsg->_state_mask.clear_bit(DepthWriteAttrib::get_class_slot()); + + if (get_clear_stencil_active()) { + glStencilMask(~0); + glgsg->_glClearBufferfi(GL_DEPTH_STENCIL, 0, get_clear_depth(), get_clear_stencil()); + } else { + GLfloat depth = get_clear_depth(); + glgsg->_glClearBufferfv(GL_DEPTH, 0, &depth); + } + } else if (get_clear_stencil_active()) { + GLint stencil = get_clear_stencil(); + glgsg->_glClearBufferiv(GL_STENCIL, 0, &stencil); + } + + report_my_gl_errors(); +} +#endif + //////////////////////////////////////////////////////////////////// // Function: glGraphicsBuffer::begin_frame // Access: Public, Virtual diff --git a/panda/src/glstuff/glGraphicsBuffer_src.h b/panda/src/glstuff/glGraphicsBuffer_src.h index 03e429a422..fe1d55ae92 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.h +++ b/panda/src/glstuff/glGraphicsBuffer_src.h @@ -68,6 +68,9 @@ public: GraphicsOutput *host); virtual ~CLP(GraphicsBuffer)(); +#ifndef OPENGLES + virtual void clear(Thread *current_thread); +#endif virtual bool begin_frame(FrameMode mode, Thread *current_thread); virtual void end_frame(FrameMode mode, Thread *current_thread); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 38c153ed92..6a35cc3aa2 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -1954,7 +1954,6 @@ reset() { #if defined(OPENGLES_1) _glDrawBuffers = NULL; - _glClearBufferfv = NULL; _max_color_targets = 1; #elif defined(OPENGLES_2) @@ -1997,8 +1996,15 @@ reset() { if (is_at_least_gl_version(3, 0)) { _glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) get_extension_func("glClearBufferfv"); + _glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) + get_extension_func("glClearBufferiv"); + _glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) + get_extension_func("glClearBufferfi"); + } else { _glClearBufferfv = NULL; + _glClearBufferiv = NULL; + _glClearBufferfi = NULL; } #endif // !OPENGLES @@ -2798,7 +2804,8 @@ clear(DrawableRegion *clearable) { return; } - //XXX rdb: Is this line really necessary? + //XXX rdb: Is this line really necessary? Could we perhaps just + // reset the color write mask and other relevant attributes? set_state_and_transform(RenderState::make_empty(), _internal_transform); int mask = 0; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index e4f6c989d5..597d333f9b 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -814,7 +814,13 @@ public: INLINE bool get_supports_framebuffer_blit(); PFNGLBLITFRAMEBUFFEREXTPROC _glBlitFramebuffer; PFNGLDRAWBUFFERSPROC _glDrawBuffers; + +#ifndef OPENGLES PFNGLCLEARBUFFERFVPROC _glClearBufferfv; + PFNGLCLEARBUFFERIVPROC _glClearBufferiv; + PFNGLCLEARBUFFERFIPROC _glClearBufferfi; +#endif + int _max_fb_samples; bool _supports_viewport_arrays; bool _supports_bindless_texture;