From e6425aa2bf3e6a9bba2f10066dc3f09cea11086f Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 14 Aug 2019 15:27:10 +0200 Subject: 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 --- source/blender/gpu/CMakeLists.txt | 1 + source/blender/gpu/intern/gpu_context.cpp | 10 +++ source/blender/gpu/intern/gpu_context_private.h | 2 + source/blender/gpu/intern/gpu_matrix.c | 91 ++++++++++++++++--------- source/blender/gpu/intern/gpu_matrix_private.h | 35 ++++++++++ 5 files changed, 106 insertions(+), 33 deletions(-) create mode 100644 source/blender/gpu/intern/gpu_matrix_private.h (limited to 'source/blender/gpu') diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index c620644a5f8..fb7d3c1ace8 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -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 diff --git a/source/blender/gpu/intern/gpu_context.cpp b/source/blender/gpu/intern/gpu_context.cpp index 97f9e52f944..93df65006ff 100644 --- a/source/blender/gpu/intern/gpu_context.cpp +++ b/source/blender/gpu/intern/gpu_context.cpp @@ -36,6 +36,7 @@ #include "gpu_batch_private.h" #include "gpu_context_private.h" +#include "gpu_matrix_private.h" #include #include @@ -71,6 +72,7 @@ struct GPUContext { std::unordered_set framebuffers; /* Framebuffers that have FBO from this context */ #endif + struct GPUMatrixState *matrix_state; std::vector orphaned_vertarray_ids; std::vector 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; +} diff --git a/source/blender/gpu/intern/gpu_context_private.h b/source/blender/gpu/intern/gpu_context_private.h index 6825b67d2c8..c9379e5433f 100644 --- a/source/blender/gpu/intern/gpu_context_private.h +++ b/source/blender/gpu/intern/gpu_context_private.h @@ -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 diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c index 58ca800a92c..fb0dffb58d1 100644 --- a/source/blender/gpu/intern/gpu_matrix.c +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -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; } /** \} */ diff --git a/source/blender/gpu/intern/gpu_matrix_private.h b/source/blender/gpu/intern/gpu_matrix_private.h new file mode 100644 index 00000000000..862ef065481 --- /dev/null +++ b/source/blender/gpu/intern/gpu_matrix_private.h @@ -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__ */ -- cgit v1.2.3