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/opengl/gl_context.cc
Clément Foucault efc97b3919 GPUBatch: GL backend isolation
This changes the drawing paradigm a bit. The VAO configuration is done
JIT-style and depends on context active shader.

This is to allow more flexibility for implementations to do optimization
at lower level.

The vao cache is now its own class to isolate the concept. It is this
class that is reference by the GLContext for ownership of the containing
VAO ids.
2020-08-13 14:20:24 +02:00

237 lines
5.8 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.
*
* Copyright 2020, Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup gpu
*/
#include "BLI_assert.h"
#include "BLI_utildefines.h"
#include "GPU_framebuffer.h"
#include "GHOST_C-api.h"
#include "gpu_context_private.hh"
#include "gl_backend.hh" /* TODO remove */
#include "gl_context.hh"
using namespace blender;
using namespace blender::gpu;
/* -------------------------------------------------------------------- */
/** \name Constructor / Destructor
* \{ */
GLContext::GLContext(void *ghost_window, GLSharedOrphanLists &shared_orphan_list)
: shared_orphan_list_(shared_orphan_list)
{
default_framebuffer_ = ghost_window ?
GHOST_GetDefaultOpenGLFramebuffer((GHOST_WindowHandle)ghost_window) :
0;
glGenVertexArrays(1, &default_vao_);
float data[4] = {0.0f, 0.0f, 0.0f, 1.0f};
glGenBuffers(1, &default_attr_vbo_);
glBindBuffer(GL_ARRAY_BUFFER, default_attr_vbo_);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
GLContext::~GLContext()
{
BLI_assert(orphaned_framebuffers_.is_empty());
BLI_assert(orphaned_vertarrays_.is_empty());
/* For now don't allow GPUFrameBuffers to be reuse in another context. */
BLI_assert(framebuffers_.is_empty());
/* Delete vaos so the batch can be reused in another context. */
for (GLVaoCache *cache : vao_caches_) {
cache->clear();
}
glDeleteVertexArrays(1, &default_vao_);
glDeleteBuffers(1, &default_attr_vbo_);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Activate / Deactivate context
* \{ */
void GLContext::activate(void)
{
/* Make sure no other context is already bound to this thread. */
BLI_assert(is_active_ == false);
is_active_ = true;
thread_ = pthread_self();
/* Clear accumulated orphans. */
orphans_clear();
}
void GLContext::deactivate(void)
{
is_active_ = false;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Safe object deletion
*
* GPU objects can be freed when the context is not bound.
* In this case we delay the deletion until the context is bound again.
* \{ */
void GLSharedOrphanLists::orphans_clear(void)
{
/* Check if any context is active on this thread! */
BLI_assert(GPU_context_active_get());
lists_mutex.lock();
if (!buffers.is_empty()) {
glDeleteBuffers((uint)buffers.size(), buffers.data());
buffers.clear();
}
if (!textures.is_empty()) {
glDeleteTextures((uint)textures.size(), textures.data());
textures.clear();
}
lists_mutex.unlock();
};
void GLContext::orphans_clear(void)
{
/* Check if context has been activated by another thread! */
BLI_assert(this->is_active_on_thread());
lists_mutex_.lock();
if (!orphaned_vertarrays_.is_empty()) {
glDeleteVertexArrays((uint)orphaned_vertarrays_.size(), orphaned_vertarrays_.data());
orphaned_vertarrays_.clear();
}
if (!orphaned_framebuffers_.is_empty()) {
glDeleteFramebuffers((uint)orphaned_framebuffers_.size(), orphaned_framebuffers_.data());
orphaned_framebuffers_.clear();
}
lists_mutex_.unlock();
shared_orphan_list_.orphans_clear();
};
void GLContext::orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, GLuint id)
{
list_mutex.lock();
orphan_list.append(id);
list_mutex.unlock();
}
void GLContext::vao_free(GLuint vao_id)
{
if (this == GPU_context_active_get()) {
glDeleteVertexArrays(1, &vao_id);
}
else {
orphans_add(orphaned_vertarrays_, lists_mutex_, vao_id);
}
}
void GLContext::fbo_free(GLuint fbo_id)
{
if (this == GPU_context_active_get()) {
glDeleteFramebuffers(1, &fbo_id);
}
else {
orphans_add(orphaned_framebuffers_, lists_mutex_, fbo_id);
}
}
void GLBackend::buf_free(GLuint buf_id)
{
/* Any context can free. */
if (GPU_context_active_get()) {
glDeleteBuffers(1, &buf_id);
}
else {
orphans_add(shared_orphan_list_.buffers, shared_orphan_list_.lists_mutex, buf_id);
}
}
void GLBackend::tex_free(GLuint tex_id)
{
/* Any context can free. */
if (GPU_context_active_get()) {
glDeleteTextures(1, &tex_id);
}
else {
orphans_add(shared_orphan_list_.textures, shared_orphan_list_.lists_mutex, tex_id);
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Linked object deletion
*
* These objects contain data that are stored per context. We
* need to do some cleanup if they are used across context or if context
* is discarded.
* \{ */
void GLContext::vao_cache_register(GLVaoCache *cache)
{
lists_mutex_.lock();
vao_caches_.add(cache);
lists_mutex_.unlock();
}
void GLContext::vao_cache_unregister(GLVaoCache *cache)
{
lists_mutex_.lock();
vao_caches_.remove(cache);
lists_mutex_.unlock();
}
void GLContext::framebuffer_register(struct GPUFrameBuffer *fb)
{
#ifdef DEBUG
lists_mutex_.lock();
framebuffers_.add(fb);
lists_mutex_.unlock();
#else
UNUSED_VARS(fb);
#endif
}
void GLContext::framebuffer_unregister(struct GPUFrameBuffer *fb)
{
#ifdef DEBUG
lists_mutex_.lock();
framebuffers_.remove(fb);
lists_mutex_.unlock();
#else
UNUSED_VARS(fb);
#endif
}
/** \} */