diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_state.cc')
-rw-r--r-- | source/blender/gpu/intern/gpu_state.cc | 468 |
1 files changed, 190 insertions, 278 deletions
diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc index 794c7a3eb97..478fd639cdd 100644 --- a/source/blender/gpu/intern/gpu_state.cc +++ b/source/blender/gpu/intern/gpu_state.cc @@ -25,6 +25,7 @@ # define PIXELSIZE (1.0f) #endif +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "BKE_global.h" @@ -33,239 +34,252 @@ #include "GPU_glew.h" #include "GPU_state.h" -static GLenum gpu_get_gl_blendfunction(eGPUBlendFunction blend) -{ - switch (blend) { - case GPU_ONE: - return GL_ONE; - case GPU_SRC_ALPHA: - return GL_SRC_ALPHA; - case GPU_ONE_MINUS_SRC_ALPHA: - return GL_ONE_MINUS_SRC_ALPHA; - case GPU_DST_COLOR: - return GL_DST_COLOR; - case GPU_ZERO: - return GL_ZERO; - default: - BLI_assert(!"Unhandled blend mode"); - return GL_ZERO; - } +#include "gpu_context_private.hh" + +#include "gpu_state_private.hh" + +using namespace blender::gpu; + +#define SET_STATE(_prefix, _state, _value) \ + do { \ + GPUStateManager *stack = GPU_context_active_get()->state_manager; \ + auto &state_object = stack->_prefix##state; \ + state_object._state = (_value); \ + } while (0) + +#define SET_IMMUTABLE_STATE(_state, _value) SET_STATE(, _state, _value) +#define SET_MUTABLE_STATE(_state, _value) SET_STATE(mutable_, _state, _value) + +/* -------------------------------------------------------------------- */ +/** \name Immutable state Setters + * \{ */ + +void GPU_blend(eGPUBlend blend) +{ + SET_IMMUTABLE_STATE(blend, blend); } -void GPU_blend(bool enable) +void GPU_face_culling(eGPUFaceCullTest culling) { - if (enable) { - glEnable(GL_BLEND); - } - else { - glDisable(GL_BLEND); - } + SET_IMMUTABLE_STATE(culling_test, culling); } -void GPU_blend_set_func(eGPUBlendFunction sfactor, eGPUBlendFunction dfactor) +void GPU_front_facing(bool invert) { - glBlendFunc(gpu_get_gl_blendfunction(sfactor), gpu_get_gl_blendfunction(dfactor)); + SET_IMMUTABLE_STATE(invert_facing, invert); } -void GPU_blend_set_func_separate(eGPUBlendFunction src_rgb, - eGPUBlendFunction dst_rgb, - eGPUBlendFunction src_alpha, - eGPUBlendFunction dst_alpha) +void GPU_provoking_vertex(eGPUProvokingVertex vert) { - glBlendFuncSeparate(gpu_get_gl_blendfunction(src_rgb), - gpu_get_gl_blendfunction(dst_rgb), - gpu_get_gl_blendfunction(src_alpha), - gpu_get_gl_blendfunction(dst_alpha)); + SET_IMMUTABLE_STATE(provoking_vert, vert); } -void GPU_face_culling(eGPUFaceCull culling) +void GPU_depth_test(eGPUDepthTest test) { - if (culling == GPU_CULL_NONE) { - glDisable(GL_CULL_FACE); - } - else { - glEnable(GL_CULL_FACE); - glCullFace((culling == GPU_CULL_FRONT) ? GL_FRONT : GL_BACK); - } + SET_IMMUTABLE_STATE(depth_test, test); } -void GPU_front_facing(bool invert) +void GPU_stencil_test(eGPUStencilTest test) { - glFrontFace((invert) ? GL_CW : GL_CCW); + SET_IMMUTABLE_STATE(stencil_test, test); } -void GPU_provoking_vertex(eGPUProvokingVertex vert) +void GPU_line_smooth(bool enable) { - glProvokingVertex((vert == GPU_VERTEX_FIRST) ? GL_FIRST_VERTEX_CONVENTION : - GL_LAST_VERTEX_CONVENTION); + SET_IMMUTABLE_STATE(line_smooth, enable); } -void GPU_depth_range(float near, float far) +void GPU_polygon_smooth(bool enable) { - /* glDepthRangef is only for OpenGL 4.1 or higher */ - glDepthRange(near, far); + SET_IMMUTABLE_STATE(polygon_smooth, enable); } -void GPU_depth_test(bool enable) +void GPU_logic_op_xor_set(bool enable) { - if (enable) { - glEnable(GL_DEPTH_TEST); - } - else { - glDisable(GL_DEPTH_TEST); - } + SET_IMMUTABLE_STATE(logic_op_xor, enable); } -bool GPU_depth_test_enabled() +void GPU_write_mask(eGPUWriteMask mask) { - return glIsEnabled(GL_DEPTH_TEST); + SET_IMMUTABLE_STATE(write_mask, mask); } -void GPU_line_smooth(bool enable) +void GPU_color_mask(bool r, bool g, bool b, bool a) { - if (enable && ((G.debug & G_DEBUG_GPU) == 0)) { - glEnable(GL_LINE_SMOOTH); - } - else { - glDisable(GL_LINE_SMOOTH); - } + GPUStateManager *stack = GPU_context_active_get()->state_manager; + auto &state = stack->state; + uint32_t write_mask = state.write_mask; + SET_FLAG_FROM_TEST(write_mask, r, (uint32_t)GPU_WRITE_RED); + SET_FLAG_FROM_TEST(write_mask, g, (uint32_t)GPU_WRITE_GREEN); + SET_FLAG_FROM_TEST(write_mask, b, (uint32_t)GPU_WRITE_BLUE); + SET_FLAG_FROM_TEST(write_mask, a, (uint32_t)GPU_WRITE_ALPHA); + state.write_mask = write_mask; } -void GPU_line_width(float width) +void GPU_depth_mask(bool depth) { - float max_size = GPU_max_line_width(); - float final_size = width * PIXELSIZE; - /* Fix opengl errors on certain platform / drivers. */ - CLAMP(final_size, 1.0f, max_size); - glLineWidth(final_size); + GPUStateManager *stack = GPU_context_active_get()->state_manager; + auto &state = stack->state; + uint32_t write_mask = state.write_mask; + SET_FLAG_FROM_TEST(write_mask, depth, (uint32_t)GPU_WRITE_DEPTH); + state.write_mask = write_mask; } -void GPU_point_size(float size) +void GPU_shadow_offset(bool enable) { - glPointSize(size * PIXELSIZE); + SET_IMMUTABLE_STATE(shadow_bias, enable); } -void GPU_polygon_smooth(bool enable) +void GPU_clip_distances(int distances_enabled) { - if (enable && ((G.debug & G_DEBUG_GPU) == 0)) { - glEnable(GL_POLYGON_SMOOTH); - } - else { - glDisable(GL_POLYGON_SMOOTH); - } + SET_IMMUTABLE_STATE(clip_distances, distances_enabled); +} + +void GPU_state_set(eGPUWriteMask write_mask, + eGPUBlend blend, + eGPUFaceCullTest culling_test, + eGPUDepthTest depth_test, + eGPUStencilTest stencil_test, + eGPUStencilOp stencil_op, + eGPUProvokingVertex provoking_vert) +{ + GPUStateManager *stack = GPU_context_active_get()->state_manager; + auto &state = stack->state; + state.write_mask = (uint32_t)write_mask; + state.blend = (uint32_t)blend; + state.culling_test = (uint32_t)culling_test; + state.depth_test = (uint32_t)depth_test; + state.stencil_test = (uint32_t)stencil_test; + state.stencil_op = (uint32_t)stencil_op; + state.provoking_vert = (uint32_t)provoking_vert; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mutable State Setters + * \{ */ + +void GPU_depth_range(float near, float far) +{ + GPUStateManager *stack = GPU_context_active_get()->state_manager; + auto &state = stack->mutable_state; + copy_v2_fl2(state.depth_range, near, far); +} + +void GPU_line_width(float width) +{ + SET_MUTABLE_STATE(line_width, width * PIXELSIZE); +} + +void GPU_point_size(float size) +{ + SET_MUTABLE_STATE(point_size, size * PIXELSIZE); } /* Programmable point size * - shaders set their own point size when enabled * - use glPointSize when disabled */ +/* TODO remove and use program point size everywhere */ void GPU_program_point_size(bool enable) { - if (enable) { - glEnable(GL_PROGRAM_POINT_SIZE); - } - else { - glDisable(GL_PROGRAM_POINT_SIZE); - } + GPUStateManager *stack = GPU_context_active_get()->state_manager; + auto &state = stack->mutable_state; + /* Set point size sign negative to disable. */ + state.point_size = fabsf(state.point_size) * (enable ? 1 : -1); } void GPU_scissor_test(bool enable) { - if (enable) { - glEnable(GL_SCISSOR_TEST); - } - else { - glDisable(GL_SCISSOR_TEST); - } + GPU_context_active_get()->active_fb->scissor_test_set(enable); } void GPU_scissor(int x, int y, int width, int height) { - glScissor(x, y, width, height); + int scissor_rect[4] = {x, y, width, height}; + GPU_context_active_get()->active_fb->scissor_set(scissor_rect); } void GPU_viewport(int x, int y, int width, int height) { - glViewport(x, y, width, height); + int viewport_rect[4] = {x, y, width, height}; + GPU_context_active_get()->active_fb->viewport_set(viewport_rect); } -void GPU_scissor_get_f(float coords[4]) +void GPU_stencil_reference_set(uint reference) { - glGetFloatv(GL_SCISSOR_BOX, coords); + SET_MUTABLE_STATE(stencil_reference, (uint8_t)reference); } -void GPU_scissor_get_i(int coords[4]) +void GPU_stencil_write_mask_set(uint write_mask) { - glGetIntegerv(GL_SCISSOR_BOX, coords); + SET_MUTABLE_STATE(stencil_write_mask, (uint8_t)write_mask); } -void GPU_viewport_size_get_f(float coords[4]) +void GPU_stencil_compare_mask_set(uint compare_mask) { - glGetFloatv(GL_VIEWPORT, coords); + SET_MUTABLE_STATE(stencil_compare_mask, (uint8_t)compare_mask); } -void GPU_viewport_size_get_i(int coords[4]) -{ - glGetIntegerv(GL_VIEWPORT, coords); -} +/** \} */ -void GPU_flush(void) +/* -------------------------------------------------------------------- */ +/** \name State Getters + * \{ */ + +eGPUBlend GPU_blend_get() { - glFlush(); + GPUState &state = GPU_context_active_get()->state_manager->state; + return (eGPUBlend)state.blend; } -void GPU_finish(void) +eGPUWriteMask GPU_write_mask_get() { - glFinish(); + GPUState &state = GPU_context_active_get()->state_manager->state; + return (eGPUWriteMask)state.write_mask; } -void GPU_unpack_row_length_set(uint len) +uint GPU_stencil_mask_get() { - glPixelStorei(GL_UNPACK_ROW_LENGTH, len); + GPUStateMutable &state = GPU_context_active_get()->state_manager->mutable_state; + return state.stencil_write_mask; } -void GPU_logic_op_xor_set(bool enable) +eGPUDepthTest GPU_depth_test_get() { - if (enable) { - glLogicOp(GL_XOR); - glEnable(GL_COLOR_LOGIC_OP); - } - else { - glDisable(GL_COLOR_LOGIC_OP); - } + GPUState &state = GPU_context_active_get()->state_manager->state; + return (eGPUDepthTest)state.depth_test; } -void GPU_color_mask(bool r, bool g, bool b, bool a) +eGPUStencilTest GPU_stencil_test_get() { - glColorMask(r, g, b, a); + GPUState &state = GPU_context_active_get()->state_manager->state; + return (eGPUStencilTest)state.stencil_test; } -void GPU_depth_mask(bool depth) +void GPU_scissor_get(int coords[4]) { - glDepthMask(depth); + GPU_context_active_get()->active_fb->scissor_get(coords); } -bool GPU_depth_mask_get(void) +void GPU_viewport_size_get_f(float coords[4]) { - GLint mask; - glGetIntegerv(GL_DEPTH_WRITEMASK, &mask); - return mask == GL_TRUE; + int viewport[4]; + GPU_context_active_get()->active_fb->viewport_get(viewport); + for (int i = 0; i < 4; i++) { + coords[i] = viewport[i]; + } } -void GPU_stencil_mask(uint stencil) +void GPU_viewport_size_get_i(int coords[4]) { - glStencilMask(stencil); + GPU_context_active_get()->active_fb->viewport_get(coords); } -void GPU_clip_distances(int distances_new) +bool GPU_depth_mask_get(void) { - static int distances_enabled = 0; - for (int i = 0; i < distances_new; i++) { - glEnable(GL_CLIP_DISTANCE0 + i); - } - for (int i = distances_new; i < distances_enabled; i++) { - glDisable(GL_CLIP_DISTANCE0 + i); - } - distances_enabled = distances_new; + GPUState &state = GPU_context_active_get()->state_manager->state; + return (state.write_mask & GPU_WRITE_DEPTH) != 0; } bool GPU_mipmap_enabled(void) @@ -274,163 +288,61 @@ bool GPU_mipmap_enabled(void) return true; } -/** \name GPU Push/Pop State - * \{ */ - -#define STATE_STACK_DEPTH 16 - -typedef struct { - eGPUAttrMask mask; - - /* GL_BLEND_BIT */ - uint is_blend : 1; - - /* GL_DEPTH_BUFFER_BIT */ - uint is_depth_test : 1; - int depth_func; - double depth_clear_value; - bool depth_write_mask; - - /* GL_SCISSOR_BIT */ - int scissor_box[4]; - uint is_scissor_test : 1; - - /* GL_VIEWPORT_BIT */ - int viewport[4]; - double near_far[2]; -} GPUAttrValues; - -typedef struct { - GPUAttrValues attr_stack[STATE_STACK_DEPTH]; - uint top; -} GPUAttrStack; - -static GPUAttrStack state = { - {}, - 0, -}; +/** \} */ -#define AttrStack state -#define Attr state.attr_stack[state.top] +/* -------------------------------------------------------------------- */ +/** \name Context Utils + * \{ */ -/** - * Replacement for glPush/PopAttributes - * - * We don't need to cover all the options of legacy OpenGL - * but simply the ones used by Blender. - */ -void gpuPushAttr(eGPUAttrMask mask) +void GPU_flush(void) { - Attr.mask = mask; - - if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { - Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); - glGetIntegerv(GL_DEPTH_FUNC, &Attr.depth_func); - glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Attr.depth_clear_value); - glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Attr.depth_write_mask); - } - - if ((mask & GPU_SCISSOR_BIT) != 0) { - Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Attr.scissor_box); - } - - if ((mask & GPU_VIEWPORT_BIT) != 0) { - glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attr.near_far); - glGetIntegerv(GL_VIEWPORT, (GLint *)&Attr.viewport); - } - - if ((mask & GPU_BLEND_BIT) != 0) { - Attr.is_blend = glIsEnabled(GL_BLEND); - } - - BLI_assert(AttrStack.top < STATE_STACK_DEPTH); - AttrStack.top++; + glFlush(); } -static void restore_mask(GLenum cap, const bool value) +void GPU_finish(void) { - if (value) { - glEnable(cap); - } - else { - glDisable(cap); - } + glFinish(); } -void gpuPopAttr(void) +void GPU_unpack_row_length_set(uint len) { - BLI_assert(AttrStack.top > 0); - AttrStack.top--; - - GLint mask = Attr.mask; - - if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { - restore_mask(GL_DEPTH_TEST, Attr.is_depth_test); - glDepthFunc(Attr.depth_func); - glClearDepth(Attr.depth_clear_value); - glDepthMask(Attr.depth_write_mask); - } - - if ((mask & GPU_VIEWPORT_BIT) != 0) { - glViewport(Attr.viewport[0], Attr.viewport[1], Attr.viewport[2], Attr.viewport[3]); - glDepthRange(Attr.near_far[0], Attr.near_far[1]); - } - - if ((mask & GPU_SCISSOR_BIT) != 0) { - restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test); - glScissor(Attr.scissor_box[0], Attr.scissor_box[1], Attr.scissor_box[2], Attr.scissor_box[3]); - } - - if ((mask & GPU_BLEND_BIT) != 0) { - restore_mask(GL_BLEND, Attr.is_blend); - } + glPixelStorei(GL_UNPACK_ROW_LENGTH, len); } -#undef Attr -#undef AttrStack +/** \} */ -/* Default OpenGL State +/* -------------------------------------------------------------------- */ +/** \name Default OpenGL State * * This is called on startup, for opengl offscreen render. * Generally we should always return to this state when * temporarily modifying the state for drawing, though that are (undocumented) - * exceptions that we should try to get rid of. */ - -void GPU_state_init(void) -{ - GPU_program_point_size(false); - - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glDisable(GL_COLOR_LOGIC_OP); - glDisable(GL_STENCIL_TEST); - glDisable(GL_DITHER); - - glDepthFunc(GL_LEQUAL); - glDepthRange(0.0, 1.0); - - glFrontFace(GL_CCW); - glCullFace(GL_BACK); - glDisable(GL_CULL_FACE); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - /* Is default but better be explicit. */ - glEnable(GL_MULTISAMPLE); - - /* This is a bit dangerous since addons could change this. */ - glEnable(GL_PRIMITIVE_RESTART); - glPrimitiveRestartIndex((GLuint)0xFFFFFFFF); + * exceptions that we should try to get rid of. + * \{ */ - /* TODO: Should become default. But needs at least GL 4.3 */ - if (GLEW_ARB_ES3_compatibility) { - /* Takes predecence over GL_PRIMITIVE_RESTART */ - glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); - } +GPUStateManager::GPUStateManager(void) +{ + /* Set default state. */ + state.write_mask = GPU_WRITE_COLOR; + state.blend = GPU_BLEND_NONE; + state.culling_test = GPU_CULL_NONE; + state.depth_test = GPU_DEPTH_NONE; + state.stencil_test = GPU_STENCIL_NONE; + state.stencil_op = GPU_STENCIL_OP_NONE; + state.provoking_vert = GPU_VERTEX_LAST; + state.logic_op_xor = false; + state.invert_facing = false; + state.shadow_bias = false; + state.polygon_smooth = false; + state.clip_distances = 0; + + mutable_state.depth_range[0] = 0.0f; + mutable_state.depth_range[1] = 1.0f; + mutable_state.point_size = 1.0f; + mutable_state.line_width = 1.0f; + mutable_state.stencil_write_mask = 0x00; + mutable_state.stencil_compare_mask = 0x00; + mutable_state.stencil_reference = 0x00; } /** \} */ |