Blender  V3.3
gl_context.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. All rights reserved. */
3 
8 #include "BLI_assert.h"
9 #include "BLI_utildefines.h"
10 
11 #include "BKE_global.h"
12 
13 #include "GPU_framebuffer.h"
14 
15 #include "GHOST_C-api.h"
16 
17 #include "gpu_context_private.hh"
18 #include "gpu_immediate_private.hh"
19 
20 #include "gl_debug.hh"
21 #include "gl_immediate.hh"
22 #include "gl_state.hh"
23 #include "gl_uniform_buffer.hh"
24 
25 #include "gl_backend.hh" /* TODO: remove. */
26 #include "gl_context.hh"
27 
28 using namespace blender;
29 using namespace blender::gpu;
30 
31 /* -------------------------------------------------------------------- */
35 GLContext::GLContext(void *ghost_window, GLSharedOrphanLists &shared_orphan_list)
36  : shared_orphan_list_(shared_orphan_list)
37 {
38  if (G.debug & G_DEBUG_GPU) {
40  }
41 
42  float data[4] = {0.0f, 0.0f, 0.0f, 1.0f};
43  glGenBuffers(1, &default_attr_vbo_);
44  glBindBuffer(GL_ARRAY_BUFFER, default_attr_vbo_);
45  glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
46  glBindBuffer(GL_ARRAY_BUFFER, 0);
47 
49  imm = new GLImmediate();
50  ghost_window_ = ghost_window;
51 
52  if (ghost_window) {
53  GLuint default_fbo = GHOST_GetDefaultOpenGLFramebuffer((GHOST_WindowHandle)ghost_window);
54  GHOST_RectangleHandle bounds = GHOST_GetClientBounds((GHOST_WindowHandle)ghost_window);
58 
59  if (default_fbo != 0) {
60  /* Bind default framebuffer, otherwise state might be undefined because of
61  * detect_mip_render_workaround(). */
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  BLI_assert(orphaned_framebuffers_.is_empty());
91  BLI_assert(orphaned_vertarrays_.is_empty());
92  /* For now don't allow GPUFrameBuffers to be reuse in another context. */
93  BLI_assert(framebuffers_.is_empty());
94  /* Delete VAO's so the batch can be reused in another context. */
95  for (GLVaoCache *cache : vao_caches_) {
96  cache->clear();
97  }
98  glDeleteBuffers(1, &default_attr_vbo_);
99 }
100 
103 /* -------------------------------------------------------------------- */
108 {
109  /* Make sure no other context is already bound to this thread. */
110  BLI_assert(is_active_ == false);
111 
112  is_active_ = true;
113  thread_ = pthread_self();
114 
115  /* Clear accumulated orphans. */
116  orphans_clear();
117 
118  if (ghost_window_) {
119  /* Get the correct framebuffer size for the internal framebuffers. */
120  GHOST_RectangleHandle bounds = GHOST_GetClientBounds((GHOST_WindowHandle)ghost_window_);
124 
125  if (front_left) {
126  front_left->size_set(w, h);
127  }
128  if (back_left) {
129  back_left->size_set(w, h);
130  }
131  if (front_right) {
132  front_right->size_set(w, h);
133  }
134  if (back_right) {
135  back_right->size_set(w, h);
136  }
137  }
138 
139  /* Not really following the state but we should consider
140  * no ubo bound when activating a context. */
141  bound_ubo_slots = 0;
142 
143  immActivate();
144 }
145 
147 {
148  immDeactivate();
149  is_active_ = false;
150 }
151 
153 {
154  /* No-op. */
155 }
156 
158 {
159  /* No-op. */
160 }
161 
164 /* -------------------------------------------------------------------- */
169 {
170  glFlush();
171 }
172 
174 {
175  glFinish();
176 }
177 
180 /* -------------------------------------------------------------------- */
188 {
189  /* Check if any context is active on this thread! */
191 
192  lists_mutex.lock();
193  if (!buffers.is_empty()) {
194  glDeleteBuffers((uint)buffers.size(), buffers.data());
195  buffers.clear();
196  }
197  if (!textures.is_empty()) {
198  glDeleteTextures((uint)textures.size(), textures.data());
199  textures.clear();
200  }
201  lists_mutex.unlock();
202 };
203 
204 void GLContext::orphans_clear()
205 {
206  /* Check if context has been activated by another thread! */
208 
209  lists_mutex_.lock();
210  if (!orphaned_vertarrays_.is_empty()) {
211  glDeleteVertexArrays((uint)orphaned_vertarrays_.size(), orphaned_vertarrays_.data());
212  orphaned_vertarrays_.clear();
213  }
214  if (!orphaned_framebuffers_.is_empty()) {
215  glDeleteFramebuffers((uint)orphaned_framebuffers_.size(), orphaned_framebuffers_.data());
216  orphaned_framebuffers_.clear();
217  }
218  lists_mutex_.unlock();
219 
220  shared_orphan_list_.orphans_clear();
221 };
222 
223 void GLContext::orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, GLuint id)
224 {
225  list_mutex.lock();
226  orphan_list.append(id);
227  list_mutex.unlock();
228 }
229 
230 void GLContext::vao_free(GLuint vao_id)
231 {
232  if (this == GLContext::get()) {
233  glDeleteVertexArrays(1, &vao_id);
234  }
235  else {
236  orphans_add(orphaned_vertarrays_, lists_mutex_, vao_id);
237  }
238 }
239 
240 void GLContext::fbo_free(GLuint fbo_id)
241 {
242  if (this == GLContext::get()) {
243  glDeleteFramebuffers(1, &fbo_id);
244  }
245  else {
246  orphans_add(orphaned_framebuffers_, lists_mutex_, fbo_id);
247  }
248 }
249 
250 void GLContext::buf_free(GLuint buf_id)
251 {
252  /* Any context can free. */
253  if (GLContext::get()) {
254  glDeleteBuffers(1, &buf_id);
255  }
256  else {
258  orphans_add(orphan_list.buffers, orphan_list.lists_mutex, buf_id);
259  }
260 }
261 
262 void GLContext::tex_free(GLuint tex_id)
263 {
264  /* Any context can free. */
265  if (GLContext::get()) {
266  glDeleteTextures(1, &tex_id);
267  }
268  else {
270  orphans_add(orphan_list.textures, orphan_list.lists_mutex, tex_id);
271  }
272 }
273 
276 /* -------------------------------------------------------------------- */
285 {
286  lists_mutex_.lock();
287  vao_caches_.add(cache);
288  lists_mutex_.unlock();
289 }
290 
292 {
293  lists_mutex_.lock();
294  vao_caches_.remove(cache);
295  lists_mutex_.unlock();
296 }
297 
300 /* -------------------------------------------------------------------- */
304 void GLContext::memory_statistics_get(int *r_total_mem, int *r_free_mem)
305 {
306  /* TODO(merwin): use Apple's platform API to get this info. */
307  if (GLEW_NVX_gpu_memory_info) {
308  /* Returned value in Kb. */
309  glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, r_total_mem);
310  glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, r_free_mem);
311  }
312  else if (GLEW_ATI_meminfo) {
313  int stats[4];
314  glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats);
315 
316  *r_total_mem = 0;
317  *r_free_mem = stats[0]; /* Total memory free in the pool. */
318  }
319  else {
320  *r_total_mem = 0;
321  *r_free_mem = 0;
322  }
323 }
324 
@ G_DEBUG_GPU
Definition: BKE_global.h:193
#define BLI_assert(a)
Definition: BLI_assert.h:46
unsigned int uint
Definition: BLI_sys_types.h:67
ThreadMutex mutex
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_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle)
GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle)
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition: btDbvt.cpp:299
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
bool is_empty() const
Definition: BLI_set.hh:547
int64_t size() const
Definition: BLI_vector.hh:694
void append(const T &value)
Definition: BLI_vector.hh:433
bool is_empty() const
Definition: BLI_vector.hh:706
void size_set(int width, int height)
static GLBackend * get()
Definition: gl_backend.hh:54
GLSharedOrphanLists & shared_orphan_list_get()
Definition: gl_backend.hh:119
static void buf_free(GLuint buf_id)
Definition: gl_context.cc:250
void begin_frame() override
Definition: gl_context.cc:152
void activate() override
Definition: gl_context.cc:107
void flush() override
Definition: gl_context.cc:168
void memory_statistics_get(int *total_mem, int *free_mem) override
Definition: gl_context.cc:304
GLContext(void *ghost_window, GLSharedOrphanLists &shared_orphan_list)
Definition: gl_context.cc:35
void vao_cache_unregister(GLVaoCache *cache)
Definition: gl_context.cc:291
static GLContext * get()
Definition: gl_context.hh:117
void finish() override
Definition: gl_context.cc:173
static void tex_free(GLuint tex_id)
Definition: gl_context.cc:262
void deactivate() override
Definition: gl_context.cc:146
void vao_free(GLuint vao_id)
Definition: gl_context.cc:230
void end_frame() override
Definition: gl_context.cc:157
void vao_cache_register(GLVaoCache *cache)
Definition: gl_context.cc:284
void fbo_free(GLuint fbo_id)
Definition: gl_context.cc:240
void immDeactivate()
void immActivate()
#define G(x, y, z)
void init_gl_callbacks()
Definition: gl_debug.cc:134