Files
test/source/blender/gpu/intern/gpu_state.cc
Sergey Sharybin c1bc70b711 Cleanup: Add a copyright notice to files and use SPDX format
A lot of files were missing copyright field in the header and
the Blender Foundation contributed to them in a sense of bug
fixing and general maintenance.

This change makes it explicit that those files are at least
partially copyrighted by the Blender Foundation.

Note that this does not make it so the Blender Foundation is
the only holder of the copyright in those files, and developers
who do not have a signed contract with the foundation still
hold the copyright as well.

Another aspect of this change is using SPDX format for the
header. We already used it for the license specification,
and now we state it for the copyright as well, following the
FAQ:

    https://reuse.software/faq/
2023-05-31 16:19:06 +02:00

433 lines
10 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \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 "GPU_state.h"
#include "gpu_backend.hh"
#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);
}
eGPUFaceCullTest GPU_face_culling_get()
{
GPUState &state = Context::get()->state_manager->state;
return (eGPUFaceCullTest)state.culling_test;
}
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);
}
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);
}
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;
}
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 #80169, #81289).
* 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;
}
}
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);
}
GPUFence *GPU_fence_create()
{
Fence *fence = GPUBackend::get()->fence_alloc();
return wrap(fence);
}
void GPU_fence_free(GPUFence *fence)
{
delete unwrap(fence);
}
void GPU_fence_signal(GPUFence *fence)
{
unwrap(fence)->signal();
}
void GPU_fence_wait(GPUFence *fence)
{
unwrap(fence)->wait();
}
/** \} */
/* -------------------------------------------------------------------- */
/** \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;
}
/** \} */