GPUState: Make use of GPUStateStack class

This isolate most GL calls to the GL backend. Still a few remains.
This commit is contained in:
Clément Foucault 2020-08-16 20:56:39 +02:00
parent 298329554a
commit f30df15edc
Notes: blender-bot 2023-02-14 05:50:03 +01:00
Referenced by issue #79899, viewport artifacts when sculpting with AA
8 changed files with 180 additions and 133 deletions

View File

@ -20,6 +20,8 @@
#pragma once
#include "BLI_utildefines.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -33,6 +35,8 @@ typedef enum eGPUWriteMask {
GPU_WRITE_COLOR = (GPU_WRITE_RED | GPU_WRITE_GREEN | GPU_WRITE_BLUE | GPU_WRITE_ALPHA),
} eGPUWriteMask;
ENUM_OPERATORS(eGPUWriteMask)
/**
* Defines the fixed pipeline blending equation.
* SRC is the output color from the shader.
@ -126,7 +130,6 @@ void GPU_viewport_size_get_i(int coords[4]);
void GPU_color_mask(bool r, bool g, bool b, bool a);
void GPU_depth_mask(bool depth);
bool GPU_depth_mask_get(void);
void GPU_stencil_mask(uint stencil);
void GPU_unpack_row_length_set(uint len);
void GPU_clip_distances(int enabled_len);
bool GPU_mipmap_enabled(void);

View File

@ -70,6 +70,7 @@ GPUContext::GPUContext()
GPUContext::~GPUContext()
{
GPU_matrix_state_discard(matrix_state);
delete state_stack;
}
bool GPUContext::is_active_on_thread(void)

View File

@ -29,6 +29,8 @@
#include "GPU_context.h"
#include "gpu_state_private.hh"
#include <mutex>
#include <pthread.h>
#include <string.h>
@ -44,6 +46,7 @@ struct GPUContext {
GPUShader *shader = NULL;
GPUFrameBuffer *current_fbo = NULL;
GPUMatrixState *matrix_state = NULL;
blender::gpu::GPUStateStack *state_stack = NULL;
protected:
/** Thread on which this context is active. */

View File

