Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpu/intern/gpu_state.cc')
-rw-r--r--source/blender/gpu/intern/gpu_state.cc468
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;
}
/** \} */