Blender V4.5
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 because of
62 * detect_mip_render_workaround(). */
63 glBindFramebuffer(GL_FRAMEBUFFER, default_fbo);
64 front_left = new GLFrameBuffer("front_left", this, GL_COLOR_ATTACHMENT0, default_fbo, w, h);
65 back_left = new GLFrameBuffer("back_left", this, GL_COLOR_ATTACHMENT0, default_fbo, w, h);
66 }
67 else {
68 front_left = new GLFrameBuffer("front_left", this, GL_FRONT_LEFT, 0, w, h);
69 back_left = new GLFrameBuffer("back_left", this, GL_BACK_LEFT, 0, w, h);
70 }
71
72 GLboolean supports_stereo_quad_buffer = GL_FALSE;
73 glGetBooleanv(GL_STEREO, &supports_stereo_quad_buffer);
74 if (supports_stereo_quad_buffer) {
75 front_right = new GLFrameBuffer("front_right", this, GL_FRONT_RIGHT, 0, w, h);
76 back_right = new GLFrameBuffer("back_right", this, GL_BACK_RIGHT, 0, w, h);
77 }
78 }
79 else {
80 /* For off-screen contexts. Default frame-buffer is null. */
81 back_left = new GLFrameBuffer("back_left", this, GL_NONE, 0, 0, 0);
82 }
83
85 static_cast<GLStateManager *>(state_manager)->active_fb = static_cast<GLFrameBuffer *>(
86 active_fb);
87}
88
90{
91 if (G.profile_gpu) {
92 /* Ensure query results are available. */
93 finish();
94 process_frame_timings();
95 }
97 BLI_assert(orphaned_framebuffers_.is_empty());
98 BLI_assert(orphaned_vertarrays_.is_empty());
99 /* For now don't allow GPUFrameBuffers to be reuse in another context. */
100 BLI_assert(framebuffers_.is_empty());
101 /* Delete VAO's so the batch can be reused in another context. */
102 for (GLVaoCache *cache : vao_caches_) {
103 cache->clear();
104 }
105 glDeleteBuffers(1, &default_attr_vbo_);
106}
107
109
110/* -------------------------------------------------------------------- */
113
115{
116 /* Make sure no other context is already bound to this thread. */
117 BLI_assert(is_active_ == false);
118
119 is_active_ = true;
120 thread_ = pthread_self();
121
122 /* Clear accumulated orphans. */
123 orphans_clear();
124
125 if (ghost_window_) {
126 /* Get the correct framebuffer size for the internal framebuffers. */
127 GHOST_RectangleHandle bounds = GHOST_GetClientBounds((GHOST_WindowHandle)ghost_window_);
131
132 if (front_left) {
133 front_left->size_set(w, h);
134 }
135 if (back_left) {
136 back_left->size_set(w, h);
137 }
138 if (front_right) {
139 front_right->size_set(w, h);
140 }
141 if (back_right) {
142 back_right->size_set(w, h);
143 }
144 }
145
146 /* Not really following the state but we should consider
147 * no ubo bound when activating a context. */
148 bound_ubo_slots = 0;
150
151 immActivate();
152}
153
155{
157 is_active_ = false;
158}
159
161{
162 /* No-op. */
163}
164
166{
167 process_frame_timings();
168}
169
171
172/* -------------------------------------------------------------------- */
175
177{
178 glFlush();
179}
180
182{
183 glFinish();
184}
185
187
188/* -------------------------------------------------------------------- */
194
196{
197 /* Check if any context is active on this thread! */
199
200 lists_mutex.lock();
201 if (!buffers.is_empty()) {
202 glDeleteBuffers(uint(buffers.size()), buffers.data());
203 buffers.clear();
204 }
205 if (!textures.is_empty()) {
206 glDeleteTextures(uint(textures.size()), textures.data());
207 textures.clear();
208 }
209 lists_mutex.unlock();
210};
211
212void GLContext::orphans_clear()
213{
214 /* Check if context has been activated by another thread! */
216
217 lists_mutex_.lock();
218 if (!orphaned_vertarrays_.is_empty()) {
219 glDeleteVertexArrays(uint(orphaned_vertarrays_.size()), orphaned_vertarrays_.data());
220 orphaned_vertarrays_.clear();
221 }
222 if (!orphaned_framebuffers_.is_empty()) {
223 glDeleteFramebuffers(uint(orphaned_framebuffers_.size()), orphaned_framebuffers_.data());
224 orphaned_framebuffers_.clear();
225 }
226 lists_mutex_.unlock();
227
228 shared_orphan_list_.orphans_clear();
229};
230
231void GLContext::orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, GLuint id)
232{
233 list_mutex.lock();
234 orphan_list.append(id);
235 list_mutex.unlock();
236}
237
238void GLContext::vao_free(GLuint vao_id)
239{
240 if (this == GLContext::get()) {
241 glDeleteVertexArrays(1, &vao_id);
242 }
243 else {
244 orphans_add(orphaned_vertarrays_, lists_mutex_, vao_id);
245 }
246}
247
248void GLContext::fbo_free(GLuint fbo_id)
249{
250 if (this == GLContext::get()) {
251 glDeleteFramebuffers(1, &fbo_id);
252 }
253 else {
254 orphans_add(orphaned_framebuffers_, lists_mutex_, fbo_id);
255 }
256}
257
258void GLContext::buf_free(GLuint buf_id)
259{
260 /* Any context can free. */
261 if (GLContext::get()) {
262 glDeleteBuffers(1, &buf_id);
263 }
264 else {
266 orphans_add(orphan_list.buffers, orphan_list.lists_mutex, buf_id);
267 }
268}
269
270void GLContext::tex_free(GLuint tex_id)
271{
272 /* Any context can free. */
273 if (GLContext::get()) {
274 glDeleteTextures(1, &tex_id);
275 }
276 else {
278 orphans_add(orphan_list.textures, orphan_list.lists_mutex, tex_id);
279 }
280}
281
283
284/* -------------------------------------------------------------------- */
291
293{
294 lists_mutex_.lock();
295 vao_caches_.add(cache);
296 lists_mutex_.unlock();
297}
298
300{
301 lists_mutex_.lock();
302 vao_caches_.remove(cache);
303 lists_mutex_.unlock();
304}
305
307
308/* -------------------------------------------------------------------- */
311
312void GLContext::memory_statistics_get(int *r_total_mem, int *r_free_mem)
313{
314 if (epoxy_has_gl_extension("GL_NVX_gpu_memory_info")) {
315 /* Returned value in Kb. */
316 glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, r_total_mem);
317 glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, r_free_mem);
318 }
319 else if (epoxy_has_gl_extension("GL_ATI_meminfo")) {
320 int stats[4];
321 glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats);
322
323 *r_total_mem = 0;
324 *r_free_mem = stats[0]; /* Total memory free in the pool. */
325 }
326 else {
327 *r_total_mem = 0;
328 *r_free_mem = 0;
329 }
330}
331
@ 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)
BMesh const char void * data
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
static void buf_free(GLuint buf_id)
void memory_statistics_get(int *r_total_mem, int *r_free_mem) override
void begin_frame() override
void activate() override
void flush() override
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 tex_free(GLuint tex_id)
void deactivate() override
void vao_free(GLuint vao_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)