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"
|
|
|
|
|
2020-08-16 14:01:07 +02:00
|
|
|
#include "gpu_state_private.hh"
|
|
|
|
|
2020-08-16 14:47:13 +02:00
|
|
|
/* TODO remove */
|
|
|
|
#include "gl_state.hh"
|
|
|
|
|
2020-08-16 14:01:07 +02:00
|
|
|
using namespace blender::gpu;
|
|
|
|
|
2020-08-16 15:38:34 +02:00
|
|
|
void GPU_blend(eGPUBlend blend)
|
2018-06-26 15:17:31 -06:00
|
|
|
{
|
2020-08-16 15:16:21 +02:00
|
|
|
GLStateStack::set_blend(blend);
|
2018-06-26 15:17:31 -06:00
|
|
|
}
|
|
|
|
|
2020-08-16 14:01:07 +02:00
|
|
|
void GPU_face_culling(eGPUFaceCullTest culling)
|
2020-07-17 20:04:37 +02:00
|
|
|
{
|
|
|
|
if (culling == GPU_CULL_NONE) {
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
glCullFace((culling == GPU_CULL_FRONT) ? GL_FRONT : GL_BACK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-17 20:13:11 +02:00
|
|
|
void GPU_front_facing(bool invert)
|
|
|
|
{
|
|
|
|
glFrontFace((invert) ? GL_CW : GL_CCW);
|
|
|
|
}
|
|
|
|
|
2020-07-17 20:26:12 +02:00
|
|
|
void GPU_provoking_vertex(eGPUProvokingVertex vert)
|
|
|
|
{
|
|
|
|
glProvokingVertex((vert == GPU_VERTEX_FIRST) ? GL_FIRST_VERTEX_CONVENTION :
|
|
|
|
GL_LAST_VERTEX_CONVENTION);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-17 19:21:33 +02:00
|
|
|
void GPU_scissor_test(bool enable)
|
|
|
|
{
|
|
|
|
if (enable) {
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-07-17 19:03:30 +02:00
|
|
|
void GPU_viewport(int x, int y, int width, int height)
|
|
|
|
{
|
|
|
|
glViewport(x, y, width, height);
|
|
|
|
}
|
|
|
|
|
2020-08-16 01:49:52 +02:00
|
|
|
void GPU_scissor_get(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
|
|
|
|
2020-07-17 18:51:26 +02:00
|
|
|
void GPU_unpack_row_length_set(uint len)
|
|
|
|
{
|
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, len);
|
|
|
|
}
|
|
|
|
|
2020-07-16 03:31:25 +02:00
|
|
|
void GPU_logic_op_xor_set(bool enable)
|
2019-07-02 12:30:55 +10:00
|
|
|
{
|
|
|
|
if (enable) {
|
2020-07-16 03:31:25 +02:00
|
|
|
glLogicOp(GL_XOR);
|
2019-07-02 12:30:55 +10:00
|
|
|
glEnable(GL_COLOR_LOGIC_OP);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glDisable(GL_COLOR_LOGIC_OP);
|
|
|
|
}
|
|
|
|
}
|
2020-03-11 14:52:57 +11:00
|
|
|
|
2020-07-16 04:16:10 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-07-17 23:00:55 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-07-29 18:13:19 +02:00
|
|
|
bool GPU_mipmap_enabled(void)
|
|
|
|
{
|
|
|
|
/* TODO(fclem) this used to be a userdef option. */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-08-16 14:01:07 +02:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \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--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2020-03-11 14:52:57 +11:00
|
|
|
/** \name GPU Push/Pop State
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
#define STATE_STACK_DEPTH 16
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
eGPUAttrMask mask;
|
|
|
|
|
2020-07-28 19:26:54 +02:00
|
|
|
/* GL_BLEND_BIT */
|
2020-03-11 14:52:57 +11:00
|
|
|
uint is_blend : 1;
|
|
|
|
|
|
|
|
/* GL_DEPTH_BUFFER_BIT */
|
2020-07-28 19:26:54 +02:00
|
|
|
uint is_depth_test : 1;
|
2020-03-11 14:52:57 +11:00
|
|
|
int depth_func;
|
|
|
|
double depth_clear_value;
|
|
|
|
bool depth_write_mask;
|
|
|
|
|
|
|
|
/* GL_SCISSOR_BIT */
|
|
|
|
int scissor_box[4];
|
2020-07-28 19:26:54 +02:00
|
|
|
uint is_scissor_test : 1;
|
2020-03-11 14:52:57 +11:00
|
|
|
|
|
|
|
/* 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 = {
|
2020-07-29 15:52:33 +02:00
|
|
|
{},
|
|
|
|
0,
|
2020-03-11 14:52:57 +11:00
|
|
|
};
|
|
|
|
|
|
|
|
#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_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++;
|
|
|
|
}
|
|
|
|
|
|
|
|
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_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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef Attr
|
|
|
|
#undef AttrStack
|
|
|
|
|
2020-05-15 14:29:27 +02:00
|
|
|
/* 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);
|
|
|
|
|
2020-07-17 15:58:33 +02:00
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
2020-07-17 18:51:26 +02:00
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
2020-07-17 15:58:33 +02:00
|
|
|
|
2020-05-15 14:29:27 +02:00
|
|
|
/* 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);
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-11 14:52:57 +11:00
|
|
|
/** \} */
|