GPU: Add GC to FBOs and UBOs and centralize all GCs
GPUFrameBuffers were being free when no context was attached or in the wrong gl context. This make sure this does not happen again. You can now safely free any gl resource from any thread (well as long as it's not used anymore!).
This commit is contained in:
parent
3882d0943b
commit
5037dd8abd
Notes:
blender-bot
2023-02-14 07:39:44 +01:00
Referenced by issue #55695, Crash due to GPU memory leak when tweaking shader and light settings with Eevee
|
@ -136,6 +136,10 @@ void DRW_opengl_context_destroy(void);
|
|||
void DRW_opengl_context_enable(void);
|
||||
void DRW_opengl_context_disable(void);
|
||||
|
||||
/* Never use this. Only for closing blender. */
|
||||
void DRW_opengl_context_enable_ex(bool restore);
|
||||
void DRW_opengl_context_disable_ex(bool restore);
|
||||
|
||||
void DRW_opengl_render_context_enable(void *re_gl_context);
|
||||
void DRW_opengl_render_context_disable(void *re_gl_context);
|
||||
void DRW_gawain_render_context_enable(void *re_gpu_context);
|
||||
|
|
|
@ -2374,21 +2374,21 @@ void DRW_opengl_context_destroy(void)
|
|||
}
|
||||
}
|
||||
|
||||
void DRW_opengl_context_enable(void)
|
||||
void DRW_opengl_context_enable_ex(bool restore)
|
||||
{
|
||||
if (DST.gl_context != NULL) {
|
||||
/* IMPORTANT: We dont support immediate mode in render mode!
|
||||
* This shall remain in effect until immediate mode supports
|
||||
* multiple threads. */
|
||||
BLI_ticket_mutex_lock(DST.gl_context_mutex);
|
||||
if (BLI_thread_is_main()) {
|
||||
if (BLI_thread_is_main() && restore) {
|
||||
if (!G.background) {
|
||||
immDeactivate();
|
||||
}
|
||||
}
|
||||
WM_opengl_context_activate(DST.gl_context);
|
||||
GPU_context_active_set(DST.gpu_context);
|
||||
if (BLI_thread_is_main()) {
|
||||
if (BLI_thread_is_main() && restore) {
|
||||
if (!G.background) {
|
||||
immActivate();
|
||||
}
|
||||
|
@ -2397,7 +2397,7 @@ void DRW_opengl_context_enable(void)
|
|||
}
|
||||
}
|
||||
|
||||
void DRW_opengl_context_disable(void)
|
||||
void DRW_opengl_context_disable_ex(bool restore)
|
||||
{
|
||||
if (DST.gl_context != NULL) {
|
||||
#ifdef __APPLE__
|
||||
|
@ -2406,7 +2406,7 @@ void DRW_opengl_context_disable(void)
|
|||
glFlush();
|
||||
#endif
|
||||
|
||||
if (BLI_thread_is_main()) {
|
||||
if (BLI_thread_is_main() && restore) {
|
||||
wm_window_reset_drawable();
|
||||
}
|
||||
else {
|
||||
|
@ -2418,6 +2418,16 @@ void DRW_opengl_context_disable(void)
|
|||
}
|
||||
}
|
||||
|
||||
void DRW_opengl_context_enable(void)
|
||||
{
|
||||
DRW_opengl_context_enable_ex(true);
|
||||
}
|
||||
|
||||
void DRW_opengl_context_disable(void)
|
||||
{
|
||||
DRW_opengl_context_disable_ex(true);
|
||||
}
|
||||
|
||||
void DRW_opengl_render_context_enable(void *re_gl_context)
|
||||
{
|
||||
/* If thread is main you should use DRW_opengl_context_enable(). */
|
||||
|
|
|
@ -62,9 +62,9 @@ set(SRC
|
|||
intern/gpu_batch.c
|
||||
intern/gpu_batch_presets.c
|
||||
intern/gpu_batch_utils.c
|
||||
intern/gpu_buffer_id.cpp
|
||||
intern/gpu_buffers.c
|
||||
intern/gpu_codegen.c
|
||||
intern/gpu_context.cpp
|
||||
intern/gpu_debug.c
|
||||
intern/gpu_draw.c
|
||||
intern/gpu_element.c
|
||||
|
@ -84,7 +84,6 @@ set(SRC
|
|||
intern/gpu_state.c
|
||||
intern/gpu_texture.c
|
||||
intern/gpu_uniformbuffer.c
|
||||
intern/gpu_vertex_array_id.cpp
|
||||
intern/gpu_vertex_buffer.c
|
||||
intern/gpu_vertex_format.c
|
||||
intern/gpu_viewport.c
|
||||
|
@ -113,7 +112,6 @@ set(SRC
|
|||
GPU_attr_binding.h
|
||||
GPU_basic_shader.h
|
||||
GPU_batch.h
|
||||
GPU_buffer_id.h
|
||||
GPU_buffers.h
|
||||
GPU_common.h
|
||||
GPU_debug.h
|
||||
|
@ -135,7 +133,6 @@ set(SRC
|
|||
GPU_state.h
|
||||
GPU_texture.h
|
||||
GPU_uniformbuffer.h
|
||||
GPU_vertex_array_id.h
|
||||
GPU_vertex_buffer.h
|
||||
GPU_vertex_format.h
|
||||
GPU_viewport.h
|
||||
|
@ -143,6 +140,7 @@ set(SRC
|
|||
intern/gpu_attr_binding_private.h
|
||||
intern/gpu_batch_private.h
|
||||
intern/gpu_codegen.h
|
||||
intern/gpu_context_private.h
|
||||
intern/gpu_primitive_private.h
|
||||
intern/gpu_private.h
|
||||
intern/gpu_select_private.h
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 by Mike Erwin.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Blender Foundation
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/gpu/GPU_buffer_id.h
|
||||
* \ingroup gpu
|
||||
*
|
||||
* GPU buffer IDs
|
||||
*/
|
||||
|
||||
#ifndef __GPU_BUFFER_ID_H__
|
||||
#define __GPU_BUFFER_ID_H__
|
||||
|
||||
/* Manage GL buffer IDs in a thread-safe way
|
||||
* Use these instead of glGenBuffers & its friends
|
||||
* - alloc must be called from main thread
|
||||
* - free can be called from any thread */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "GPU_common.h"
|
||||
|
||||
GLuint GPU_buf_id_alloc(void);
|
||||
void GPU_buf_id_free(GLuint buffer_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GPU_BUFFER_ID_H__ */
|
|
@ -254,11 +254,6 @@ void GPU_material_free(struct ListBase *gpumaterial);
|
|||
|
||||
void GPU_materials_free(struct Main *bmain);
|
||||
|
||||
void GPU_material_orphans_init(void);
|
||||
void GPU_material_orphans_exit(void);
|
||||
/* This has to be called from a thread with an ogl context bound. */
|
||||
void GPU_material_orphans_delete(void);
|
||||
|
||||
struct Scene *GPU_material_scene(GPUMaterial *material);
|
||||
GPUMatType GPU_Material_get_type(GPUMaterial *material);
|
||||
struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
|
||||
|
|
|
@ -198,11 +198,6 @@ void GPU_invalid_tex_free(void);
|
|||
|
||||
void GPU_texture_free(GPUTexture *tex);
|
||||
|
||||
void GPU_texture_orphans_init(void);
|
||||
void GPU_texture_orphans_exit(void);
|
||||
/* This has to be called from a thread with an ogl context bound. */
|
||||
void GPU_texture_orphans_delete(void);
|
||||
|
||||
void GPU_texture_ref(GPUTexture *tex);
|
||||
void GPU_texture_bind(GPUTexture *tex, int number);
|
||||
void GPU_texture_unbind(GPUTexture *tex);
|
||||
|
|
|
@ -32,12 +32,11 @@
|
|||
|
||||
#include "GPU_batch.h"
|
||||
#include "GPU_batch_presets.h"
|
||||
#include "GPU_buffer_id.h"
|
||||
#include "GPU_matrix.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_vertex_array_id.h"
|
||||
|
||||
#include "gpu_batch_private.h"
|
||||
#include "gpu_context_private.h"
|
||||
#include "gpu_primitive_private.h"
|
||||
#include "gpu_shader_private.h"
|
||||
|
||||
|
|
|
@ -43,9 +43,6 @@ extern "C" {
|
|||
|
||||
void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *interface);
|
||||
|
||||
void gpu_context_add_batch(GPUContext *ctx, GPUBatch *batch);
|
||||
void gpu_context_remove_batch(GPUContext *ctx, GPUBatch *batch);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 by Mike Erwin.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Blender Foundation
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/gpu/intern/gpu_buffer_id.cpp
|
||||
* \ingroup gpu
|
||||
*
|
||||
* GPU buffer IDs
|
||||
*/
|
||||
|
||||
#include "GPU_buffer_id.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#define ORPHAN_DEBUG 0
|
||||
|
||||
#if ORPHAN_DEBUG
|
||||
# include <cstdio>
|
||||
#endif
|
||||
|
||||
static std::vector<GLuint> orphaned_buffer_ids;
|
||||
|
||||
static std::mutex orphan_mutex;
|
||||
|
||||
extern "C" {
|
||||
extern int BLI_thread_is_main(void); /* Blender-specific function */
|
||||
}
|
||||
|
||||
static bool thread_is_main()
|
||||
{
|
||||
/* "main" here means the GL context's thread */
|
||||
return BLI_thread_is_main();
|
||||
}
|
||||
|
||||
GLuint GPU_buf_id_alloc()
|
||||
{
|
||||
/* delete orphaned IDs */
|
||||
orphan_mutex.lock();
|
||||
if (!orphaned_buffer_ids.empty()) {
|
||||
const auto orphaned_buffer_len = (uint)orphaned_buffer_ids.size();
|
||||
#if ORPHAN_DEBUG
|
||||
printf("deleting %u orphaned VBO%s\n", orphaned_buffer_len, orphaned_buffer_len == 1 ? "" : "s");
|
||||
#endif
|
||||
glDeleteBuffers(orphaned_buffer_len, orphaned_buffer_ids.data());
|
||||
orphaned_buffer_ids.clear();
|
||||
}
|
||||
orphan_mutex.unlock();
|
||||
|
||||
GLuint new_buffer_id = 0;
|
||||
glGenBuffers(1, &new_buffer_id);
|
||||
return new_buffer_id;
|
||||
}
|
||||
|
||||
void GPU_buf_id_free(GLuint buffer_id)
|
||||
{
|
||||
if (thread_is_main()) {
|
||||
glDeleteBuffers(1, &buffer_id);
|
||||
}
|
||||
else {
|
||||
/* add this ID to the orphaned list */
|
||||
orphan_mutex.lock();
|
||||
#if ORPHAN_DEBUG
|
||||
printf("orphaning VBO %u\n", buffer_id);
|
||||
#endif
|
||||
orphaned_buffer_ids.emplace_back(buffer_id);
|
||||
orphan_mutex.unlock();
|
||||
}
|
||||
}
|
|
@ -34,9 +34,15 @@
|
|||
* - free can be called from any thread
|
||||
*/
|
||||
|
||||
#include "gpu_batch_private.h"
|
||||
#include "GPU_vertex_array_id.h"
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "GPU_context.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
|
||||
#include "gpu_batch_private.h"
|
||||
#include "gpu_context_private.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
@ -56,10 +62,19 @@ static bool thread_is_main() {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
static std::vector<GLuint> orphaned_buffer_ids;
|
||||
static std::vector<GLuint> orphaned_texture_ids;
|
||||
|
||||
static std::mutex orphans_mutex;
|
||||
|
||||
struct GPUContext {
|
||||
GLuint default_vao;
|
||||
std::unordered_set<GPUBatch *> batches; /* Batches that have VAOs from this context */
|
||||
#ifdef DEBUG
|
||||
std::unordered_set<GPUFrameBuffer *> framebuffers; /* Framebuffers that have FBO from this context */
|
||||
#endif
|
||||
std::vector<GLuint> orphaned_vertarray_ids;
|
||||
std::vector<GLuint> orphaned_framebuffer_ids;
|
||||
std::mutex orphans_mutex; /* todo: try spinlock instead */
|
||||
#if TRUST_NO_ONE
|
||||
pthread_t thread; /* Thread on which this context is active. */
|
||||
|
@ -78,22 +93,51 @@ thread_local GPUContext *active_ctx = NULL;
|
|||
static thread_local GPUContext *active_ctx = NULL;
|
||||
#endif
|
||||
|
||||
static void clear_orphans(GPUContext *ctx)
|
||||
static void orphans_add(GPUContext *ctx, std::vector<GLuint> *orphan_list, GLuint id)
|
||||
{
|
||||
std::mutex *mutex = (ctx) ? &ctx->orphans_mutex : &orphans_mutex;
|
||||
|
||||
mutex->lock();
|
||||
orphan_list->emplace_back(id);
|
||||
mutex->unlock();
|
||||
}
|
||||
|
||||
static void orphans_clear(GPUContext *ctx)
|
||||
{
|
||||
BLI_assert(ctx); /* need at least an active context */
|
||||
BLI_assert(pthread_equal(pthread_self(), ctx->thread)); /* context has been activated by another thread! */
|
||||
|
||||
ctx->orphans_mutex.lock();
|
||||
if (!ctx->orphaned_vertarray_ids.empty()) {
|
||||
uint orphan_len = (uint)ctx->orphaned_vertarray_ids.size();
|
||||
glDeleteVertexArrays(orphan_len, ctx->orphaned_vertarray_ids.data());
|
||||
ctx->orphaned_vertarray_ids.clear();
|
||||
}
|
||||
if (!ctx->orphaned_framebuffer_ids.empty()) {
|
||||
uint orphan_len = (uint)ctx->orphaned_framebuffer_ids.size();
|
||||
glDeleteFramebuffers(orphan_len, ctx->orphaned_framebuffer_ids.data());
|
||||
ctx->orphaned_framebuffer_ids.clear();
|
||||
}
|
||||
|
||||
ctx->orphans_mutex.unlock();
|
||||
|
||||
orphans_mutex.lock();
|
||||
if (!orphaned_buffer_ids.empty()) {
|
||||
uint orphan_len = (uint)orphaned_buffer_ids.size();
|
||||
glDeleteBuffers(orphan_len, orphaned_buffer_ids.data());
|
||||
orphaned_buffer_ids.clear();
|
||||
}
|
||||
if (!orphaned_texture_ids.empty()) {
|
||||
uint orphan_len = (uint)orphaned_texture_ids.size();
|
||||
glDeleteTextures(orphan_len, orphaned_texture_ids.data());
|
||||
orphaned_texture_ids.clear();
|
||||
}
|
||||
orphans_mutex.unlock();
|
||||
}
|
||||
|
||||
GPUContext *GPU_context_create(void)
|
||||
{
|
||||
#if TRUST_NO_ONE
|
||||
/* assert(thread_is_main()); */
|
||||
#endif
|
||||
/* BLI_assert(thread_is_main()); */
|
||||
GPUContext *ctx = new GPUContext;
|
||||
glGenVertexArrays(1, &ctx->default_vao);
|
||||
GPU_context_active_set(ctx);
|
||||
|
@ -103,12 +147,12 @@ GPUContext *GPU_context_create(void)
|
|||
/* to be called after GPU_context_active_set(ctx_to_destroy) */
|
||||
void GPU_context_discard(GPUContext *ctx)
|
||||
{
|
||||
#if TRUST_NO_ONE
|
||||
/* Make sure no other thread has locked it. */
|
||||
assert(ctx == active_ctx);
|
||||
assert(pthread_equal(pthread_self(), ctx->thread));
|
||||
assert(ctx->orphaned_vertarray_ids.empty());
|
||||
#endif
|
||||
BLI_assert(ctx == active_ctx);
|
||||
BLI_assert(pthread_equal(pthread_self(), ctx->thread));
|
||||
BLI_assert(ctx->orphaned_vertarray_ids.empty());
|
||||
/* For now don't allow GPUFrameBuffers to be reuse in another ctx. */
|
||||
BLI_assert(ctx->framebuffers.empty());
|
||||
/* delete remaining vaos */
|
||||
while (!ctx->batches.empty()) {
|
||||
/* this removes the array entry */
|
||||
|
@ -135,7 +179,7 @@ void GPU_context_active_set(GPUContext *ctx)
|
|||
}
|
||||
#endif
|
||||
if (ctx) {
|
||||
clear_orphans(ctx);
|
||||
orphans_clear(ctx);
|
||||
}
|
||||
active_ctx = ctx;
|
||||
}
|
||||
|
@ -147,50 +191,125 @@ GPUContext *GPU_context_active_get(void)
|
|||
|
||||
GLuint GPU_vao_default(void)
|
||||
{
|
||||
#if TRUST_NO_ONE
|
||||
assert(active_ctx); /* need at least an active context */
|
||||
assert(pthread_equal(pthread_self(), active_ctx->thread)); /* context has been activated by another thread! */
|
||||
#endif
|
||||
BLI_assert(active_ctx); /* need at least an active context */
|
||||
BLI_assert(pthread_equal(pthread_self(), active_ctx->thread)); /* context has been activated by another thread! */
|
||||
return active_ctx->default_vao;
|
||||
}
|
||||
|
||||
GLuint GPU_vao_alloc(void)
|
||||
{
|
||||
#if TRUST_NO_ONE
|
||||
assert(active_ctx); /* need at least an active context */
|
||||
assert(pthread_equal(pthread_self(), active_ctx->thread)); /* context has been activated by another thread! */
|
||||
#endif
|
||||
clear_orphans(active_ctx);
|
||||
|
||||
GLuint new_vao_id = 0;
|
||||
orphans_clear(active_ctx);
|
||||
glGenVertexArrays(1, &new_vao_id);
|
||||
return new_vao_id;
|
||||
}
|
||||
|
||||
/* this can be called from multiple thread */
|
||||
GLuint GPU_fbo_alloc(void)
|
||||
{
|
||||
GLuint new_fbo_id = 0;
|
||||
orphans_clear(active_ctx);
|
||||
glGenFramebuffers(1, &new_fbo_id);
|
||||
return new_fbo_id;
|
||||
}
|
||||
|
||||
GLuint GPU_buf_alloc(void)
|
||||
{
|
||||
GLuint new_buffer_id = 0;
|
||||
orphans_clear(active_ctx);
|
||||
glGenBuffers(1, &new_buffer_id);
|
||||
return new_buffer_id;
|
||||
}
|
||||
|
||||
GLuint GPU_tex_alloc(void)
|
||||
{
|
||||
GLuint new_texture_id = 0;
|
||||
orphans_clear(active_ctx);
|
||||
glGenTextures(1, &new_texture_id);
|
||||
return new_texture_id;
|
||||
}
|
||||
|
||||
void GPU_vao_free(GLuint vao_id, GPUContext *ctx)
|
||||
{
|
||||
#if TRUST_NO_ONE
|
||||
assert(ctx);
|
||||
#endif
|
||||
BLI_assert(ctx);
|
||||
if (ctx == active_ctx) {
|
||||
glDeleteVertexArrays(1, &vao_id);
|
||||
}
|
||||
else {
|
||||
ctx->orphans_mutex.lock();
|
||||
ctx->orphaned_vertarray_ids.emplace_back(vao_id);
|
||||
ctx->orphans_mutex.unlock();
|
||||
orphans_add(ctx, &ctx->orphaned_vertarray_ids, vao_id);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_fbo_free(GLuint fbo_id, GPUContext *ctx)
|
||||
{
|
||||
BLI_assert(ctx);
|
||||
if (ctx == active_ctx) {
|
||||
glDeleteFramebuffers(1, &fbo_id);
|
||||
}
|
||||
else {
|
||||
orphans_add(ctx, &ctx->orphaned_framebuffer_ids, fbo_id);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_buf_free(GLuint buf_id)
|
||||
{
|
||||
if (active_ctx) {
|
||||
glDeleteBuffers(1, &buf_id);
|
||||
}
|
||||
else {
|
||||
orphans_add(NULL, &orphaned_buffer_ids, buf_id);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_tex_free(GLuint tex_id)
|
||||
{
|
||||
if (active_ctx) {
|
||||
glDeleteTextures(1, &tex_id);
|
||||
}
|
||||
else {
|
||||
orphans_add(NULL, &orphaned_texture_ids, tex_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* GPUBatch & GPUFrameBuffer contains respectively VAO & FBO indices
|
||||
* which are not shared across contexts. So we need to keep track of
|
||||
* ownership. */
|
||||
|
||||
void gpu_context_add_batch(GPUContext *ctx, GPUBatch *batch)
|
||||
{
|
||||
BLI_assert(ctx);
|
||||
ctx->orphans_mutex.lock();
|
||||
ctx->batches.emplace(batch);
|
||||
ctx->orphans_mutex.unlock();
|
||||
}
|
||||
|
||||
void gpu_context_remove_batch(GPUContext *ctx, GPUBatch *batch)
|
||||
{
|
||||
BLI_assert(ctx);
|
||||
ctx->orphans_mutex.lock();
|
||||
ctx->batches.erase(batch);
|
||||
ctx->orphans_mutex.unlock();
|
||||
}
|
||||
|
||||
void gpu_context_add_framebuffer(GPUContext *ctx, GPUFrameBuffer *fb)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
BLI_assert(ctx);
|
||||
ctx->orphans_mutex.lock();
|
||||
ctx->framebuffers.emplace(fb);
|
||||
ctx->orphans_mutex.unlock();
|
||||
#else
|
||||
UNUSED_VARS(ctx, fb);
|
||||
#endif
|
||||
}
|
||||
|
||||
void gpu_context_remove_framebuffer(GPUContext *ctx, GPUFrameBuffer *fb)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
BLI_assert(ctx);
|
||||
ctx->orphans_mutex.lock();
|
||||
ctx->framebuffers.erase(fb);
|
||||
ctx->orphans_mutex.unlock();
|
||||
#else
|
||||
UNUSED_VARS(ctx, fb);
|
||||
#endif
|
||||
}
|
|
@ -23,33 +23,46 @@
|
|||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/gpu/GPU_vertex_array_id.h
|
||||
/** \file blender/gpu/intern/gpu_context_private.h
|
||||
* \ingroup gpu
|
||||
*
|
||||
* Manage GL vertex array IDs in a thread-safe way
|
||||
* Use these instead of glGenBuffers & its friends
|
||||
* - alloc must be called from a thread that is bound
|
||||
* to the context that will be used for drawing with
|
||||
* this vao.
|
||||
* - free can be called from any thread
|
||||
* This interface allow GPU to manage GL objects for mutiple context and threads.
|
||||
*/
|
||||
|
||||
#ifndef __GPU_VERTEX_ARRAY_ID_H__
|
||||
#define __GPU_VERTEX_ARRAY_ID_H__
|
||||
#ifndef __GPU_CONTEXT_PRIVATE_H__
|
||||
#define __GPU_CONTEXT_PRIVATE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "GPU_common.h"
|
||||
#include "GPU_context.h"
|
||||
|
||||
struct GPUFrameBuffer;
|
||||
|
||||
GLuint GPU_vao_default(void);
|
||||
|
||||
/* These require a gl ctx bound. */
|
||||
GLuint GPU_buf_alloc(void);
|
||||
GLuint GPU_tex_alloc(void);
|
||||
GLuint GPU_vao_alloc(void);
|
||||
void GPU_vao_free(GLuint vao_id, GPUContext *);
|
||||
GLuint GPU_fbo_alloc(void);
|
||||
|
||||
/* These can be called any threads even without gl ctx. */
|
||||
void GPU_buf_free(GLuint buf_id);
|
||||
void GPU_tex_free(GLuint tex_id);
|
||||
/* These two need the ctx the id was created with. */
|
||||
void GPU_vao_free(GLuint vao_id, GPUContext *ctx);
|
||||
void GPU_fbo_free(GLuint fbo_id, GPUContext *ctx);
|
||||
|
||||
void gpu_context_add_batch(GPUContext *ctx, GPUBatch *batch);
|
||||
void gpu_context_remove_batch(GPUContext *ctx, GPUBatch *batch);
|
||||
|
||||
void gpu_context_add_framebuffer(GPUContext *ctx, struct GPUFrameBuffer *fb);
|
||||
void gpu_context_remove_framebuffer(GPUContext *ctx, struct GPUFrameBuffer *fb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GPU_VERTEX_ARRAY_ID_H__ */
|
||||
#endif /* __GPU_CONTEXT_PRIVATE_H__ */
|
|
@ -30,7 +30,8 @@
|
|||
*/
|
||||
|
||||
#include "GPU_element.h"
|
||||
#include "GPU_buffer_id.h"
|
||||
|
||||
#include "gpu_context_private.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -279,7 +280,7 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
|
|||
#endif
|
||||
|
||||
if (elem->vbo_id == 0) {
|
||||
elem->vbo_id = GPU_buf_id_alloc();
|
||||
elem->vbo_id = GPU_buf_alloc();
|
||||
}
|
||||
/* send data to GPU */
|
||||
/* GL_ELEMENT_ARRAY_BUFFER changes the state of the last VAO bound,
|
||||
|
@ -302,7 +303,7 @@ void GPU_indexbuf_use(GPUIndexBuf *elem)
|
|||
void GPU_indexbuf_discard(GPUIndexBuf *elem)
|
||||
{
|
||||
if (elem->vbo_id) {
|
||||
GPU_buf_id_free(elem->vbo_id);
|
||||
GPU_buf_free(elem->vbo_id);
|
||||
}
|
||||
free(elem);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,8 @@
|
|||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "intern/gpu_private.h"
|
||||
#include "gpu_private.h"
|
||||
#include "gpu_context_private.h"
|
||||
|
||||
static ThreadLocal(void *) g_currentfb;
|
||||
|
||||
|
@ -69,6 +70,7 @@ typedef enum {
|
|||
#define GPU_FB_ATTACHEMENT_SET_DIRTY(flag, type) (flag |= (1 << type))
|
||||
|
||||
struct GPUFrameBuffer {
|
||||
GPUContext *ctx;
|
||||
GLuint object;
|
||||
GPUAttachment attachments[GPU_FB_MAX_ATTACHEMENT];
|
||||
uint16_t dirty_flag;
|
||||
|
@ -196,7 +198,9 @@ GPUFrameBuffer *GPU_framebuffer_create(void)
|
|||
|
||||
static void gpu_framebuffer_init(GPUFrameBuffer *fb)
|
||||
{
|
||||
glGenFramebuffers(1, &fb->object);
|
||||
fb->object = GPU_fbo_alloc();
|
||||
fb->ctx = GPU_context_active_get();
|
||||
gpu_context_add_framebuffer(fb->ctx, fb);
|
||||
}
|
||||
|
||||
void GPU_framebuffer_free(GPUFrameBuffer *fb)
|
||||
|
@ -207,8 +211,11 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb)
|
|||
}
|
||||
}
|
||||
|
||||
/* This restores the framebuffer if it was bound */
|
||||
glDeleteFramebuffers(1, &fb->object);
|
||||
if (fb->object != 0) {
|
||||
/* This restores the framebuffer if it was bound */
|
||||
GPU_fbo_free(fb->object, fb->ctx);
|
||||
gpu_context_remove_framebuffer(fb->ctx, fb);
|
||||
}
|
||||
|
||||
if (gpu_framebuffer_current_get() == fb->object) {
|
||||
gpu_framebuffer_current_set(0);
|
||||
|
|
|
@ -32,11 +32,10 @@
|
|||
#include "UI_resources.h"
|
||||
|
||||
#include "GPU_attr_binding.h"
|
||||
#include "GPU_buffer_id.h"
|
||||
#include "GPU_immediate.h"
|
||||
#include "GPU_vertex_array_id.h"
|
||||
|
||||
#include "gpu_attr_binding_private.h"
|
||||
#include "gpu_context_private.h"
|
||||
#include "gpu_primitive_private.h"
|
||||
#include "gpu_shader_private.h"
|
||||
#include "gpu_vertex_format_private.h"
|
||||
|
@ -91,7 +90,7 @@ void immInit(void)
|
|||
#endif
|
||||
memset(&imm, 0, sizeof(Immediate));
|
||||
|
||||
imm.vbo_id = GPU_buf_id_alloc();
|
||||
imm.vbo_id = GPU_buf_alloc();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
|
||||
glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
|
@ -127,7 +126,7 @@ void immDeactivate(void)
|
|||
|
||||
void immDestroy(void)
|
||||
{
|
||||
GPU_buf_id_free(imm.vbo_id);
|
||||
GPU_buf_free(imm.vbo_id);
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,8 +57,6 @@ void GPU_init(void)
|
|||
|
||||
gpu_extensions_init(); /* must come first */
|
||||
|
||||
GPU_texture_orphans_init();
|
||||
GPU_material_orphans_init();
|
||||
gpu_codegen_init();
|
||||
gpu_framebuffer_module_init();
|
||||
|
||||
|
@ -84,9 +82,6 @@ void GPU_exit(void)
|
|||
|
||||
gpu_batch_exit();
|
||||
|
||||
GPU_texture_orphans_exit();
|
||||
GPU_material_orphans_exit();
|
||||
|
||||
if (G.debug & G_DEBUG_GPU)
|
||||
gpu_debug_exit();
|
||||
|
||||
|
|
|
@ -75,9 +75,6 @@
|
|||
# include "BKE_DerivedMesh.h"
|
||||
#endif
|
||||
|
||||
static ListBase g_orphaned_mat = {NULL, NULL};
|
||||
static ThreadMutex g_orphan_lock;
|
||||
|
||||
/* Structs */
|
||||
|
||||
struct GPUMaterial {
|
||||
|
@ -175,44 +172,12 @@ void GPU_material_free(ListBase *gpumaterial)
|
|||
{
|
||||
for (LinkData *link = gpumaterial->first; link; link = link->next) {
|
||||
GPUMaterial *material = link->data;
|
||||
|
||||
/* TODO(fclem): Check if the thread has an ogl context. */
|
||||
if (BLI_thread_is_main()) {
|
||||
gpu_material_free_single(material);
|
||||
MEM_freeN(material);
|
||||
}
|
||||
else {
|
||||
BLI_mutex_lock(&g_orphan_lock);
|
||||
BLI_addtail(&g_orphaned_mat, BLI_genericNodeN(material));
|
||||
BLI_mutex_unlock(&g_orphan_lock);
|
||||
}
|
||||
gpu_material_free_single(material);
|
||||
MEM_freeN(material);
|
||||
}
|
||||
BLI_freelistN(gpumaterial);
|
||||
}
|
||||
|
||||
void GPU_material_orphans_init(void)
|
||||
{
|
||||
BLI_mutex_init(&g_orphan_lock);
|
||||
}
|
||||
|
||||
void GPU_material_orphans_delete(void)
|
||||
{
|
||||
BLI_mutex_lock(&g_orphan_lock);
|
||||
LinkData *link;
|
||||
while ((link = BLI_pophead(&g_orphaned_mat))) {
|
||||
gpu_material_free_single((GPUMaterial *)link->data);
|
||||
MEM_freeN(link->data);
|
||||
MEM_freeN(link);
|
||||
}
|
||||
BLI_mutex_unlock(&g_orphan_lock);
|
||||
}
|
||||
|
||||
void GPU_material_orphans_exit(void)
|
||||
{
|
||||
GPU_material_orphans_delete();
|
||||
BLI_mutex_end(&g_orphan_lock);
|
||||
}
|
||||
|
||||
GPUBuiltin GPU_get_material_builtins(GPUMaterial *material)
|
||||
{
|
||||
return material->builtins;
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#ifndef __GPU_PRIVATE_H__
|
||||
#define __GPU_PRIVATE_H__
|
||||
|
||||
struct GPUContext;
|
||||
struct GPUFrameBuffer;
|
||||
|
||||
/* call this before running any of the functions below */
|
||||
void gpu_extensions_init(void);
|
||||
void gpu_extensions_exit(void);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "DNA_space_types.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_context.h"
|
||||
#include "GPU_matrix.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
@ -572,6 +573,7 @@ void GPU_shader_transform_feedback_disable(GPUShader *UNUSED(shader))
|
|||
|
||||
void GPU_shader_free(GPUShader *shader)
|
||||
{
|
||||
BLI_assert(GPU_context_active_get() != NULL);
|
||||
BLI_assert(shader);
|
||||
|
||||
if (shader->vertex)
|
||||
|
|
|
@ -29,9 +29,11 @@
|
|||
* GPU shader interface (C --> GLSL)
|
||||
*/
|
||||
|
||||
#include "gpu_batch_private.h"
|
||||
#include "GPU_shader_interface.h"
|
||||
#include "GPU_vertex_array_id.h"
|
||||
|
||||
#include "gpu_batch_private.h"
|
||||
#include "gpu_context_private.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
|
|
@ -38,22 +38,22 @@
|
|||
#include "BKE_global.h"
|
||||
|
||||
#include "GPU_batch.h"
|
||||
#include "GPU_context.h"
|
||||
#include "GPU_debug.h"
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_glew.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "gpu_context_private.h"
|
||||
|
||||
static struct GPUTextureGlobal {
|
||||
GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */
|
||||
GPUTexture *invalid_tex_2D;
|
||||
GPUTexture *invalid_tex_3D;
|
||||
} GG = {NULL, NULL, NULL};
|
||||
|
||||
static ListBase g_orphaned_tex = {NULL, NULL};
|
||||
static ThreadMutex g_orphan_lock;
|
||||
|
||||
/* Maximum number of FBOs a texture can be attached to. */
|
||||
#define GPU_TEX_MAX_FBO_ATTACHED 8
|
||||
|
||||
|
@ -535,7 +535,7 @@ GPUTexture *GPU_texture_create_nD(
|
|||
gpu_texture_memory_footprint_add(tex);
|
||||
|
||||
/* Generate Texture object */
|
||||
glGenTextures(1, &tex->bindcode);
|
||||
tex->bindcode = GPU_tex_alloc();
|
||||
|
||||
if (!tex->bindcode) {
|
||||
if (err_out)
|
||||
|
@ -668,7 +668,7 @@ static GPUTexture *GPU_texture_cube_create(
|
|||
gpu_texture_memory_footprint_add(tex);
|
||||
|
||||
/* Generate Texture object */
|
||||
glGenTextures(1, &tex->bindcode);
|
||||
tex->bindcode = GPU_tex_alloc();
|
||||
|
||||
if (!tex->bindcode) {
|
||||
if (err_out)
|
||||
|
@ -752,7 +752,7 @@ GPUTexture *GPU_texture_create_buffer(GPUTextureFormat tex_format, const GLuint
|
|||
}
|
||||
|
||||
/* Generate Texture object */
|
||||
glGenTextures(1, &tex->bindcode);
|
||||
tex->bindcode = GPU_tex_alloc();
|
||||
|
||||
if (!tex->bindcode) {
|
||||
fprintf(stderr, "GPUTexture: texture create failed\n");
|
||||
|
@ -1301,17 +1301,6 @@ void GPU_texture_filters(GPUTexture *tex, GPUFilterFunction min_filter, GPUFilte
|
|||
glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, gpu_get_gl_filterfunction(mag_filter));
|
||||
}
|
||||
|
||||
|
||||
static void gpu_texture_delete(GPUTexture *tex)
|
||||
{
|
||||
if (tex->bindcode)
|
||||
glDeleteTextures(1, &tex->bindcode);
|
||||
|
||||
gpu_texture_memory_footprint_remove(tex);
|
||||
|
||||
MEM_freeN(tex);
|
||||
}
|
||||
|
||||
void GPU_texture_free(GPUTexture *tex)
|
||||
{
|
||||
tex->refcount--;
|
||||
|
@ -1326,40 +1315,15 @@ void GPU_texture_free(GPUTexture *tex)
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO(fclem): Check if the thread has an ogl context. */
|
||||
if (BLI_thread_is_main()) {
|
||||
gpu_texture_delete(tex);
|
||||
}
|
||||
else {
|
||||
BLI_mutex_lock(&g_orphan_lock);
|
||||
BLI_addtail(&g_orphaned_tex, BLI_genericNodeN(tex));
|
||||
BLI_mutex_unlock(&g_orphan_lock);
|
||||
}
|
||||
if (tex->bindcode)
|
||||
GPU_tex_free(tex->bindcode);
|
||||
|
||||
gpu_texture_memory_footprint_remove(tex);
|
||||
|
||||
MEM_freeN(tex);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_texture_orphans_init(void)
|
||||
{
|
||||
BLI_mutex_init(&g_orphan_lock);
|
||||
}
|
||||
|
||||
void GPU_texture_orphans_delete(void)
|
||||
{
|
||||
BLI_mutex_lock(&g_orphan_lock);
|
||||
LinkData *link;
|
||||
while ((link = BLI_pophead(&g_orphaned_tex))) {
|
||||
gpu_texture_delete((GPUTexture *)link->data);
|
||||
MEM_freeN(link);
|
||||
}
|
||||
BLI_mutex_unlock(&g_orphan_lock);
|
||||
}
|
||||
|
||||
void GPU_texture_orphans_exit(void)
|
||||
{
|
||||
GPU_texture_orphans_delete();
|
||||
BLI_mutex_end(&g_orphan_lock);
|
||||
}
|
||||
|
||||
void GPU_texture_ref(GPUTexture *tex)
|
||||
{
|
||||
tex->refcount++;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "BLI_blenlib.h"
|
||||
|
||||
#include "gpu_codegen.h"
|
||||
#include "gpu_context_private.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
#include "GPU_glew.h"
|
||||
|
@ -88,7 +89,7 @@ GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_
|
|||
ubo->bindpoint = -1;
|
||||
|
||||
/* Generate Buffer object */
|
||||
glGenBuffers(1, &ubo->bindcode);
|
||||
ubo->bindcode = GPU_buf_alloc();
|
||||
|
||||
if (!ubo->bindcode) {
|
||||
if (err_out)
|
||||
|
@ -127,7 +128,7 @@ GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_ou
|
|||
ubo->flag = GPU_UBO_FLAG_DIRTY;
|
||||
|
||||
/* Generate Buffer object. */
|
||||
glGenBuffers(1, &ubo->buffer.bindcode);
|
||||
ubo->buffer.bindcode = GPU_buf_alloc();
|
||||
|
||||
if (!ubo->buffer.bindcode) {
|
||||
if (err_out)
|
||||
|
@ -190,7 +191,7 @@ void GPU_uniformbuffer_free(GPUUniformBuffer *ubo)
|
|||
gpu_uniformbuffer_dynamic_free(ubo);
|
||||
}
|
||||
|
||||
glDeleteBuffers(1, &ubo->bindcode);
|
||||
GPU_buf_free(ubo->bindcode);
|
||||
MEM_freeN(ubo);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,10 @@
|
|||
*/
|
||||
|
||||
#include "GPU_vertex_buffer.h"
|
||||
#include "GPU_buffer_id.h"
|
||||
|
||||
#include "gpu_context_private.h"
|
||||
#include "gpu_vertex_format_private.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -88,7 +90,7 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts, const GPUVertFormat *for
|
|||
void GPU_vertbuf_discard(GPUVertBuf *verts)
|
||||
{
|
||||
if (verts->vbo_id) {
|
||||
GPU_buf_id_free(verts->vbo_id);
|
||||
GPU_buf_free(verts->vbo_id);
|
||||
#if VRAM_USAGE
|
||||
vbo_memory_usage -= GPU_vertbuf_size_get(verts);
|
||||
#endif
|
||||
|
@ -117,7 +119,7 @@ void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len)
|
|||
#endif
|
||||
/* only create the buffer the 1st time */
|
||||
if (verts->vbo_id == 0) {
|
||||
verts->vbo_id = GPU_buf_id_alloc();
|
||||
verts->vbo_id = GPU_buf_alloc();
|
||||
}
|
||||
/* discard previous data if any */
|
||||
if (verts->data) {
|
||||
|
|
|
@ -119,6 +119,7 @@
|
|||
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_immediate.h"
|
||||
#include "GPU_init_exit.h"
|
||||
|
||||
#include "BKE_sound.h"
|
||||
|
@ -515,9 +516,11 @@ void WM_exit_ext(bContext *C, const bool do_python)
|
|||
BLF_exit();
|
||||
|
||||
if (opengl_is_init) {
|
||||
DRW_opengl_context_enable_ex(false);
|
||||
GPU_pass_cache_free();
|
||||
DRW_opengl_context_destroy();
|
||||
GPU_exit();
|
||||
DRW_opengl_context_disable_ex(false);
|
||||
DRW_opengl_context_destroy();
|
||||
}
|
||||
|
||||
#ifdef WITH_INTERNATIONAL
|
||||
|
|
|
@ -1921,8 +1921,6 @@ void wm_window_raise(wmWindow *win)
|
|||
|
||||
void wm_window_swap_buffers(wmWindow *win)
|
||||
{
|
||||
GPU_texture_orphans_delete(); /* XXX should be done elsewhere. */
|
||||
GPU_material_orphans_delete(); /* XXX Amen to that. */
|
||||
GHOST_SwapWindowBuffers(win->ghostwin);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue