Immediate Mode: replacing glPushAttrib/glPopAttrib

Reference document: http://docs.gl/gl3/glPushAttrib

This patch only tackles the bits that are set by Blender with the
following exceptions:

1) Deprecated states (e.g., GL_STIPPLE) are not saved/restored

2) The exception being GL_ALPHA_TEST, which will be removed, but it may
affect drawing too much now. To be removed once we no longer set GL_ALPHA_TEST
elsewhere.

3) paint_cursor will be tackled separated, since it was abusing
glPush/PopAttrib in the first place.

4) Despite what the glPushAttrib page above may suggest, GL_DEPTH_WRITEMASK needs glGet, not glIsEnabled

5) BGE is still a problem since it relies on GL_ALL_ATTRIB_BITS which
would lead to a way more complete/lenghty solution. Since the BGE has
other (OpenGL deprecated) problems anyways, it can be handled on its own
time.

Finally, the original design for 2.8 was to implement a proper stack
system. However we need to move to core profile sooner than later. So
this is a pragmatic temporary (that may be permanent) solution.

Reviewers: merwin, campbellbarton

Differential Revision: https://developer.blender.org/D2600
This commit is contained in:
Dalai Felinto
2017-04-04 20:33:23 +02:00
parent bbfa1a8639
commit cbd78c8126
7 changed files with 270 additions and 78 deletions

View File

@@ -175,6 +175,58 @@ void GPU_select_index_get(int index, int *r_col);
int GPU_select_to_index(unsigned int col);
void GPU_select_to_index_array(unsigned int *col, const unsigned int size);
typedef enum eGPUStateMask {
GPU_DEPTH_BUFFER_BIT = (1 << 0),
GPU_ENABLE_BIT = (1 << 1),
GPU_SCISSOR_BIT = (1 << 2),
GPU_VIEWPORT_BIT = (1 << 3),
GPU_BLEND_BIT = (1 << 4),
} eGPUStateMask;
typedef struct GPUStateValues
{
eGPUStateMask mask;
/* GL_ENABLE_BIT */
unsigned int is_alpha_test : 1;
unsigned int is_blend : 1;
bool is_clip_plane[6];
unsigned int is_cull_face : 1;
unsigned int is_depth_test : 1;
unsigned int is_dither : 1;
bool is_light[8];
unsigned int is_lighting : 1;
unsigned int is_line_smooth : 1;
unsigned int is_color_logic_op : 1;
unsigned int is_map1_vertex3 : 1;
unsigned int is_multisample : 1;
unsigned int is_normalize : 1;
unsigned int is_polygon_offset_line : 1;
unsigned int is_polygon_offset_fill : 1;
unsigned int is_polygon_smooth : 1;
unsigned int is_sample_alpha_to_coverage : 1;
unsigned int is_scissor_test : 1;
unsigned int is_stencil_test : 1;
unsigned int is_texture_2d : 1;
/* GL_DEPTH_BUFFER_BIT */
/* unsigned int is_depth_test : 1; */
int depth_func;
double depth_clear_value;
bool depth_write_mask;
/* GL_SCISSOR_BIT */
int scissor_box[4];
/* unsigned int is_scissor_test : 1; */
/* GL_VIEWPORT_BIT */
int viewport[4];
double near_far[2];
} GPUStateValues;
void gpuSaveState(GPUStateValues *attribs, eGPUStateMask mask);
void gpuRestoreState(GPUStateValues *attribs);
#ifdef __cplusplus
}
#endif

View File

