2018-06-26 15:17:31 -06:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup gpu
|
2018-06-26 15:17:31 -06:00
|
|
|
*/
|
|
|
|
|
2020-03-11 14:52:57 +11:00
|
|
|
#ifndef GPU_STANDALONE
|
|
|
|
# include "DNA_userdef_types.h"
|
|
|
|
# define PIXELSIZE (U.pixelsize)
|
|
|
|
#else
|
|
|
|
# define PIXELSIZE (1.0f)
|
|
|
|
#endif
|
2018-10-30 16:21:44 +01:00
|
|
|
|
2019-06-06 10:06:54 +10:00
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
2019-03-23 23:47:12 +01:00
|
|
|
#include "BKE_global.h"
|
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "GPU_extensions.h"
|
2018-06-26 15:17:31 -06:00
|
|
|
#include "GPU_glew.h"
|
|
|
|
#include "GPU_state.h"
|
|
|
|
|
2019-01-23 14:15:43 +11:00
|
|
|
static GLenum gpu_get_gl_blendfunction(eGPUBlendFunction blend)
|
2018-06-26 15:17:31 -06:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
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;
|
|
|
|
}
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void GPU_blend(bool enable)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (enable) {
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
}
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
2019-01-23 14:15:43 +11:00
|
|
|
void GPU_blend_set_func(eGPUBlendFunction sfactor, eGPUBlendFunction dfactor)
|
2018-06-26 15:17:31 -06:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
glBlendFunc(gpu_get_gl_blendfunction(sfactor), gpu_get_gl_blendfunction(dfactor));
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
void GPU_blend_set_func_separate(eGPUBlendFunction src_rgb,
|
|
|
|
eGPUBlendFunction dst_rgb,
|
|
|
|
eGPUBlendFunction src_alpha,
|
|
|
|
eGPUBlendFunction dst_alpha)
|
2018-06-26 15:17:31 -06:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
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));
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
2018-10-30 15:31:32 -03:00
|
|
|
void GPU_depth_range(float near, float far)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* glDepthRangef is only for OpenGL 4.1 or higher */
|
|
|
|
glDepthRange(near, far);
|
2018-10-30 15:31:32 -03:00
|
|
|
}
|
|
|
|
|
2018-06-26 15:17:31 -06:00
|
|
|
void GPU_depth_test(bool enable)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (enable) {
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
}
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GPU_depth_test_enabled()
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return glIsEnabled(GL_DEPTH_TEST);
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void GPU_line_smooth(bool enable)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (enable && ((G.debug & G_DEBUG_GPU) == 0)) {
|
|
|
|
glEnable(GL_LINE_SMOOTH);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glDisable(GL_LINE_SMOOTH);
|
|
|
|
}
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void GPU_line_width(float width)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
float max_size = GPU_max_line_width();
|
2020-03-11 14:52:57 +11:00
|
|
|
float final_size = width * PIXELSIZE;
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Fix opengl errors on certain platform / drivers. */
|
|
|
|
CLAMP(final_size, 1.0f, max_size);
|
|
|
|
glLineWidth(final_size);
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void GPU_point_size(float size)
|
|
|
|
{
|
2020-03-11 14:52:57 +11:00
|
|
|
glPointSize(size * PIXELSIZE);
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void GPU_polygon_smooth(bool enable)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (enable && ((G.debug & G_DEBUG_GPU) == 0)) {
|
|
|
|
glEnable(GL_POLYGON_SMOOTH);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glDisable(GL_POLYGON_SMOOTH);
|
|
|
|
}
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
2019-05-28 17:14:22 +02:00
|
|
|
/* Programmable point size
|
|
|
|
* - shaders set their own point size when enabled
|
|
|
|
* - use glPointSize when disabled */
|
|
|
|
void GPU_program_point_size(bool enable)
|
|
|
|
{
|
|
|
|
if (enable) {
|
|
|
|
glEnable(GL_PROGRAM_POINT_SIZE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glDisable(GL_PROGRAM_POINT_SIZE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-26 15:17:31 -06:00
|
|
|
void GPU_scissor(int x, int y, int width, int height)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
glScissor(x, y, width, height);
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
2018-07-02 18:27:05 +02:00
|
|
|
void GPU_scissor_get_f(float coords[4])
|
2018-06-26 15:17:31 -06:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
glGetFloatv(GL_SCISSOR_BOX, coords);
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
2018-07-02 18:27:05 +02:00
|
|
|
void GPU_scissor_get_i(int coords[4])
|
2018-06-26 15:17:31 -06:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
glGetIntegerv(GL_SCISSOR_BOX, coords);
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
2018-07-02 18:27:05 +02:00
|
|
|
void GPU_viewport_size_get_f(float coords[4])
|
2018-06-26 15:17:31 -06:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
glGetFloatv(GL_VIEWPORT, coords);
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
2018-07-02 18:27:05 +02:00
|
|
|
void GPU_viewport_size_get_i(int coords[4])
|
2018-06-26 15:17:31 -06:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
glGetIntegerv(GL_VIEWPORT, coords);
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
2018-10-31 12:28:59 +01:00
|
|
|
|
|
|
|
void GPU_flush(void)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
glFlush();
|
2018-10-31 12:28:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void GPU_finish(void)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
glFinish();
|
2018-11-04 10:08:55 +11:00
|
|
|
}
|
2019-07-02 12:30:55 +10:00
|
|
|
|
|
|
|
void GPU_logic_op_invert_set(bool enable)
|
|
|
|
{
|
|
|
|
if (enable) {
|
|
|
|
glLogicOp(GL_INVERT);
|
|
|
|
glEnable(GL_COLOR_LOGIC_OP);
|
|
|
|
glDisable(GL_DITHER);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glLogicOp(GL_COPY);
|
|
|
|
glDisable(GL_COLOR_LOGIC_OP);
|
|
|
|
glEnable(GL_DITHER);
|
|
|
|
}
|
|
|
|
}
|
2020-03-11 14:52:57 +11:00
|
|
|
|
|
|
|
/** \name GPU Push/Pop State
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
#define STATE_STACK_DEPTH 16
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
eGPUAttrMask mask;
|
|
|
|
|
|
|
|
/* GL_ENABLE_BIT */
|
|
|
|
uint is_blend : 1;
|
|
|
|
uint is_cull_face : 1;
|
|
|
|
uint is_depth_test : 1;
|
|
|
|
uint is_dither : 1;
|
|
|
|
uint is_lighting : 1;
|
|
|
|
uint is_line_smooth : 1;
|
|
|
|
uint is_color_logic_op : 1;
|
|
|
|
uint is_multisample : 1;
|
|
|
|
uint is_polygon_offset_line : 1;
|
|
|
|
uint is_polygon_offset_fill : 1;
|
|
|
|
uint is_polygon_smooth : 1;
|
|
|
|
uint is_sample_alpha_to_coverage : 1;
|
|
|
|
uint is_scissor_test : 1;
|
|
|
|
uint is_stencil_test : 1;
|
2020-03-19 08:06:49 +01:00
|
|
|
uint is_framebuffer_srgb : 1;
|
2020-03-11 14:52:57 +11:00
|
|
|
|
|
|
|
bool is_clip_plane[6];
|
|
|
|
|
|
|
|
/* 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 = {
|
|
|
|
.top = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define AttrStack state
|
|
|
|
#define Attr state.attr_stack[state.top]
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
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_ENABLE_BIT) != 0) {
|
|
|
|
Attr.is_blend = glIsEnabled(GL_BLEND);
|
|
|
|
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
|
|
Attr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i);
|
|
|
|
}
|
|
|
|
|
|
|
|
Attr.is_cull_face = glIsEnabled(GL_CULL_FACE);
|
|
|
|
Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
|
|
|
Attr.is_dither = glIsEnabled(GL_DITHER);
|
|
|
|
Attr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH);
|
|
|
|
Attr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
|
|
|
|
Attr.is_multisample = glIsEnabled(GL_MULTISAMPLE);
|
|
|
|
Attr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE);
|
|
|
|
Attr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
|
|
|
|
Attr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH);
|
|
|
|
Attr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
|
|
|
Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
|
|
|
Attr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2020-03-19 08:06:49 +01:00
|
|
|
Attr.is_framebuffer_srgb = glIsEnabled(GL_FRAMEBUFFER_SRGB);
|
2020-03-11 14:52:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((mask & GPU_BLEND_BIT) != 0) {
|
|
|
|
Attr.is_blend = glIsEnabled(GL_BLEND);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_assert(AttrStack.top < STATE_STACK_DEPTH);
|
|
|
|
AttrStack.top++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void restore_mask(GLenum cap, const bool value)
|
|
|
|
{
|
|
|
|
if (value) {
|
|
|
|
glEnable(cap);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glDisable(cap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gpuPopAttr(void)
|
|
|
|
{
|
|
|
|
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_ENABLE_BIT) != 0) {
|
|
|
|
restore_mask(GL_BLEND, Attr.is_blend);
|
|
|
|
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
|
|
restore_mask(GL_CLIP_PLANE0 + i, Attr.is_clip_plane[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
restore_mask(GL_CULL_FACE, Attr.is_cull_face);
|
|
|
|
restore_mask(GL_DEPTH_TEST, Attr.is_depth_test);
|
|
|
|
restore_mask(GL_DITHER, Attr.is_dither);
|
|
|
|
restore_mask(GL_LINE_SMOOTH, Attr.is_line_smooth);
|
|
|
|
restore_mask(GL_COLOR_LOGIC_OP, Attr.is_color_logic_op);
|
|
|
|
restore_mask(GL_MULTISAMPLE, Attr.is_multisample);
|
|
|
|
restore_mask(GL_POLYGON_OFFSET_LINE, Attr.is_polygon_offset_line);
|
|
|
|
restore_mask(GL_POLYGON_OFFSET_FILL, Attr.is_polygon_offset_fill);
|
|
|
|
restore_mask(GL_POLYGON_SMOOTH, Attr.is_polygon_smooth);
|
|
|
|
restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Attr.is_sample_alpha_to_coverage);
|
|
|
|
restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test);
|
|
|
|
restore_mask(GL_STENCIL_TEST, Attr.is_stencil_test);
|
|
|
|
}
|
|
|
|
|
|
|
|
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]);
|
2020-03-19 08:06:49 +01:00
|
|
|
restore_mask(GL_FRAMEBUFFER_SRGB, Attr.is_framebuffer_srgb);
|
2020-03-11 14:52:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef Attr
|
|
|
|
#undef AttrStack
|
|
|
|
|
|
|
|
/** \} */
|