@ -25,6 +25,7 @@
# define PIXELSIZE (1.0f)
#endif
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
@ -33,6 +34,8 @@
#include "GPU_glew.h"
#include "GPU_state.h"
#include "gpu_context_private.hh"
#include "gpu_state_private.hh"
/* TODO remove */
@ -40,194 +43,198 @@
using namespace blender::gpu;
#define SET_STATE(_prefix, _state, _value) \
do { \
GPUStateStack *stack = GPU_context_active_get()->state_stack; \
auto &state_object = stack->_prefix##stack_top_get(); \
state_object._state = _value; \
/* TODO remove this and only push state at draw time. */ \
stack->set_##_prefix##state(state_object); \
} 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)
{
GLStateStack::set_blend(blend);
SET_IMMUTABLE_STATE(blend, blend);
}
void GPU_face_culling(eGPUFaceCullTest culling)
{
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(culling_test, culling);
}
void GPU_front_facing(bool invert)
{
glFrontFace((invert) ? GL_CW : GL_CCW);
SET_IMMUTABLE_STATE(invert_facing, invert);
}
void GPU_provoking_vertex(eGPUProvokingVertex vert)
{
glProvokingVertex((vert == GPU_VERTEX_FIRST) ? GL_FIRST_VERTEX_CONVENTION :
GL_LAST_VERTEX_CONVENTION);
}
void GPU_depth_range(float near, float far)
{
/* glDepthRangef is only for OpenGL 4.1 or higher */
glDepthRange(near, far);
SET_IMMUTABLE_STATE(provoking_vert, vert);
}
/* TODO explicit depth test. */
void GPU_depth_test(bool enable)
{
if (enable) {
glEnable(GL_DEPTH_TEST);
}
else {
glDisable(GL_DEPTH_TEST);
}
}
bool GPU_depth_test_enabled()
{
return glIsEnabled(GL_DEPTH_TEST);
SET_IMMUTABLE_STATE(depth_test, (enable) ? GPU_DEPTH_LESS : GPU_DEPTH_NONE);
}
void GPU_line_smooth(bool enable)
{
if (enable && ((G.debug & G_DEBUG_GPU) == 0)) {
glEnable(GL_LINE_SMOOTH);
}
else {
glDisable(GL_LINE_SMOOTH);
}
}
void GPU_line_width(float width)
{
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);
}
void GPU_point_size(float size)
{
glPointSize(size * PIXELSIZE);
SET_IMMUTABLE_STATE(line_smooth, enable);
}
void GPU_polygon_smooth(bool enable)
{
if (enable && ((G.debug & G_DEBUG_GPU) == 0)) {
glEnable(GL_POLYGON_SMOOTH);
}
else {
glDisable(GL_POLYGON_SMOOTH);
}
SET_IMMUTABLE_STATE(polygon_smooth, enable);
}
void GPU_logic_op_xor_set(bool enable)
{
SET_IMMUTABLE_STATE(logic_op_xor, enable);
}
void GPU_color_mask(bool r, bool g, bool b, bool a)
{
GPUStateStack *stack = GPU_context_active_get()->state_stack;
auto &state = stack->stack_top_get();
eGPUWriteMask write_mask = state.write_mask;
SET_FLAG_FROM_TEST(write_mask, r, GPU_WRITE_RED);
SET_FLAG_FROM_TEST(write_mask, g, GPU_WRITE_GREEN);
SET_FLAG_FROM_TEST(write_mask, b, GPU_WRITE_BLUE);
SET_FLAG_FROM_TEST(write_mask, a, GPU_WRITE_ALPHA);
state.write_mask = write_mask;
/* TODO remove this and only push state at draw time. */
stack->set_state(state);
}
void GPU_depth_mask(bool depth)
{
GPUStateStack *stack = GPU_context_active_get()->state_stack;
auto &state = stack->stack_top_get();
eGPUWriteMask write_mask = state.write_mask;
SET_FLAG_FROM_TEST(write_mask, depth, GPU_WRITE_DEPTH);
state.write_mask = write_mask;
/* TODO remove this and only push state at draw time. */
stack->set_state(state);
}
void GPU_clip_distances(int distances_enabled)
{
SET_IMMUTABLE_STATE(clip_distances, distances_enabled);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mutable State Setters
* \{ */
void GPU_depth_range(float near, float far)
{
GPUStateStack *stack = GPU_context_active_get()->state_stack;
auto &state = stack->mutable_stack_top_get();
copy_v2_fl2(state.depth_range, near, far);
/* TODO remove this and only push state at draw time. */
stack->set_mutable_state(state);
}
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);
}
GPUStateStack *stack = GPU_context_active_get()->state_stack;
auto &state = stack->mutable_stack_top_get();
/* Set point size sign negative to disable. */
state.point_size = fabsf(state.point_size) * (enable ? 1 : -1);
/* TODO remove this and only push state at draw time. */
stack->set_mutable_state(state);
}
void GPU_scissor_test(bool enable)
{
if (enable) {
glEnable(GL_SCISSOR_TEST);
}
else {
glDisable(GL_SCISSOR_TEST);
}
GPUStateStack *stack = GPU_context_active_get()->state_stack;
auto &state = stack->mutable_stack_top_get();
/* Set point size sign negative to disable. */
state.scissor_rect[2] = abs(state.scissor_rect[2]) * (enable ? 1 : -1);
/* TODO remove this and only push state at draw time. */
stack->set_mutable_state(state);
}
void GPU_scissor(int x, int y, int width, int height)
{
glScissor(x, y, width, height);
GPUStateStack *stack = GPU_context_active_get()->state_stack;
auto &state = stack->mutable_stack_top_get();
int scissor_rect[4] = {x, y, width, height};
copy_v4_v4_int(state.scissor_rect, scissor_rect);
/* TODO remove this and only push state at draw time. */
stack->set_mutable_state(state);
}
void GPU_viewport(int x, int y, int width, int height)
{
glViewport(x, y, width, height);
GPUStateStack *stack = GPU_context_active_get()->state_stack;
auto &state = stack->mutable_stack_top_get();
int viewport_rect[4] = {x, y, width, height};
copy_v4_v4_int(state.viewport_rect, viewport_rect);
/* TODO remove this and only push state at draw time. */
stack->set_mutable_state(state);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name State Getters
* \{ */
bool GPU_depth_test_enabled()
{
GPUState &state = GPU_context_active_get()->state_stack->stack_top_get();
return state.depth_test != GPU_DEPTH_NONE;
}
void GPU_scissor_get(int coords[4])
{
glGetIntegerv(GL_SCISSOR_BOX, coords);
GPUStateMutable &state = GPU_context_active_get()->state_stack->mutable_stack_top_get();
copy_v4_v4_int(coords, state.scissor_rect);
}
void GPU_viewport_size_get_f(float coords[4])
{
glGetFloatv(GL_VIEWPORT, coords);
GPUStateMutable &state = GPU_context_active_get()->state_stack->mutable_stack_top_get();
for (int i = 0; i < 4; i++) {
coords[i] = state.viewport_rect[i];
}
}
void GPU_viewport_size_get_i(int coords[4])
{
glGetIntegerv(GL_VIEWPORT, coords);
}
void GPU_flush(void)
{
glFlush();
}
void GPU_finish(void)
{
glFinish();
}
void GPU_unpack_row_length_set(uint len)
{
glPixelStorei(GL_UNPACK_ROW_LENGTH, len);
}
void GPU_logic_op_xor_set(bool enable)
{
if (enable) {
glLogicOp(GL_XOR);
glEnable(GL_COLOR_LOGIC_OP);
}
else {
glDisable(GL_COLOR_LOGIC_OP);
}
}
void GPU_color_mask(bool r, bool g, bool b, bool a)
{
glColorMask(r, g, b, a);
}
void GPU_depth_mask(bool depth)
{
glDepthMask(depth);
GPUStateMutable &state = GPU_context_active_get()->state_stack->mutable_stack_top_get();
copy_v4_v4_int(coords, state.viewport_rect);
}
bool GPU_depth_mask_get(void)
{
GLint mask;
glGetIntegerv(GL_DEPTH_WRITEMASK, &mask);
return mask == GL_TRUE;
}
void GPU_stencil_mask(uint stencil)
{
glStencilMask(stencil);
}
void GPU_clip_distances(int distances_new)
{
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_stack->stack_top_get();
return (state.write_mask & GPU_WRITE_DEPTH) != 0;
}
bool GPU_mipmap_enabled(void)
@ -236,8 +243,10 @@ bool GPU_mipmap_enabled(void)
return true;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Draw State (DRW_state)
/** \name GPUStateStack
* \{ */
void GPUStateStack::push_stack(void)
@ -264,6 +273,27 @@ void GPUStateStack::pop_mutable_stack(void)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Context Utils
* \{ */
void GPU_flush(void)
{
glFlush();
}
void GPU_finish(void)
{
glFinish();
}
void GPU_unpack_row_length_set(uint len)
{
glPixelStorei(GL_UNPACK_ROW_LENGTH, len);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name GPU Push/Pop State
* \{ */

View File

@ -137,6 +137,8 @@ class GPUStateStack {
int mutable_stack_top = 0;
public:
virtual ~GPUStateStack(){};
virtual void set_state(GPUState &state) = 0;
virtual void set_mutable_state(GPUStateMutable &state) = 0;

View File

@ -30,6 +30,8 @@
#include "gpu_context_private.hh"
#include "gl_state.hh"
#include "gl_backend.hh" /* TODO remove */
#include "gl_context.hh"
@ -54,6 +56,8 @@ GLContext::GLContext(void *ghost_window, GLSharedOrphanLists &shared_orphan_list
glBindBuffer(GL_ARRAY_BUFFER, default_attr_vbo_);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
state_stack = new GLStateStack();
}
GLContext::~GLContext()

View File

@ -41,6 +41,9 @@ void GLStateStack::set_state(GPUState &state)
{
GPUState changed = state ^ current_;
if (changed.blend != 0) {
set_blend(state.blend);
}
if (changed.write_mask != 0) {
set_write_mask(state.write_mask);
}
@ -101,10 +104,7 @@ void GLStateStack::set_mutable_state(GPUStateMutable &state)
(changed.scissor_rect[2] != 0) || (changed.scissor_rect[3] != 0)) {
glScissor(UNPACK4(state.scissor_rect));
if ((state.scissor_rect[0] != state.viewport_rect[0]) ||
(state.scissor_rect[1] != state.viewport_rect[1]) ||
(state.scissor_rect[2] != state.viewport_rect[2]) ||
(state.scissor_rect[3] != state.viewport_rect[3])) {
if ((state.scissor_rect[2] > 0)) {
glEnable(GL_SCISSOR_TEST);
}
else {

View File

@ -20,6 +20,8 @@
* \ingroup gpu
*/
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "gpu_state_private.hh"
@ -52,6 +54,8 @@ class GLStateStack : public GPUStateStack {
static void set_provoking_vert(const eGPUProvokingVertex vert);
static void set_shadow_bias(const bool enable);
static void set_blend(const eGPUBlend value);
MEM_CXX_CLASS_ALLOC_FUNCS("GLStateStack")
};
} // namespace gpu