Use glClearBufferfv to clear MRTs more efficiently (without having to call glDrawBuffers several times)

This commit is contained in:
rdb 2014-08-17 16:41:19 +00:00
parent f8acde64f7
commit 1055c2e0fd
3 changed files with 118 additions and 60 deletions

View File

@ -1280,7 +1280,7 @@ open_buffer() {
// A lot of code seems to depend on being able to get a
// color buffer by just setting the rgb_color bit.
if (_fb_properties.get_color_bits() == 0 &&
_fb_properties.get_rgb_color() > 0) {
_fb_properties.get_rgb_color()) {
_fb_properties.set_color_bits(1);
}

View File

@ -1423,6 +1423,7 @@ reset() {
}
_glDrawBuffers = NULL;
_glClearBufferfv = NULL;
#ifndef OPENGLES
if (is_at_least_gl_version(2, 0)) {
_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
@ -1438,6 +1439,11 @@ reset() {
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
_max_color_targets = max_draw_buffers;
}
if (is_at_least_gl_version(3, 0)) {
_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)
get_extension_func("glClearBufferfv");
}
#endif // OPENGLES
#ifndef OPENGLES
@ -2178,9 +2184,7 @@ clear(DrawableRegion *clearable) {
PStatTimer timer(_clear_pcollector);
report_my_gl_errors();
if ((!clearable->get_clear_color_active())&&
(!clearable->get_clear_depth_active())&&
(!clearable->get_clear_stencil_active())) {
if (!clearable->is_any_clear_active()) {
return;
}
@ -2188,56 +2192,110 @@ clear(DrawableRegion *clearable) {
int mask = 0;
for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
int layerid = GraphicsOutput::RTP_aux_rgba_0 + i;
int layerbit = RenderBuffer::T_aux_rgba_0 << i;
if (clearable->get_clear_active(layerid)) {
LColor v = clearable->get_clear_value(layerid);
glClearColor(v[0],v[1],v[2],v[3]);
set_draw_buffer(layerbit);
glClear(GL_COLOR_BUFFER_BIT);
}
}
for (int i=0; i<_current_properties->get_aux_hrgba(); i++) {
int layerid = GraphicsOutput::RTP_aux_hrgba_0 + i;
int layerbit = RenderBuffer::T_aux_hrgba_0 << i;
if (clearable->get_clear_active(layerid)) {
LColor v = clearable->get_clear_value(layerid);
glClearColor(v[0],v[1],v[2],v[3]);
set_draw_buffer(layerbit);
glClear(GL_COLOR_BUFFER_BIT);
}
}
for (int i=0; i<_current_properties->get_aux_float(); i++) {
int layerid = GraphicsOutput::RTP_aux_float_0 + i;
int layerbit = RenderBuffer::T_aux_float_0 << i;
if (clearable->get_clear_active(layerid)) {
LColor v = clearable->get_clear_value(layerid);
glClearColor(v[0],v[1],v[2],v[3]);
set_draw_buffer(layerbit);
glClear(GL_COLOR_BUFFER_BIT);
}
}
#ifndef OPENGLES
if (_current_fbo != 0 && _glClearBufferfv != NULL) {
// We can use glClearBuffer to clear all the color attachments,
// which protects us from the overhead of having to call set_draw_buffer
// for every single attachment.
int index = 0;
// In the past, it was possible to set the draw buffer
// once in prepare_display_region and then forget about it.
// Now, with aux layers, it is necessary to occasionally
// change the draw buffer. In time, I think there will need
// to be a draw buffer attrib. Until then, this little hack
// to put things back the way they were after
// prepare_display_region will do.
set_draw_buffer(_draw_buffer_type);
if (_current_properties->get_color_bits() > 0) {
if (clearable->get_clear_color_active()) {
LColor v = clearable->get_clear_color();
glClearColor(v[0],v[1],v[2],v[3]);
if (gl_color_mask) {
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
if (_current_properties->get_color_bits() > 0) {
if (_current_properties->is_stereo()) {
// Clear both left and right attachments.
if (clearable->get_clear_active(GraphicsOutput::RTP_color)) {
LColorf v = LCAST(float, clearable->get_clear_value(GraphicsOutput::RTP_color));
_glClearBufferfv(GL_COLOR, index, v.get_data());
_glClearBufferfv(GL_COLOR, index + 1, v.get_data());
}
index += 2;
} else {
if (clearable->get_clear_active(GraphicsOutput::RTP_color)) {
LColorf v = LCAST(float, clearable->get_clear_value(GraphicsOutput::RTP_color));
_glClearBufferfv(GL_COLOR, index, v.get_data());
}
++index;
}
}
for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
int layerid = GraphicsOutput::RTP_aux_rgba_0 + i;
if (clearable->get_clear_active(layerid)) {
LColorf v = LCAST(float, clearable->get_clear_value(layerid));
_glClearBufferfv(GL_COLOR, index, v.get_data());
}
++index;
}
for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
int layerid = GraphicsOutput::RTP_aux_hrgba_0 + i;
if (clearable->get_clear_active(layerid)) {
LColorf v = LCAST(float, clearable->get_clear_value(layerid));
_glClearBufferfv(GL_COLOR, index, v.get_data());
}
++index;
}
for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
int layerid = GraphicsOutput::RTP_aux_float_0 + i;
if (clearable->get_clear_active(layerid)) {
LColorf v = LCAST(float, clearable->get_clear_value(layerid));
_glClearBufferfv(GL_COLOR, index, v.get_data());
}
++index;
}
} else
#endif
{
if (_current_properties->get_aux_mask() != 0) {
for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
int layerid = GraphicsOutput::RTP_aux_rgba_0 + i;
int layerbit = RenderBuffer::T_aux_rgba_0 << i;
if (clearable->get_clear_active(layerid)) {
LColor v = clearable->get_clear_value(layerid);
glClearColor(v[0], v[1], v[2], v[3]);
set_draw_buffer(layerbit);
glClear(GL_COLOR_BUFFER_BIT);
}
}
for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
int layerid = GraphicsOutput::RTP_aux_hrgba_0 + i;
int layerbit = RenderBuffer::T_aux_hrgba_0 << i;
if (clearable->get_clear_active(layerid)) {
LColor v = clearable->get_clear_value(layerid);
glClearColor(v[0], v[1], v[2], v[3]);
set_draw_buffer(layerbit);
glClear(GL_COLOR_BUFFER_BIT);
}
}
for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
int layerid = GraphicsOutput::RTP_aux_float_0 + i;
int layerbit = RenderBuffer::T_aux_float_0 << i;
if (clearable->get_clear_active(layerid)) {
LColor v = clearable->get_clear_value(layerid);
glClearColor(v[0], v[1], v[2], v[3]);
set_draw_buffer(layerbit);
glClear(GL_COLOR_BUFFER_BIT);
}
}
// In the past, it was possible to set the draw buffer
// once in prepare_display_region and then forget about it.
// Now, with aux layers, it is necessary to occasionally
// change the draw buffer. In time, I think there will need
// to be a draw buffer attrib. Until then, this little hack
// to put things back the way they were after
// prepare_display_region will do.
set_draw_buffer(_draw_buffer_type);
}
if (_current_properties->get_color_bits() > 0) {
if (clearable->get_clear_color_active()) {
LColor v = clearable->get_clear_color();
glClearColor(v[0], v[1], v[2], v[3]);
if (gl_color_mask) {
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
_state_mask.clear_bit(ColorWriteAttrib::get_class_slot());
mask |= GL_COLOR_BUFFER_BIT;
}
_state_mask.clear_bit(ColorWriteAttrib::get_class_slot());
mask |= GL_COLOR_BUFFER_BIT;
}
}
@ -6322,19 +6380,19 @@ set_draw_buffer(int rbtype) {
++index;
}
}
for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
if (rbtype & (RenderBuffer::T_aux_rgba_0 << i)) {
buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
}
++index;
}
for (int i=0; i<_current_properties->get_aux_hrgba(); i++) {
for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
if (rbtype & (RenderBuffer::T_aux_hrgba_0 << i)) {
buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
}
++index;
}
for (int i=0; i<_current_properties->get_aux_float(); i++) {
for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
if (rbtype & (RenderBuffer::T_aux_float_0 << i)) {
buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
}
@ -6423,19 +6481,19 @@ set_read_buffer(int rbtype) {
}
++index;
}
for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
if (rbtype & (RenderBuffer::T_aux_rgba_0 << i)) {
buffer = GL_COLOR_ATTACHMENT0_EXT + index;
}
++index;
}
for (int i=0; i<_current_properties->get_aux_hrgba(); i++) {
for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
if (rbtype & (RenderBuffer::T_aux_hrgba_0 << i)) {
buffer = GL_COLOR_ATTACHMENT0_EXT + index;
}
++index;
}
for (int i=0; i<_current_properties->get_aux_float(); i++) {
for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
if (rbtype & (RenderBuffer::T_aux_float_0 << i)) {
buffer = GL_COLOR_ATTACHMENT0_EXT + index;
}
@ -6487,8 +6545,6 @@ set_read_buffer(int rbtype) {
#endif // OPENGLES
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::get_numeric_type
// Access: Protected, Static

View File

@ -88,6 +88,7 @@ typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
@ -689,6 +690,7 @@ public:
INLINE bool get_supports_framebuffer_blit();
PFNGLBLITFRAMEBUFFEREXTPROC _glBlitFramebuffer;
PFNGLDRAWBUFFERSPROC _glDrawBuffers;
PFNGLCLEARBUFFERFVPROC _glClearBufferfv;
int _max_fb_samples;
bool _supports_viewport_arrays;
bool _supports_bindless_texture;