Manage GPU_matrix stacks per GPUContext
Previously, we had one global `GPU_matrix` stack, so the API was not thread safe. This patch makes the stack be per `GPUContext`, effectively making it local per thread (`GPUContext` is located in thread local storage). Reviewed By: brecht Differential Revision: https://developer.blender.org/D5405
This commit is contained in:
@@ -116,6 +116,7 @@ set(SRC
|
||||
intern/gpu_batch_private.h
|
||||
intern/gpu_codegen.h
|
||||
intern/gpu_context_private.h
|
||||
intern/gpu_matrix_private.h
|
||||
intern/gpu_primitive_private.h
|
||||
intern/gpu_private.h
|
||||
intern/gpu_select_private.h
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include "gpu_batch_private.h"
|
||||
#include "gpu_context_private.h"
|
||||
#include "gpu_matrix_private.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
@@ -71,6 +72,7 @@ struct GPUContext {
|
||||
std::unordered_set<GPUFrameBuffer *>
|
||||
framebuffers; /* Framebuffers that have FBO from this context */
|
||||
#endif
|
||||
struct GPUMatrixState *matrix_state;
|
||||
std::vector<GLuint> orphaned_vertarray_ids;
|
||||
std::vector<GLuint> orphaned_framebuffer_ids;
|
||||
std::mutex orphans_mutex; /* todo: try spinlock instead */
|
||||
@@ -139,6 +141,7 @@ GPUContext *GPU_context_create(GLuint default_framebuffer)
|
||||
GPUContext *ctx = new GPUContext;
|
||||
glGenVertexArrays(1, &ctx->default_vao);
|
||||
ctx->default_framebuffer = default_framebuffer;
|
||||
ctx->matrix_state = GPU_matrix_state_create();
|
||||
GPU_context_active_set(ctx);
|
||||
return ctx;
|
||||
}
|
||||
@@ -159,6 +162,7 @@ void GPU_context_discard(GPUContext *ctx)
|
||||
/* this removes the array entry */
|
||||
GPU_batch_vao_cache_clear(*ctx->batches.begin());
|
||||
}
|
||||
GPU_matrix_state_discard(ctx->matrix_state);
|
||||
glDeleteVertexArrays(1, &ctx->default_vao);
|
||||
delete ctx;
|
||||
active_ctx = NULL;
|
||||
@@ -333,3 +337,9 @@ GPUFrameBuffer *gpu_context_active_framebuffer_get(GPUContext *ctx)
|
||||
{
|
||||
return ctx->current_fbo;
|
||||
}
|
||||
|
||||
struct GPUMatrixState *gpu_context_active_matrix_state_get()
|
||||
{
|
||||
BLI_assert(active_ctx);
|
||||
return active_ctx->matrix_state;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ void gpu_context_remove_framebuffer(GPUContext *ctx, struct GPUFrameBuffer *fb);
|
||||
void gpu_context_active_framebuffer_set(GPUContext *ctx, struct GPUFrameBuffer *fb);
|
||||
struct GPUFrameBuffer *gpu_context_active_framebuffer_get(GPUContext *ctx);
|
||||
|
||||
struct GPUMatrixState *gpu_context_active_matrix_state_get(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
|
||||
#include "GPU_shader_interface.h"
|
||||
|
||||
#include "gpu_context_private.h"
|
||||
#include "gpu_matrix_private.h"
|
||||
|
||||
#define SUPPRESS_GENERIC_MATRIX_API
|
||||
#define USE_GPU_PY_MATRIX_API /* only so values are declared */
|
||||
#include "GPU_matrix.h"
|
||||
@@ -32,6 +35,8 @@
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#define DEBUG_MATRIX_BIND 0
|
||||
|
||||
#define MATRIX_STACK_DEPTH 32
|
||||
@@ -44,7 +49,7 @@ typedef struct MatrixStack {
|
||||
uint top;
|
||||
} MatrixStack;
|
||||
|
||||
typedef struct {
|
||||
typedef struct GPUMatrixState {
|
||||
MatrixStack model_view_stack;
|
||||
MatrixStack projection_stack;
|
||||
|
||||
@@ -56,8 +61,16 @@ typedef struct {
|
||||
* TODO: separate Model from View transform? Batches/objects have model,
|
||||
* camera/eye has view & projection
|
||||
*/
|
||||
} MatrixState;
|
||||
} GPUMatrixState;
|
||||
|
||||
#define ModelViewStack gpu_context_active_matrix_state_get()->model_view_stack
|
||||
#define ModelView ModelViewStack.stack[ModelViewStack.top]
|
||||
|
||||
#define ProjectionStack gpu_context_active_matrix_state_get()->projection_stack
|
||||
#define Projection ProjectionStack.stack[ProjectionStack.top]
|
||||
|
||||
GPUMatrixState *GPU_matrix_state_create(void)
|
||||
{
|
||||
#define MATRIX_4X4_IDENTITY \
|
||||
{ \
|
||||
{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, \
|
||||
@@ -66,27 +79,36 @@ typedef struct {
|
||||
} \
|
||||
}
|
||||
|
||||
static MatrixState state = {
|
||||
.model_view_stack = {{MATRIX_4X4_IDENTITY}, 0},
|
||||
.projection_stack = {{MATRIX_4X4_IDENTITY}, 0},
|
||||
.dirty = true,
|
||||
};
|
||||
GPUMatrixState *state = MEM_mallocN(sizeof(*state), __func__);
|
||||
const MatrixStack identity_stack = {{MATRIX_4X4_IDENTITY}, 0};
|
||||
|
||||
state->model_view_stack = state->projection_stack = identity_stack;
|
||||
state->dirty = true;
|
||||
|
||||
#undef MATRIX_4X4_IDENTITY
|
||||
|
||||
#define ModelViewStack state.model_view_stack
|
||||
#define ModelView ModelViewStack.stack[ModelViewStack.top]
|
||||
return state;
|
||||
}
|
||||
|
||||
#define ProjectionStack state.projection_stack
|
||||
#define Projection ProjectionStack.stack[ProjectionStack.top]
|
||||
void GPU_matrix_state_discard(GPUMatrixState *state)
|
||||
{
|
||||
MEM_freeN(state);
|
||||
}
|
||||
|
||||
static void gpu_matrix_state_active_set_dirty(bool value)
|
||||
{
|
||||
GPUMatrixState *state = gpu_context_active_matrix_state_get();
|
||||
state->dirty = value;
|
||||
}
|
||||
|
||||
void GPU_matrix_reset(void)
|
||||
{
|
||||
state.model_view_stack.top = 0;
|
||||
state.projection_stack.top = 0;
|
||||
GPUMatrixState *state = gpu_context_active_matrix_state_get();
|
||||
state->model_view_stack.top = 0;
|
||||
state->projection_stack.top = 0;
|
||||
unit_m4(ModelView);
|
||||
unit_m4(Projection);
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
#ifdef WITH_GPU_SAFETY
|
||||
@@ -123,7 +145,7 @@ void GPU_matrix_pop(void)
|
||||
{
|
||||
BLI_assert(ModelViewStack.top > 0);
|
||||
ModelViewStack.top--;
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_push_projection(void)
|
||||
@@ -137,34 +159,34 @@ void GPU_matrix_pop_projection(void)
|
||||
{
|
||||
BLI_assert(ProjectionStack.top > 0);
|
||||
ProjectionStack.top--;
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_set(const float m[4][4])
|
||||
{
|
||||
copy_m4_m4(ModelView, m);
|
||||
CHECKMAT(ModelView3D);
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_identity_projection_set(void)
|
||||
{
|
||||
unit_m4(Projection);
|
||||
CHECKMAT(Projection3D);
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_projection_set(const float m[4][4])
|
||||
{
|
||||
copy_m4_m4(Projection, m);
|
||||
CHECKMAT(Projection3D);
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_identity_set(void)
|
||||
{
|
||||
unit_m4(ModelView);
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_translate_2f(float x, float y)
|
||||
@@ -194,7 +216,7 @@ void GPU_matrix_translate_3f(float x, float y, float z)
|
||||
m[3][2] = z;
|
||||
GPU_matrix_mul(m);
|
||||
#endif
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_translate_3fv(const float vec[3])
|
||||
@@ -243,7 +265,7 @@ void GPU_matrix_mul(const float m[4][4])
|
||||
{
|
||||
mul_m4_m4_post(ModelView, m);
|
||||
CHECKMAT(ModelView);
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_rotate_2d(float deg)
|
||||
@@ -272,7 +294,7 @@ void GPU_matrix_rotate_axis(float deg, char axis)
|
||||
/* rotate_m4 works in place */
|
||||
rotate_m4(ModelView, axis, DEG2RADF(deg));
|
||||
CHECKMAT(ModelView);
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
static void mat4_ortho_set(
|
||||
@@ -298,7 +320,7 @@ static void mat4_ortho_set(
|
||||
m[2][3] = 0.0f;
|
||||
m[3][3] = 1.0f;
|
||||
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
static void mat4_frustum_set(
|
||||
@@ -324,7 +346,7 @@ static void mat4_frustum_set(
|
||||
m[2][3] = -1.0f;
|
||||
m[3][3] = 0.0f;
|
||||
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3])
|
||||
@@ -389,14 +411,14 @@ static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3
|
||||
m[2][3] = 0.0f;
|
||||
m[3][3] = 1.0f;
|
||||
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_ortho_set(float left, float right, float bottom, float top, float near, float far)
|
||||
{
|
||||
mat4_ortho_set(Projection, left, right, bottom, top, near, far);
|
||||
CHECKMAT(Projection);
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top)
|
||||
@@ -404,7 +426,7 @@ void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top)
|
||||
Mat4 m;
|
||||
mat4_ortho_set(m, left, right, bottom, top, -1.0f, 1.0f);
|
||||
CHECKMAT(Projection2D);
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_frustum_set(
|
||||
@@ -412,7 +434,7 @@ void GPU_matrix_frustum_set(
|
||||
{
|
||||
mat4_frustum_set(Projection, left, right, bottom, top, near, far);
|
||||
CHECKMAT(Projection);
|
||||
state.dirty = true;
|
||||
gpu_matrix_state_active_set_dirty(true);
|
||||
}
|
||||
|
||||
void GPU_matrix_perspective_set(float fovy, float aspect, float near, float far)
|
||||
@@ -678,12 +700,13 @@ void GPU_matrix_bind(const GPUShaderInterface *shaderface)
|
||||
glUniformMatrix4fv(P_inv->location, 1, GL_FALSE, (const float *)m);
|
||||
}
|
||||
|
||||
state.dirty = false;
|
||||
gpu_matrix_state_active_set_dirty(false);
|
||||
}
|
||||
|
||||
bool GPU_matrix_dirty_get(void)
|
||||
{
|
||||
return state.dirty;
|
||||
GPUMatrixState *state = gpu_context_active_matrix_state_get();
|
||||
return state->dirty;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -695,12 +718,14 @@ BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mis
|
||||
|
||||
int GPU_matrix_stack_level_get_model_view(void)
|
||||
{
|
||||
return (int)state.model_view_stack.top;
|
||||
GPUMatrixState *state = gpu_context_active_matrix_state_get();
|
||||
return (int)state->model_view_stack.top;
|
||||
}
|
||||
|
||||
int GPU_matrix_stack_level_get_projection(void)
|
||||
{
|
||||
return (int)state.projection_stack.top;
|
||||
GPUMatrixState *state = gpu_context_active_matrix_state_get();
|
||||
return (int)state->projection_stack.top;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
35
source/blender/gpu/intern/gpu_matrix_private.h
Normal file
35
source/blender/gpu/intern/gpu_matrix_private.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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_MATRIX_PRIVATE_H__
|
||||
#define __GPU_MATRIX_PRIVATE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct GPUMatrixState *GPU_matrix_state_create(void);
|
||||
void GPU_matrix_state_discard(struct GPUMatrixState *state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GPU_MATRIX_PRIVATE_H__ */
|
||||
Reference in New Issue
Block a user