@@ -42,6 +42,7 @@
#include "DNA_gpu_types.h"
#include "GPU_compositing.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_glew.h"
@@ -196,6 +197,8 @@ struct GPUFX {
Batch *quad_batch;
Batch *point_batch;
struct GPUStateValues attribs;
};
#if 0
@@ -642,7 +645,7 @@ bool GPU_fx_compositor_initialize_passes(
if (scissor_rect) {
int w_sc = BLI_rcti_size_x(scissor_rect) + 1;
int h_sc = BLI_rcti_size_y(scissor_rect) + 1;
glPushAttrib(GL_SCISSOR_BIT);
gpuSaveState(&fx->attribs, GPU_SCISSOR_BIT);
glEnable(GL_SCISSOR_TEST);
glScissor(scissor_rect->xmin - rect->xmin, scissor_rect->ymin - rect->ymin,
w_sc, h_sc);
@@ -718,7 +721,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0);
/* full screen quad where we will always write to depth buffer */
glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT);
gpuSaveState(&fx->attribs, GPU_DEPTH_BUFFER_BIT | GPU_SCISSOR_BIT);
glDepthFunc(GL_ALWAYS);
/* disable scissor from sculpt if any */
glDisable(GL_SCISSOR_TEST);
@@ -751,7 +754,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glPopAttrib();
gpuRestoreState(&fx->attribs);
}
@@ -781,8 +784,9 @@ bool GPU_fx_do_composite_pass(
GPU_framebuffer_texture_detach(fx->color_buffer);
GPU_framebuffer_texture_detach(fx->depth_buffer);
if (fx->restore_stencil)
glPopAttrib();
if (fx->restore_stencil) {
gpuRestoreState(&fx->attribs);
}
src = fx->color_buffer;
target = fx->color_buffer_sec;

View File

@@ -2484,4 +2484,130 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
#undef INDEX_BUF_ARRAY
}
/**
* Replacement for glPush/PopAttributes
*
* We don't need to cover all the options of legacy OpenGL
* but simply the ones used by Blender.
*/
void gpuSaveState(GPUStateValues *values, eGPUStateMask mask)
{
values->mask = mask;
if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
values->is_depth_test = glIsEnabled(GL_DEPTH_TEST);
glGetIntegerv(GL_DEPTH_FUNC, &values->depth_func);
glGetDoublev(GL_DEPTH_CLEAR_VALUE, &values->depth_clear_value);
glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&values->depth_write_mask);
}
if ((mask & GPU_ENABLE_BIT) != 0) {
values->is_alpha_test = glIsEnabled(GL_ALPHA_TEST);
values->is_blend = glIsEnabled(GL_BLEND);
for (int i = 0; i < 6; i++) {
values->is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i);
}
values->is_cull_face = glIsEnabled(GL_CULL_FACE);
values->is_depth_test = glIsEnabled(GL_DEPTH_TEST);
values->is_dither = glIsEnabled(GL_DITHER);
for (int i = 0; i < 8; i++) {
values->is_light[i] = glIsEnabled(GL_LIGHT0 + i);
}
values->is_line_smooth = glIsEnabled(GL_LINE_SMOOTH);
values->is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
values->is_map1_vertex3 = glIsEnabled(GL_MAP1_VERTEX_3);
values->is_multisample = glIsEnabled(GL_MULTISAMPLE);
values->is_normalize = glIsEnabled(GL_NORMALIZE);
values->is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE);
values->is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
values->is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH);
values->is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
values->is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
values->is_stencil_test = glIsEnabled(GL_STENCIL_TEST);
values->is_texture_2d = glIsEnabled(GL_TEXTURE_2D);
}
if ((mask & GPU_SCISSOR_BIT) != 0) {
values->is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&values->scissor_box);
}
if ((mask & GPU_VIEWPORT_BIT) != 0) {
glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&values->near_far);
glGetIntegerv(GL_VIEWPORT, (GLint *)&values->viewport);
}
if ((mask & GPU_BLEND_BIT) != 0) {
values->is_blend = glIsEnabled(GL_BLEND);
}
}
static void restore_mask(GLenum cap, const bool value) {
if (value) {
glEnable(cap);
}
else {
glDisable(cap);
}
}
void gpuRestoreState(GPUStateValues *values)
{
GLint mask = values->mask;
if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
restore_mask(GL_DEPTH_TEST, values->is_depth_test);
glDepthFunc(values->depth_func);
glClearDepth(values->depth_clear_value);
glDepthMask(values->depth_write_mask);
}
if ((mask & GPU_ENABLE_BIT) != 0) {
restore_mask(GL_BLEND, values->is_blend);
for (int i = 0; i < 6; i++) {
restore_mask(GL_CLIP_PLANE0 + i, values->is_clip_plane[i]);
}
restore_mask(GL_CULL_FACE, values->is_cull_face);
restore_mask(GL_DEPTH_TEST, values->is_depth_test);
restore_mask(GL_DITHER, values->is_dither);
for (int i = 0; i < 6; i++) {
restore_mask(GL_LIGHT0 + i, values->is_light[i]);
}
restore_mask(GL_LINE_SMOOTH, values->is_line_smooth);
restore_mask(GL_COLOR_LOGIC_OP, values->is_color_logic_op);
restore_mask(GL_MAP1_VERTEX_3, values->is_map1_vertex3);
restore_mask(GL_MULTISAMPLE, values->is_multisample);
restore_mask(GL_NORMALIZE, values->is_normalize);
restore_mask(GL_POLYGON_OFFSET_LINE, values->is_polygon_offset_line);
restore_mask(GL_POLYGON_OFFSET_FILL, values->is_polygon_offset_fill);
restore_mask(GL_POLYGON_SMOOTH, values->is_polygon_smooth);
restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, values->is_sample_alpha_to_coverage);
restore_mask(GL_SCISSOR_TEST, values->is_scissor_test);
restore_mask(GL_STENCIL_TEST, values->is_stencil_test);
restore_mask(GL_TEXTURE_2D, values->is_texture_2d);
}
if ((mask & GPU_VIEWPORT_BIT) != 0) {
glViewport(values->viewport[0], values->viewport[1], values->viewport[2], values->viewport[3]);
glDepthRange(values->near_far[0], values->near_far[1]);
}
if ((mask & GPU_SCISSOR_BIT) != 0) {
restore_mask(GL_SCISSOR_TEST, values->is_scissor_test);
glScissor(values->scissor_box[0], values->scissor_box[1], values->scissor_box[2], values->scissor_box[3]);
}
if ((mask & GPU_BLEND_BIT) != 0) {
restore_mask(GL_BLEND, values->is_blend);
}
}
/** \} */

