GPUState: Add GL backend and state tracking but do not use it
This is just the backend work. It is not plugged in yet because it needs more external cleanup/refactor.
This commit is contained in:
parent
2eddfa85e0
commit
2ae1c895a2
|
@ -93,6 +93,7 @@ set(SRC
|
|||
opengl/gl_context.cc
|
||||
opengl/gl_drawlist.cc
|
||||
opengl/gl_shader.cc
|
||||
opengl/gl_state.cc
|
||||
opengl/gl_vertex_array.cc
|
||||
|
||||
GPU_attr_binding.h
|
||||
|
@ -139,6 +140,7 @@ set(SRC
|
|||
intern/gpu_private.h
|
||||
intern/gpu_select_private.h
|
||||
intern/gpu_shader_private.hh
|
||||
intern/gpu_state_private.hh
|
||||
intern/gpu_vertex_format_private.h
|
||||
|
||||
opengl/gl_backend.hh
|
||||
|
@ -146,6 +148,7 @@ set(SRC
|
|||
opengl/gl_context.hh
|
||||
opengl/gl_drawlist.hh
|
||||
opengl/gl_shader.hh
|
||||
opengl/gl_state.hh
|
||||
opengl/gl_vertex_array.hh
|
||||
)
|
||||
|
||||
|
|
|
@ -112,15 +112,6 @@ typedef enum eGPUMatFlag {
|
|||
GPU_MATFLAG_BARYCENTRIC = (1 << 4),
|
||||
} eGPUMatFlag;
|
||||
|
||||
typedef enum eGPUBlendMode {
|
||||
GPU_BLEND_SOLID = 0,
|
||||
GPU_BLEND_ADD = 1,
|
||||
GPU_BLEND_ALPHA = 2,
|
||||
GPU_BLEND_CLIP = 4,
|
||||
GPU_BLEND_ALPHA_SORT = 8,
|
||||
GPU_BLEND_ALPHA_TO_COVERAGE = 16,
|
||||
} eGPUBlendMode;
|
||||
|
||||
typedef struct GPUNodeStack {
|
||||
eGPUType type;
|
||||
float vec[4];
|
||||
|
|
|
@ -24,6 +24,70 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum eGPUWriteMask {
|
||||
GPU_WRITE_RED = (1 << 0),
|
||||
GPU_WRITE_GREEN = (1 << 1),
|
||||
GPU_WRITE_BLUE = (1 << 2),
|
||||
GPU_WRITE_ALPHA = (1 << 3),
|
||||
GPU_WRITE_DEPTH = (1 << 4),
|
||||
GPU_WRITE_COLOR = (GPU_WRITE_RED | GPU_WRITE_GREEN | GPU_WRITE_BLUE | GPU_WRITE_ALPHA),
|
||||
} eGPUWriteMask;
|
||||
|
||||
/**
|
||||
* Defines the fixed pipeline blending equation.
|
||||
* SRC is the output color from the shader.
|
||||
* DST is the color from the framebuffer.
|
||||
* The blending equation is :
|
||||
* (SRC * A) + (DST * B).
|
||||
* The blend mode will modify the A and B parameters.
|
||||
*/
|
||||
typedef enum eGPUBlend {
|
||||
GPU_BLEND_NONE = 0,
|
||||
/** Premult variants will _NOT_ multiply rgb output by alpha. */
|
||||
GPU_BLEND_ALPHA,
|
||||
GPU_BLEND_ALPHA_PREMULT,
|
||||
GPU_BLEND_ADDITIVE,
|
||||
GPU_BLEND_ADDITIVE_PREMULT,
|
||||
GPU_BLEND_MULTIPLY,
|
||||
GPU_BLEND_SUBTRACT,
|
||||
/** Replace logic op: SRC * (1 - DST)
|
||||
* NOTE: Does not modify alpha. */
|
||||
GPU_BLEND_INVERT,
|
||||
/** Order independant transparency.
|
||||
* NOTE: Cannot be used as is. Needs special setup (framebuffer, shader ...). */
|
||||
GPU_BLEND_OIT,
|
||||
/** Special blend to add color under and multiply dst color by src alpha. */
|
||||
GPU_BLEND_BACKGROUND,
|
||||
/** Custom blend parameters using dual source blending : SRC0 + SRC1 * DST
|
||||
* NOTE: Can only be used with _ONE_ Draw Buffer and shader needs to be specialized. */
|
||||
GPU_BLEND_CUSTOM,
|
||||
} eGPUBlend;
|
||||
|
||||
typedef enum eGPUDepthTest {
|
||||
GPU_DEPTH_NONE = 0,
|
||||
GPU_DEPTH_ALWAYS,
|
||||
GPU_DEPTH_LESS,
|
||||
GPU_DEPTH_LESS_EQUAL,
|
||||
GPU_DEPTH_EQUAL,
|
||||
GPU_DEPTH_GREATER,
|
||||
GPU_DEPTH_GREATER_EQUAL,
|
||||
} eGPUDepthTest;
|
||||
|
||||
typedef enum eGPUStencilTest {
|
||||
GPU_STENCIL_NONE = 0,
|
||||
GPU_STENCIL_ALWAYS,
|
||||
GPU_STENCIL_EQUAL,
|
||||
GPU_STENCIL_NEQUAL,
|
||||
} eGPUStencilTest;
|
||||
|
||||
typedef enum eGPUStencilOp {
|
||||
GPU_STENCIL_OP_NONE = 0,
|
||||
GPU_STENCIL_OP_REPLACE,
|
||||
/** Special values for stencil shadows. */
|
||||
GPU_STENCIL_OP_COUNT_DEPTH_PASS,
|
||||
GPU_STENCIL_OP_COUNT_DEPTH_FAIL,
|
||||
} eGPUStencilOp;
|
||||
|
||||
/* These map directly to the GL_ blend functions, to minimize API add as needed*/
|
||||
typedef enum eGPUBlendFunction {
|
||||
GPU_ONE,
|
||||
|
@ -33,21 +97,15 @@ typedef enum eGPUBlendFunction {
|
|||
GPU_ZERO,
|
||||
} eGPUBlendFunction;
|
||||
|
||||
/* These map directly to the GL_ filter functions, to minimize API add as needed*/
|
||||
typedef enum eGPUFilterFunction {
|
||||
GPU_NEAREST,
|
||||
GPU_LINEAR,
|
||||
} eGPUFilterFunction;
|
||||
|
||||
typedef enum eGPUFaceCull {
|
||||
typedef enum eGPUFaceCullTest {
|
||||
GPU_CULL_NONE = 0, /* Culling disabled. */
|
||||
GPU_CULL_FRONT,
|
||||
GPU_CULL_BACK,
|
||||
} eGPUFaceCull;
|
||||
} eGPUFaceCullTest;
|
||||
|
||||
typedef enum eGPUProvokingVertex {
|
||||
GPU_VERTEX_FIRST = 0,
|
||||
GPU_VERTEX_LAST, /* Default */
|
||||
GPU_VERTEX_LAST = 0, /* Default. */
|
||||
GPU_VERTEX_FIRST = 1, /* Follow Blender loop order. */
|
||||
} eGPUProvokingVertex;
|
||||
|
||||
/* Initialize
|
||||
|
@ -62,7 +120,7 @@ void GPU_blend_set_func_separate(eGPUBlendFunction src_rgb,
|
|||
eGPUBlendFunction dst_rgb,
|
||||
eGPUBlendFunction src_alpha,
|
||||
eGPUBlendFunction dst_alpha);
|
||||
void GPU_face_culling(eGPUFaceCull culling);
|
||||
void GPU_face_culling(eGPUFaceCullTest culling);
|
||||
void GPU_front_facing(bool invert);
|
||||
void GPU_provoking_vertex(eGPUProvokingVertex vert);
|
||||
void GPU_depth_range(float near, float far);
|
||||
|
|
|
@ -33,6 +33,10 @@
|
|||
#include "GPU_glew.h"
|
||||
#include "GPU_state.h"
|
||||
|
||||
#include "gpu_state_private.hh"
|
||||
|
||||
using namespace blender::gpu;
|
||||
|
||||
static GLenum gpu_get_gl_blendfunction(eGPUBlendFunction blend)
|
||||
{
|
||||
switch (blend) {
|
||||
|
@ -78,7 +82,7 @@ void GPU_blend_set_func_separate(eGPUBlendFunction src_rgb,
|
|||
gpu_get_gl_blendfunction(dst_alpha));
|
||||
}
|
||||
|
||||
void GPU_face_culling(eGPUFaceCull culling)
|
||||
void GPU_face_culling(eGPUFaceCullTest culling)
|
||||
{
|
||||
if (culling == GPU_CULL_NONE) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
@ -269,6 +273,35 @@ bool GPU_mipmap_enabled(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Draw State (DRW_state)
|
||||
* \{ */
|
||||
|
||||
void GPUStateStack::push_stack(void)
|
||||
{
|
||||
stack[stack_top + 1] = stack[stack_top];
|
||||
stack_top++;
|
||||
}
|
||||
|
||||
void GPUStateStack::pop_stack(void)
|
||||
{
|
||||
stack_top--;
|
||||
}
|
||||
|
||||
void GPUStateStack::push_mutable_stack(void)
|
||||
{
|
||||
mutable_stack[mutable_stack_top + 1] = mutable_stack[mutable_stack_top];
|
||||
mutable_stack_top++;
|
||||
}
|
||||
|
||||
void GPUStateStack::pop_mutable_stack(void)
|
||||
{
|
||||
mutable_stack_top--;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name GPU Push/Pop State
|
||||
* \{ */
|
||||
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2020, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "GPU_state.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace blender {
|
||||
namespace gpu {
|
||||
|
||||
/* Ecapsulate all pipeline state that we need to track.
|
||||
* Try to keep small to reduce validation time. */
|
||||
union GPUState {
|
||||
struct {
|
||||
eGPUWriteMask write_mask : 13;
|
||||
eGPUBlend blend : 4;
|
||||
eGPUFaceCullTest culling_test : 2;
|
||||
eGPUDepthTest depth_test : 3;
|
||||
eGPUStencilTest stencil_test : 3;
|
||||
eGPUStencilOp stencil_op : 3;
|
||||
eGPUProvokingVertex provoking_vert : 1;
|
||||
/** Enable bits. */
|
||||
uint32_t logic_op_xor : 1;
|
||||
uint32_t invert_facing : 1;
|
||||
uint32_t shadow_bias : 1;
|
||||
/** Number of clip distances enabled. */
|
||||
/* TODO(fclem) This should be a shader property. */
|
||||
uint32_t clip_distances : 3;
|
||||
/* TODO(fclem) remove, old opengl features. */
|
||||
uint32_t polygon_smooth : 1;
|
||||
uint32_t line_smooth : 1;
|
||||
};
|
||||
/* Here to allow fast bitwise ops. */
|
||||
uint64_t data;
|
||||
};
|
||||
|
||||
BLI_STATIC_ASSERT(sizeof(GPUState) == sizeof(uint64_t), "GPUState is too big.");
|
||||
|
||||
inline bool operator==(const GPUState &a, const GPUState &b)
|
||||
{
|
||||
return a.data == b.data;
|
||||
}
|
||||
|
||||
inline bool operator!=(const GPUState &a, const GPUState &b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline GPUState operator^(const GPUState &a, const GPUState &b)
|
||||
{
|
||||
GPUState r;
|
||||
r.data = a.data ^ b.data;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Mutable state that does not require pipeline change. */
|
||||
union GPUStateMutable {
|
||||
struct {
|
||||
/** Offset + Extent of the drawable region inside the framebuffer. */
|
||||
int viewport_rect[4];
|
||||
/** Offset + Extent of the scissor region inside the framebuffer. */
|
||||
int scissor_rect[4];
|
||||
/** TODO remove */
|
||||
float depth_range[2];
|
||||
/** TODO remove, use explicit clear calls. */
|
||||
float clear_color[4];
|
||||
float clear_depth;
|
||||
/** Negative if using program point size. */
|
||||
/* TODO(fclem) should be passed as uniform to all shaders. */
|
||||
float point_size;
|
||||
/** Not supported on every platform. Prefer using wideline shader. */
|
||||
float line_width;
|
||||
/** Mutable stencil states. */
|
||||
uint8_t stencil_write_mask;
|
||||
uint8_t stencil_compare_mask;
|
||||
uint8_t stencil_reference;
|
||||
uint8_t _pad0;
|
||||
/* IMPORTANT: ensure x64 stuct alignment. */
|
||||
};
|
||||
/* Here to allow fast bitwise ops. */
|
||||
uint64_t data[9];
|
||||
};
|
||||
|
||||
BLI_STATIC_ASSERT(sizeof(GPUStateMutable) == sizeof(GPUStateMutable::data),
|
||||
"GPUStateMutable is too big.");
|
||||
|
||||
inline bool operator==(const GPUStateMutable &a, const GPUStateMutable &b)
|
||||
{
|
||||
return memcmp(&a, &b, sizeof(GPUStateMutable)) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const GPUStateMutable &a, const GPUStateMutable &b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline GPUStateMutable operator^(const GPUStateMutable &a, const GPUStateMutable &b)
|
||||
{
|
||||
GPUStateMutable r;
|
||||
for (int i = 0; i < ARRAY_SIZE(a.data); i++) {
|
||||
r.data[i] = a.data[i] ^ b.data[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#define GPU_STATE_STACK_LEN 4
|
||||
|
||||
class GPUStateStack {
|
||||
private:
|
||||
/** Stack of state for quick temporary modification of the state. */
|
||||
GPUState stack[GPU_STATE_STACK_LEN];
|
||||
GPUStateMutable mutable_stack[GPU_STATE_STACK_LEN];
|
||||
int stack_top = 0;
|
||||
int mutable_stack_top = 0;
|
||||
|
||||
public:
|
||||
virtual void set_state(GPUState &state) = 0;
|
||||
virtual void set_mutable_state(GPUStateMutable &state) = 0;
|
||||
|
||||
void push_stack(void);
|
||||
void pop_stack(void);
|
||||
|
||||
void push_mutable_stack(void);
|
||||
void pop_mutable_stack(void);
|
||||
|
||||
inline GPUState &stack_top_get(void);
|
||||
inline GPUStateMutable &mutable_stack_top_get(void);
|
||||
};
|
||||
|
||||
inline GPUState &GPUStateStack::stack_top_get(void)
|
||||
{
|
||||
return stack[stack_top];
|
||||
}
|
||||
|
||||
inline GPUStateMutable &GPUStateStack::mutable_stack_top_get(void)
|
||||
{
|
||||
return mutable_stack[mutable_stack_top];
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
} // namespace blender
|
|
@ -0,0 +1,389 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2020, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_state.h"
|
||||
|
||||
#include "gl_state.hh"
|
||||
|
||||
using namespace blender::gpu;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name GLStateStack
|
||||
* \{ */
|
||||
|
||||
void GLStateStack::set_state(GPUState &state)
|
||||
{
|
||||
GPUState changed = state ^ current_;
|
||||
|
||||
if (changed.write_mask != 0) {
|
||||
set_write_mask(state.write_mask);
|
||||
}
|
||||
if (changed.depth_test != 0) {
|
||||
set_depth_test(state.depth_test);
|
||||
}
|
||||
if (changed.stencil_test != 0 || changed.stencil_op != 0) {
|
||||
set_stencil_test(state.stencil_test, state.stencil_op);
|
||||
set_stencil_mask(state.stencil_test, mutable_stack_top_get());
|
||||
}
|
||||
if (changed.clip_distances != 0) {
|
||||
set_clip_distances(state.clip_distances, current_.clip_distances);
|
||||
}
|
||||
if (changed.culling_test != 0) {
|
||||
set_backface_culling(state.culling_test);
|
||||
}
|
||||
if (changed.logic_op_xor != 0) {
|
||||
set_logic_op(state.logic_op_xor);
|
||||
}
|
||||
if (changed.invert_facing != 0) {
|
||||
set_facing(state.invert_facing);
|
||||
}
|
||||
if (changed.provoking_vert != 0) {
|
||||
set_provoking_vert(state.provoking_vert);
|
||||
}
|
||||
if (changed.shadow_bias != 0) {
|
||||
set_shadow_bias(state.shadow_bias);
|
||||
}
|
||||
|
||||
/* TODO remove */
|
||||
if (changed.polygon_smooth) {
|
||||
if (state.polygon_smooth) {
|
||||
glEnable(GL_POLYGON_SMOOTH);
|
||||
}
|
||||
else {
|
||||
glDisable(GL_POLYGON_SMOOTH);
|
||||
}
|
||||
}
|
||||
if (changed.line_smooth) {
|
||||
if (state.line_smooth) {
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
}
|
||||
else {
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
}
|
||||
}
|
||||
|
||||
current_ = state;
|
||||
}
|
||||
|
||||
void GLStateStack::set_mutable_state(GPUStateMutable &state)
|
||||
{
|
||||
GPUStateMutable changed = state ^ current_mutable_;
|
||||
|
||||
glViewport(UNPACK4(state.viewport_rect));
|
||||
|
||||
if ((changed.scissor_rect[0] != 0) || (changed.scissor_rect[1] != 0) ||
|
||||
(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])) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
else {
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO remove, should be uniform. */
|
||||
if (state.point_size > 0.0f) {
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
glPointSize(state.point_size);
|
||||
}
|
||||
else {
|
||||
glDisable(GL_PROGRAM_POINT_SIZE);
|
||||
}
|
||||
|
||||
if (changed.line_width != 0) {
|
||||
/* TODO remove, should use wide line shader. */
|
||||
glLineWidth(clamp_f(state.line_width, 1.0f, GPU_max_line_width()));
|
||||
}
|
||||
|
||||
if (changed.depth_range[0] != 0 || changed.depth_range[1] != 0) {
|
||||
/* TODO remove, should modify the projection matrix instead. */
|
||||
glDepthRange(UNPACK2(state.depth_range));
|
||||
}
|
||||
|
||||
if (changed.stencil_compare_mask != 0 || changed.stencil_reference != 0 ||
|
||||
changed.stencil_write_mask != 0) {
|
||||
set_stencil_mask(current_.stencil_test, state);
|
||||
}
|
||||
|
||||
current_mutable_ = state;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name State set functions
|
||||
* \{ */
|
||||
|
||||
void GLStateStack::set_write_mask(const eGPUWriteMask value)
|
||||
{
|
||||
glDepthMask((value & GPU_WRITE_DEPTH) != 0);
|
||||
glColorMask((value & GPU_WRITE_RED) != 0,
|
||||
(value & GPU_WRITE_GREEN) != 0,
|
||||
(value & GPU_WRITE_BLUE) != 0,
|
||||
(value & GPU_WRITE_ALPHA) != 0);
|
||||
}
|
||||
|
||||
void GLStateStack::set_depth_test(const eGPUDepthTest value)
|
||||
{
|
||||
GLenum func;
|
||||
switch (value) {
|
||||
case GPU_DEPTH_LESS:
|
||||
func = GL_LESS;
|
||||
break;
|
||||
case GPU_DEPTH_LESS_EQUAL:
|
||||
func = GL_LEQUAL;
|
||||
break;
|
||||
case GPU_DEPTH_EQUAL:
|
||||
func = GL_EQUAL;
|
||||
break;
|
||||
case GPU_DEPTH_GREATER:
|
||||
func = GL_GREATER;
|
||||
break;
|
||||
case GPU_DEPTH_GREATER_EQUAL:
|
||||
func = GL_GEQUAL;
|
||||
break;
|
||||
case GPU_DEPTH_ALWAYS:
|
||||
default:
|
||||
func = GL_ALWAYS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (value != GPU_DEPTH_NONE) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(func);
|
||||
}
|
||||
else {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
void GLStateStack::set_stencil_test(const eGPUStencilTest test, const eGPUStencilOp operation)
|
||||
{
|
||||
switch (operation) {
|
||||
case GPU_STENCIL_OP_REPLACE:
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||
break;
|
||||
case GPU_STENCIL_OP_COUNT_DEPTH_PASS:
|
||||
glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
|
||||
glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
|
||||
break;
|
||||
case GPU_STENCIL_OP_COUNT_DEPTH_FAIL:
|
||||
glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_KEEP);
|
||||
glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_KEEP);
|
||||
break;
|
||||
case GPU_STENCIL_OP_NONE:
|
||||
default:
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
}
|
||||
|
||||
if (test != GPU_STENCIL_NONE) {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
}
|
||||
else {
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
void GLStateStack::set_stencil_mask(const eGPUStencilTest test, const GPUStateMutable state)
|
||||
{
|
||||
GLenum func;
|
||||
switch (test) {
|
||||
case GPU_STENCIL_NEQUAL:
|
||||
func = GL_NOTEQUAL;
|
||||
break;
|
||||
case GPU_STENCIL_EQUAL:
|
||||
func = GL_EQUAL;
|
||||
break;
|
||||
case GPU_STENCIL_ALWAYS:
|
||||
func = GL_ALWAYS;
|
||||
break;
|
||||
case GPU_STENCIL_NONE:
|
||||
default:
|
||||
glStencilMask(0x00);
|
||||
glStencilFunc(GL_ALWAYS, 0x00, 0x00);
|
||||
return;
|
||||
}
|
||||
|
||||
glStencilMask(state.stencil_write_mask);
|
||||
glStencilFunc(func, state.stencil_reference, state.stencil_compare_mask);
|
||||
}
|
||||
|
||||
void GLStateStack::set_clip_distances(const int new_dist_len, const int old_dist_len)
|
||||
{
|
||||
for (int i = 0; i < new_dist_len; i++) {
|
||||
glEnable(GL_CLIP_DISTANCE0 + i);
|
||||
}
|
||||
for (int i = new_dist_len; i < old_dist_len; i++) {
|
||||
glDisable(GL_CLIP_DISTANCE0 + i);
|
||||
}
|
||||
}
|
||||
|
||||
void GLStateStack::set_logic_op(const bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
glEnable(GL_COLOR_LOGIC_OP);
|
||||
glLogicOp(GL_XOR);
|
||||
}
|
||||
else {
|
||||
glDisable(GL_COLOR_LOGIC_OP);
|
||||
}
|
||||
}
|
||||
|
||||
void GLStateStack::set_facing(const bool invert)
|
||||
{
|
||||
glFrontFace((invert) ? GL_CW : GL_CCW);
|
||||
}
|
||||
|
||||
void GLStateStack::set_backface_culling(const eGPUFaceCullTest test)
|
||||
{
|
||||
if (test != GPU_CULL_NONE) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
else {
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace((test == GPU_CULL_FRONT) ? GL_FRONT : GL_BACK);
|
||||
}
|
||||
}
|
||||
|
||||
void GLStateStack::set_provoking_vert(const eGPUProvokingVertex vert)
|
||||
{
|
||||
GLenum value = (vert == GPU_VERTEX_FIRST) ? GL_FIRST_VERTEX_CONVENTION :
|
||||
GL_LAST_VERTEX_CONVENTION;
|
||||
glProvokingVertex(value);
|
||||
}
|
||||
|
||||
void GLStateStack::set_shadow_bias(const bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glEnable(GL_POLYGON_OFFSET_LINE);
|
||||
/* 2.0 Seems to be the lowest possible slope bias that works in every case. */
|
||||
glPolygonOffset(2.0f, 1.0f);
|
||||
}
|
||||
else {
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glDisable(GL_POLYGON_OFFSET_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
void GLStateStack::set_blend(const eGPUBlend value)
|
||||
{
|
||||
/**
|
||||
* Factors to the equation.
|
||||
* SRC is fragment shader output.
|
||||
* DST is framebuffer color.
|
||||
* final.rgb = SRC.rgb * src_rgb + DST.rgb * dst_rgb;
|
||||
* final.a = SRC.a * src_alpha + DST.a * dst_alpha;
|
||||
**/
|
||||
GLenum src_rgb, src_alpha, dst_rgb, dst_alpha;
|
||||
switch (value) {
|
||||
default:
|
||||
case GPU_BLEND_ALPHA: {
|
||||
src_rgb = GL_SRC_ALPHA;
|
||||
dst_rgb = GL_ONE_MINUS_SRC_ALPHA;
|
||||
src_alpha = GL_ONE;
|
||||
dst_alpha = GL_ONE_MINUS_SRC_ALPHA;
|
||||
break;
|
||||
}
|
||||
case GPU_BLEND_ALPHA_PREMULT: {
|
||||
src_rgb = GL_ONE;
|
||||
dst_rgb = GL_ONE_MINUS_SRC_ALPHA;
|
||||
src_alpha = GL_ONE;
|
||||
dst_alpha = GL_ONE_MINUS_SRC_ALPHA;
|
||||
break;
|
||||
}
|
||||
case GPU_BLEND_ADDITIVE: {
|
||||
/* Do not let alpha accumulate but premult the source RGB by it. */
|
||||
src_rgb = GL_SRC_ALPHA;
|
||||
dst_rgb = GL_ONE;
|
||||
src_alpha = GL_ZERO;
|
||||
dst_alpha = GL_ONE;
|
||||
break;
|
||||
}
|
||||
case GPU_BLEND_SUBTRACT:
|
||||
case GPU_BLEND_ADDITIVE_PREMULT: {
|
||||
/* Let alpha accumulate. */
|
||||
src_rgb = GL_ONE;
|
||||
dst_rgb = GL_ONE;
|
||||
src_alpha = GL_ONE;
|
||||
dst_alpha = GL_ONE;
|
||||
break;
|
||||
}
|
||||
case GPU_BLEND_MULTIPLY: {
|
||||
src_rgb = GL_DST_COLOR;
|
||||
dst_rgb = GL_ZERO;
|
||||
src_alpha = GL_DST_ALPHA;
|
||||
dst_alpha = GL_ZERO;
|
||||
break;
|
||||
}
|
||||
case GPU_BLEND_INVERT: {
|
||||
src_rgb = GL_ONE_MINUS_DST_COLOR;
|
||||
dst_rgb = GL_ZERO;
|
||||
src_alpha = GL_ZERO;
|
||||
dst_alpha = GL_ONE;
|
||||
break;
|
||||
}
|
||||
case GPU_BLEND_OIT: {
|
||||
src_rgb = GL_ONE;
|
||||
dst_rgb = GL_ONE;
|
||||
src_alpha = GL_ZERO;
|
||||
dst_alpha = GL_ONE_MINUS_SRC_ALPHA;
|
||||
break;
|
||||
}
|
||||
case GPU_BLEND_BACKGROUND: {
|
||||
src_rgb = GL_ONE_MINUS_DST_ALPHA;
|
||||
dst_rgb = GL_SRC_ALPHA;
|
||||
src_alpha = GL_ZERO;
|
||||
dst_alpha = GL_SRC_ALPHA;
|
||||
break;
|
||||
}
|
||||
case GPU_BLEND_CUSTOM: {
|
||||
src_rgb = GL_ONE;
|
||||
dst_rgb = GL_SRC1_COLOR;
|
||||
src_alpha = GL_ONE;
|
||||
dst_alpha = GL_SRC1_ALPHA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (value != GPU_BLEND_NONE) {
|
||||
glBlendFuncSeparate(src_rgb, dst_rgb, src_alpha, dst_alpha);
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
else {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2020, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "gpu_state_private.hh"
|
||||
|
||||
#include "glew-mx.h"
|
||||
|
||||
namespace blender {
|
||||
namespace gpu {
|
||||
|
||||
class GLStateStack : public GPUStateStack {
|
||||
private:
|
||||
/** Current state of the GL implementation. Avoids resetting the whole state for every change. */
|
||||
GPUState current_;
|
||||
GPUStateMutable current_mutable_;
|
||||
|
||||
public:
|
||||
void set_state(GPUState &state) override;
|
||||
void set_mutable_state(GPUStateMutable &state) override;
|
||||
|
||||
public:
|
||||
/* TODO to become private */
|
||||
static void set_write_mask(const eGPUWriteMask value);
|
||||
static void set_depth_test(const eGPUDepthTest value);
|
||||
static void set_stencil_test(const eGPUStencilTest test, const eGPUStencilOp operation);
|
||||
static void set_stencil_mask(const eGPUStencilTest test, const GPUStateMutable state);
|
||||
static void set_clip_distances(const int new_dist_len, const int old_dist_len);
|
||||
static void set_logic_op(const bool enable);
|
||||
static void set_facing(const bool invert);
|
||||
static void set_backface_culling(const eGPUFaceCullTest test);
|
||||
static void set_provoking_vert(const eGPUProvokingVertex vert);
|
||||
static void set_shadow_bias(const bool enable);
|
||||
static void set_blend(const eGPUBlend value);
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
} // namespace blender
|
Loading…
Reference in New Issue