This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/gpu/intern/gpu_state.cc

430 lines
11 KiB
C++

/*
* 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.
*/
/** \file
* \ingroup gpu
*/
#ifndef GPU_STANDALONE
# include "DNA_userdef_types.h"
# define PIXELSIZE (U.pixelsize)
#else
# define PIXELSIZE (1.0f)
#endif
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
#include "GPU_state.h"
#include "gpu_context_private.hh"
#include "gpu_state_private.hh"
using namespace blender::gpu;
#define SET_STATE(_prefix, _state, _value) \
do { \
StateManager *stack = Context::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_face_culling(eGPUFaceCullTest culling)
{
SET_IMMUTABLE_STATE(culling_test, culling);
}
void GPU_front_facing(bool invert)
{
SET_IMMUTABLE_STATE(invert_facing, invert);
}
void GPU_provoking_vertex(eGPUProvokingVertex vert)
{
SET_IMMUTABLE_STATE(provoking_vert, vert);
}
void GPU_depth_test(eGPUDepthTest test)
{
SET_IMMUTABLE_STATE(depth_test, test);
}
void GPU_stencil_test(eGPUStencilTest test)
{
SET_IMMUTABLE_STATE(stencil_test, test);
}
void GPU_line_smooth(bool enable)
{
SET_IMMUTABLE_STATE(line_smooth, enable);
}
void GPU_polygon_smooth(bool enable)
{
SET_IMMUTABLE_STATE(polygon_smooth, enable);
}
void GPU_logic_op_xor_set(bool enable)
{
SET_IMMUTABLE_STATE(logic_op_xor, enable);
}
void GPU_write_mask(eGPUWriteMask mask)
{
SET_IMMUTABLE_STATE(write_mask, mask);
}
void GPU_color_mask(bool r, bool g, bool b, bool a)
{
StateManager *stack = Context::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_depth_mask(bool depth)
{
StateManager *stack = Context::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_shadow_offset(bool enable)
{
SET_IMMUTABLE_STATE(shadow_bias, enable);
}
void GPU_clip_distances(int distances_enabled)
{
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)
{
StateManager *stack = Context::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)
{
StateManager *stack = Context::get()->state_manager;
auto &state = stack->mutable_state;
copy_v2_fl2(state.depth_range, near, far);
}
/**
* \note By convention, this is set as needed and not reset back to 1.0.
* This means code that draws lines must always set the line width beforehand,
* but is not expected to restore it's previous value.
*/
void GPU_line_width(float width)
{
width = max_ff(1.0f, width * PIXELSIZE);
SET_MUTABLE_STATE(line_width, width);
}
void GPU_point_size(float size)
{
StateManager *stack = Context::get()->state_manager;
auto &state = stack->mutable_state;
/* Keep the sign of point_size since it represents the enable state. */
state.point_size = size * ((state.point_size > 0.0) ? 1.0f : -1.0f);
}
/* Programmable point size
* - shaders set their own point size when enabled
* - use GPU_point_size when disabled */
/* TODO remove and use program point size everywhere */
void GPU_program_point_size(bool enable)
{
StateManager *stack = Context::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)
{
Context::get()->active_fb->scissor_test_set(enable);
}
void GPU_scissor(int x, int y, int width, int height)
{
int scissor_rect[4] = {x, y, width, height};
Context::get()->active_fb->scissor_set(scissor_rect);
}
void GPU_viewport(int x, int y, int width, int height)
{
int viewport_rect[4] = {x, y, width, height};
Context::get()->active_fb->viewport_set(viewport_rect);
}
void GPU_stencil_reference_set(uint reference)
{
SET_MUTABLE_STATE(stencil_reference, (uint8_t)reference);
}
void GPU_stencil_write_mask_set(uint write_mask)
{
SET_MUTABLE_STATE(stencil_write_mask, (uint8_t)write_mask);
}
void GPU_stencil_compare_mask_set(uint compare_mask)
{
SET_MUTABLE_STATE(stencil_compare_mask, (uint8_t)compare_mask);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name State Getters
* \{ */
eGPUBlend GPU_blend_get()
{
GPUState &state = Context::get()->state_manager->state;
return (eGPUBlend)state.blend;
}
eGPUWriteMask GPU_write_mask_get()
{
GPUState &state = Context::get()->state_manager->state;
return (eGPUWriteMask)state.write_mask;
}
uint GPU_stencil_mask_get()
{
const GPUStateMutable &state = Context::get()->state_manager->mutable_state;
return state.stencil_write_mask;
}
eGPUDepthTest GPU_depth_test_get()
{
GPUState &state = Context::get()->state_manager->state;
return (eGPUDepthTest)state.depth_test;
}
eGPUStencilTest GPU_stencil_test_get()
{
GPUState &state = Context::get()->state_manager->state;
return (eGPUStencilTest)state.stencil_test;
}
/* NOTE: Already premultiplied by U.pixelsize. */
float GPU_line_width_get()
{
const GPUStateMutable &state = Context::get()->state_manager->mutable_state;
return state.line_width;
}
void GPU_scissor_get(int coords[4])
{
Context::get()->active_fb->scissor_get(coords);
}
void GPU_viewport_size_get_f(float coords[4])
{
int viewport[4];
Context::get()->active_fb->viewport_get(viewport);
for (int i = 0; i < 4; i++) {
coords[i] = viewport[i];
}
}
void GPU_viewport_size_get_i(int coords[4])
{
Context::get()->active_fb->viewport_get(coords);
}
bool GPU_depth_mask_get()
{
const GPUState &state = Context::get()->state_manager->state;
return (state.write_mask & GPU_WRITE_DEPTH) != 0;
}
bool GPU_mipmap_enabled()
{
/* TODO(fclem): this used to be a userdef option. */
return true;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Context Utils
* \{ */
void GPU_flush()
{
Context::get()->flush();
}
void GPU_finish()
{
Context::get()->finish();
}
void GPU_apply_state()
{
Context::get()->state_manager->apply_state();
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name BGL workaround
*
* bgl makes direct GL calls that makes our state tracking out of date.
* This flag make it so that the pyGPU calls will not override the state set by
* bgl functions.
* \{ */
void GPU_bgl_start()
{
Context *ctx = Context::get();
if (!(ctx && ctx->state_manager)) {
return;
}
StateManager &state_manager = *(Context::get()->state_manager);
if (state_manager.use_bgl == false) {
/* Expected by many addons (see T80169, T81289).
* This will reset the blend function. */
GPU_blend(GPU_BLEND_NONE);
/* Equivalent of setting the depth func `glDepthFunc(GL_LEQUAL)`
* Needed since Python scripts may enable depth test.
* Without this block the depth test function is undefined. */
{
eGPUDepthTest depth_test_real = GPU_depth_test_get();
eGPUDepthTest depth_test_temp = GPU_DEPTH_LESS_EQUAL;
if (depth_test_real != depth_test_temp) {
GPU_depth_test(depth_test_temp);
state_manager.apply_state();
GPU_depth_test(depth_test_real);
}
}
state_manager.apply_state();
state_manager.use_bgl = true;
}
}
/* Just turn off the bgl safeguard system. Can be called even without GPU_bgl_start. */
void GPU_bgl_end()
{
Context *ctx = Context::get();
if (!(ctx && ctx->state_manager)) {
return;
}
StateManager &state_manager = *ctx->state_manager;
if (state_manager.use_bgl == true) {
state_manager.use_bgl = false;
/* Resync state tracking. */
state_manager.force_state();
}
}
bool GPU_bgl_get()
{
return Context::get()->state_manager->use_bgl;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Synchronization Utils
* \{ */
void GPU_memory_barrier(eGPUBarrier barrier)
{
Context::get()->state_manager->issue_barrier(barrier);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Default State
* \{ */
StateManager::StateManager()
{
/* 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.clip_distances = 0;
state.polygon_smooth = false;
state.line_smooth = false;
mutable_state.depth_range[0] = 0.0f;
mutable_state.depth_range[1] = 1.0f;
mutable_state.point_size = -1.0f; /* Negative is not using point size. */
mutable_state.line_width = 1.0f;
mutable_state.stencil_write_mask = 0x00;
mutable_state.stencil_compare_mask = 0x00;
mutable_state.stencil_reference = 0x00;
}
/** \} */