Blender V5.0
gl_context.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_assert.h"
10#include "BLI_utildefines.h"
11
12#include "BKE_global.hh"
13
14#include "GPU_framebuffer.hh"
15
16#include "GHOST_C-api.h"
17
20
21#include "gl_debug.hh"
22#include "gl_immediate.hh"
23#include "gl_state.hh"
24#include "gl_uniform_buffer.hh"
25
26#include "gl_backend.hh" /* TODO: remove. */
27#include "gl_context.hh"
28
29using namespace blender;
30using namespace blender::gpu;
31
32/* -------------------------------------------------------------------- */
35
36GLContext::GLContext(void *ghost_window, GLSharedOrphanLists &shared_orphan_list)
37 : shared_orphan_list_(shared_orphan_list)
38{
39 if (G.debug & G_DEBUG_GPU) {
40 debug::init_gl_callbacks();
41 }
42
43 float data[4] = {0.0f, 0.0f, 0.0f, 1.0f};
44 glGenBuffers(1, &default_attr_vbo_);
45 glBindBuffer(GL_ARRAY_BUFFER, default_attr_vbo_);
46 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
47 glBindBuffer(GL_ARRAY_BUFFER, 0);
48
50 imm = new GLImmediate();
51 ghost_window_ = ghost_window;
52
53 if (ghost_window) {
54 GLuint default_fbo = GHOST_GetDefaultGPUFramebuffer((GHOST_WindowHandle)ghost_window);
55 GHOST_RectangleHandle bounds = GHOST_GetClientBounds((GHOST_WindowHandle)ghost_window);
59
60 if (default_fbo != 0) {
61 /* Bind default framebuffer, otherwise state might be undefined. */
62 glBindFramebuffer(GL_FRAMEBUFFER, default_fbo);
63 front_left = new GLFrameBuffer("front_left", this, GL_COLOR_ATTACHMENT0, default_fbo, w, h);
64 back_left = new GLFrameBuffer("back_left", this, GL_COLOR_ATTACHMENT0, default_fbo, w, h);
65 }
66 else {
67 front_left = new GLFrameBuffer("front_left", this, GL_FRONT_LEFT, 0, w, h);
68 back_left = new GLFrameBuffer("back_left", this, GL_BACK_LEFT, 0, w, h);
69 }
70
71 GLboolean supports_stereo_quad_buffer = GL_FALSE;
72 glGetBooleanv(GL_STEREO, &supports_stereo_quad_buffer);
73 if (supports_stereo_quad_buffer) {
74 front_right = new GLFrameBuffer("front_right", this, GL_FRONT_RIGHT, 0, w, h);
75 back_right = new GLFrameBuffer("back_right", this, GL_BACK_RIGHT, 0, w, h);
76 }
77 }
78 else {
79 /* For off-screen contexts. Default frame-buffer is null. */
80 back_left = new GLFrameBuffer("back_left", this, GL_NONE, 0, 0, 0);
81 }
82
84 static_cast<GLStateManager *>(state_manager)->active_fb = static_cast<GLFrameBuffer *>(
85 active_fb);
86}
87
89{
90 if (G.profile_gpu) {
91 /* Ensure query results are available. */
92 finish();
93 process_frame_timings();
94 }
96 BLI_assert(orphaned_framebuffers_.is_empty());
97 BLI_assert(orphaned_vertarrays_.is_empty());
98 /* For now don't allow GPUFrameBuffers to be reuse in another context. */
99 BLI_assert(framebuffers_.is_empty());
100 /* Delete VAO's so the batch can be reused in another context. */
101 for (GLVaoCache *cache : vao_caches_) {
102 cache->clear();
103 }
104 glDeleteBuffers(1, &default_attr_vbo_);
105}
106
108
109/* -------------------------------------------------------------------- */
112
114{
115 /* Make sure no other context is already bound to this thread. */
116 BLI_assert(is_active_ == false);
117
118 is_active_ = true;
119 thread_ = pthread_self();
120
121 /* Clear accumulated orphans. */
122 orphans_clear();
123
124 if (ghost_window_) {
125 /* Get the correct framebuffer size for the internal framebuffers. */
126 GHOST_RectangleHandle bounds = GHOST_GetClientBounds((GHOST_WindowHandle)ghost_window_);
130
131 if (front_left) {
132 front_left->size_set(w, h);
133 }
134 if (back_left) {
135 back_left->size_set(w, h);
136 }
137 if (front_right) {
138 front_right->size_set(w, h);
139 }
140 if (back_right) {
141 back_right->size_set(w, h);
142 }
143 }
144
145 /* Not really following the state but we should consider
146 * no ubo bound when activating a context. */
147 bound_ubo_slots = 0;
149
150 immActivate();
151}
152
154{
156 is_active_ = false;
157}
158
160{
161 /* No-op. */
162}
163
165{
166 process_frame_timings();
167}
168
170
171/* -------------------------------------------------------------------- */
174
176{
177 glFlush();
178}
179
181{
182 glFinish();
183}
184
186
187/* -------------------------------------------------------------------- */
193
194void GLSharedOrphanLists::OrphanList::clear(FunctionRef<void(GLuint, GLuint *)> free_fn)
195{
196 std::scoped_lock lock(mutex_);
197 if (!handles_.is_empty()) {
198 free_fn(uint(handles_.size()), handles_.data());
199 handles_.clear();
200 }
201};
202
203void GLSharedOrphanLists::OrphanList::append(GLuint handle)
204{
205 std::scoped_lock lock(mutex_);
206 handles_.append(handle);
207};
208
210{
211 /* Check if any context is active on this thread! */
213
214 buffers.clear(glDeleteBuffers);
215 textures.clear(glDeleteTextures);
216 shaders.clear([](GLuint size, GLuint *handles) {
217 for (uint i = 0; i < size; i++) {
218 glDeleteShader(handles[i]);
219 }
220 });
221 programs.clear([](GLuint size, GLuint *handles) {
222 for (uint i = 0; i < size; i++) {
223 glDeleteProgram(handles[i]);
224 }
225 });
226};
227
228void GLContext::orphans_clear()
229{
230 /* Check if context has been activated by another thread! */
231 BLI_assert(this->is_active_on_thread());
232
233 lists_mutex_.lock();
234 if (!orphaned_vertarrays_.is_empty()) {
235 glDeleteVertexArrays(uint(orphaned_vertarrays_.size()), orphaned_vertarrays_.data());
236 orphaned_vertarrays_.clear();
237 }
238 if (!orphaned_framebuffers_.is_empty()) {
239 glDeleteFramebuffers(uint(orphaned_framebuffers_.size()), orphaned_framebuffers_.data());
240 orphaned_framebuffers_.clear();
241 }
242 lists_mutex_.unlock();
243
244 shared_orphan_list_.orphans_clear();
245};
246
247void GLContext::orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, GLuint id)
248{
249 list_mutex.lock();
250 orphan_list.append(id);
251 list_mutex.unlock();
252}
253
254void GLContext::vao_free(GLuint vao_id)
255{
256 if (this == GLContext::get()) {
257 glDeleteVertexArrays(1, &vao_id);
258 }
259 else {
260 orphans_add(orphaned_vertarrays_, lists_mutex_, vao_id);
261 }
262}
263
264void GLContext::fbo_free(GLuint fbo_id)
265{
266 if (this == GLContext::get()) {
267 glDeleteFramebuffers(1, &fbo_id);
268 }
269 else {
270 orphans_add(orphaned_framebuffers_, lists_mutex_, fbo_id);
271 }
272}
273
274void GLContext::buffer_free(GLuint buf_id)
275{
276 /* Any context can free. */
277 if (GLContext::get()) {
278 glDeleteBuffers(1, &buf_id);
279 }
280 else {
282 orphan_list.buffers.append(buf_id);
283 }
284}
285
286void GLContext::texture_free(GLuint tex_id)
287{
288 /* Any context can free. */
289 if (GLContext::get()) {
290 glDeleteTextures(1, &tex_id);
291 }
292 else {
294 orphan_list.textures.append(tex_id);
295 }
296}
297
298void GLContext::shader_free(GLuint shader_id)
299{
300 /* Any context can free. */
301 if (GLContext::get()) {
302 glDeleteShader(shader_id);
303 }
304 else {
306 orphan_list.shaders.append(shader_id);
307 }
308}
309
310void GLContext::program_free(GLuint program_id)
311{
312 /* Any context can free. */
313 if (GLContext::get()) {
314 glDeleteProgram(program_id);
315 }
316 else {
318 orphan_list.programs.append(program_id);
319 }
320}
321
323
324/* -------------------------------------------------------------------- */
331
333{
334 lists_mutex_.lock();
335 vao_caches_.add(cache);
336 lists_mutex_.unlock();
337}
338
340{
341 lists_mutex_.lock();
342 vao_caches_.remove(cache);
343 lists_mutex_.unlock();
344}
345
347
348/* -------------------------------------------------------------------- */
351
352void GLContext::memory_statistics_get(int *r_total_mem, int *r_free_mem)
353{
354 if (epoxy_has_gl_extension("GL_NVX_gpu_memory_info")) {
355 /* Returned value in Kb. */
356 glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, r_total_mem);
357 glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, r_free_mem);
358 }
359 else if (epoxy_has_gl_extension("GL_ATI_meminfo")) {
360 int stats[4];
361 glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats);
362
363 *r_total_mem = 0;
364 *r_free_mem = stats[0]; /* Total memory free in the pool. */
365 }
366 else {
367 *r_total_mem = 0;
368 *r_free_mem = 0;
369 }
370}
371
@ G_DEBUG_GPU
#define BLI_assert(a)
Definition BLI_assert.h:46
unsigned int uint
GHOST C-API function and type declarations.
int32_t GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle)
void GHOST_DisposeRectangle(GHOST_RectangleHandle rectanglehandle)
int32_t GHOST_GetHeightRectangle(GHOST_RectangleHandle rectanglehandle)
unsigned int GHOST_GetDefaultGPUFramebuffer(GHOST_WindowHandle windowhandle)
GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle)
volatile int lock
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
int64_t size() const
bool is_empty() const
T * data()
void clear()
void append(const T &value)
GLSharedOrphanLists & shared_orphan_list_get()
static GLBackend * get()
Definition gl_backend.hh:79
void memory_statistics_get(int *r_total_mem, int *r_free_mem) override
static void buffer_free(GLuint buf_id)
void begin_frame() override
void activate() override
void flush() override
static void shader_free(GLuint shader_id)
GLContext(void *ghost_window, GLSharedOrphanLists &shared_orphan_list)
Definition gl_context.cc:36
void vao_cache_unregister(GLVaoCache *cache)
static GLContext * get()
void finish() override
static void texture_free(GLuint tex_id)
void deactivate() override
void vao_free(GLuint vao_id)
static void program_free(GLuint program_id)
void end_frame() override
void vao_cache_register(GLVaoCache *cache)
void fbo_free(GLuint fbo_id)
void immDeactivate()
void immActivate()
#define G(x, y, z)
i
Definition text_draw.cc:230
ParamHandle ** handles