More efficient clears for FBO

This commit is contained in:
rdb 2015-12-21 17:59:48 +01:00
parent dc0f40cadd
commit 88e5cdfd86
6 changed files with 137 additions and 4 deletions

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;