View File

@@ -33,6 +33,7 @@
#include "BKE_global.h"
#include "GPU_batch.h"
#include "GPU_draw.h"
#include "GPU_framebuffer.h"
#include "GPU_matrix.h"
#include "GPU_shader.h"
@@ -50,6 +51,7 @@ struct GPUFrameBuffer {
GLuint object;
GPUTexture *colortex[GPU_FB_MAX_SLOTS];
GPUTexture *depthtex;
struct GPUStateValues attribs;
};
static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
@@ -198,7 +200,7 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
}
/* push attributes */
glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
gpuSaveState(&fb->attribs, GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
glDisable(GL_SCISSOR_TEST);
/* bind framebuffer */
@@ -241,7 +243,7 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
}
/* push attributes */
glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
gpuSaveState(&fb->attribs, GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
glDisable(GL_SCISSOR_TEST);
/* bind framebuffer */
@@ -294,10 +296,10 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb)
}
void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *UNUSED(tex))
{
/* restore attributes */
glPopAttrib();
gpuRestoreState(&fb->attribs);
}
void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot)

View File

@@ -31,6 +31,8 @@
#include <stdlib.h>
#include <float.h>
#include "GPU_immediate.h"
#include "GPU_draw.h"
#include "GPU_select.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
@@ -291,6 +293,8 @@ typedef struct GPUPickState {
unsigned int *rect_id;
} nearest;
};
struct GPUStateValues attribs;
} GPUPickState;
@@ -316,8 +320,8 @@ void gpu_select_pick_begin(
/* Restrict OpenGL operations for when we don't have cache */
if (ps->is_cached == false) {
gpuSaveState(&ps->attribs, GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT);
glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT);
/* disable writing to the framebuffer */
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
@@ -536,7 +540,7 @@ unsigned int gpu_select_pick_end(void)
gpu_select_pick_load_id(ps->gl.prev_id);
}
glPopAttrib();
gpuRestoreState(&ps->attribs);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}

View File

@@ -32,6 +32,8 @@
#include <stdlib.h>
#include "GPU_immediate.h"
#include "GPU_draw.h"
#include "GPU_select.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
@@ -67,6 +69,8 @@ typedef struct GPUQueryState {
char mode;
unsigned int index;
int oldhits;
/* OpenGL attrib bits */
struct GPUStateValues attribs;
} GPUQueryState;
static GPUQueryState g_query_state = {0};
@@ -94,7 +98,7 @@ void gpu_select_query_begin(
g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), "gpu selection ids");
glGenQueries(g_query_state.num_of_queries, g_query_state.queries);
glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT);
gpuSaveState(&g_query_state.attribs, GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT);
/* disable writing to the framebuffer */
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
@@ -202,7 +206,7 @@ unsigned int gpu_select_query_end(void)
glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries);
MEM_freeN(g_query_state.queries);
MEM_freeN(g_query_state.id);
glPopAttrib();
gpuRestoreState(&g_query_state.attribs);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
return hits;

View File

@@ -285,7 +285,7 @@ void GPU_viewport_unbind(GPUViewport *viewport)
DefaultFramebufferList *dfbl = (DefaultFramebufferList *)viewport->fbl;
if (dfbl->default_fb) {
GPU_framebuffer_texture_unbind(NULL, NULL);
GPU_framebuffer_texture_unbind(dfbl->default_fb, NULL);
GPU_framebuffer_restore();
glEnable(GL_SCISSOR_TEST);