Blender V5.0
draw_gpu_context.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2016 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BKE_global.hh"
10
11#include "GPU_capabilities.hh"
12#include "GPU_context.hh"
13#include "GPU_state.hh"
14
15#include "RE_engine.h"
16#include "RE_pipeline.h"
17
18#include "DRW_engine.hh"
19#include "DRW_render.hh"
20
21#include "WM_api.hh"
22#include "wm_window.hh"
23
24/* -------------------------------------------------------------------- */
30
31static TicketMutex *draw_mutex = nullptr;
32static TicketMutex *submission_mutex = nullptr;
33
39
45
47{
49 BLI_assert(locked);
50 UNUSED_VARS_NDEBUG(locked);
51}
52
57
65
71
73
74/* -------------------------------------------------------------------- */
78
79/* Context that can be shared across threads. Usage is guarded by a ticket mutex.
80 * Should eventually be moved to GPU module after we get rid of the WM calls. */
82 /* Should be private but needs to be public for XR workaround. */
83 public:
84 TicketMutex *mutex_ = nullptr;
86 void *system_gpu_context_ = nullptr;
88 GPUContext *blender_gpu_context_ = nullptr;
89
90 /* NOTE: This changes the active context. */
99
110
111 void enable()
112 {
114 /* IMPORTANT: We don't support immediate mode in render mode!
115 * This shall remain in effect until immediate mode supports
116 * multiple threads. */
118
120
124 }
125
127 {
129 }
130
131 /* Restore window drawable after disabling if restore is true. */
132 void disable(bool restore = false)
133 {
135
136 if (BLI_thread_is_main() && restore) {
138 }
139 else {
141 GPU_context_active_set(nullptr);
142 }
143 /* Render boundaries are opened and closed here as this may be
144 * called outside of an existing render loop. */
146
148 DRW_lock_end();
149 }
150};
151
153
154/* -------------------------------------------------------------------- */
160
165
167{
168 BLI_assert(viewport_context == nullptr); /* Ensure it's called once */
169
171
172 viewport_context = MEM_new<ContextShared>(__func__);
173 preview_context = MEM_new<ContextShared>(__func__);
174
175 viewport_context->enable();
176}
177
179{
181 if (viewport_context == nullptr) {
182 return;
183 }
185
186 MEM_SAFE_DELETE(viewport_context);
187 MEM_SAFE_DELETE(preview_context);
188}
189
191
192/* -------------------------------------------------------------------- */
195
196void DRW_gpu_context_enable_ex(bool /*restore*/)
197{
198 if (viewport_context == nullptr) {
199 return;
200 }
201 viewport_context->enable();
202}
203
205{
206 if (viewport_context == nullptr) {
207 return;
208 }
209 viewport_context->disable(restore);
210}
211
213{
214 if (preview_context == nullptr) {
215 return;
216 }
217 preview_context->enable();
218}
219
221{
222 if (preview_context == nullptr) {
223 return;
224 }
225 preview_context->disable();
226}
227
229{
230 /* TODO: should be replace by a more elegant alternative. */
231
232 if (G.background && viewport_context == nullptr) {
233 WM_init_gpu();
234 }
236}
237
239{
240 if (viewport_context == nullptr) {
241 return false;
242 }
244 return true;
245}
246
248{
249 return viewport_context && viewport_context->is_enabled();
250}
251
256
257void DRW_system_gpu_render_context_enable(void *re_system_gpu_context)
258{
259 /* If thread is main you should use DRW_gpu_context_enable(). */
261
263 WM_system_gpu_context_activate(re_system_gpu_context);
264}
265
266void DRW_system_gpu_render_context_disable(void *re_system_gpu_context)
267{
268 WM_system_gpu_context_release(re_system_gpu_context);
269 DRW_lock_end();
270}
271
273{
274 /* If thread is main you should use DRW_gpu_context_enable(). */
276
277 GPU_context_active_set(static_cast<GPUContext *>(re_gpu_context));
278}
279
280void DRW_blender_gpu_render_context_disable(void * /*re_gpu_context*/)
281{
282 GPU_flush();
283 GPU_context_active_set(nullptr);
284}
285
287{
288 if (G.background && viewport_context == nullptr) {
289 WM_init_gpu();
290 }
291
293
297 return;
298 }
299
300 void *re_viewport_system_gpu_context = RE_system_gpu_context_get(render);
301
302 /* Changing Context */
303 if (re_viewport_system_gpu_context != nullptr) {
304 DRW_system_gpu_render_context_enable(re_viewport_system_gpu_context);
305 /* We need to query gpu context after a gl context has been bound. */
306 void *re_viewport_context = RE_blender_gpu_context_ensure(render);
307 DRW_blender_gpu_render_context_enable(re_viewport_context);
308 }
309 else {
311 }
312}
313
315{
320 return;
321 }
322
323 void *re_viewport_system_gpu_context = RE_system_gpu_context_get(render);
324
325 if (re_viewport_system_gpu_context != nullptr) {
326 void *re_viewport_context = RE_blender_gpu_context_ensure(render);
327 /* GPU rendering may occur during context disable. */
328 DRW_blender_gpu_render_context_disable(re_viewport_context);
330 DRW_system_gpu_render_context_disable(re_viewport_system_gpu_context);
331 }
332 else {
333 /* Usually the case for a preview job. The `Render` is created inside the render thread which
334 * is too late to create a GPU context. */
337 }
338}
339
341
342/* -------------------------------------------------------------------- */
345
346#ifdef WITH_XR_OPENXR
347
348void *DRW_system_gpu_context_get()
349{
350 /* XXX: There should really be no such getter, but for VR we currently can't easily avoid it.
351 * OpenXR needs some low level info for the GPU context that will be used for submitting the
352 * final frame-buffer. VR could in theory create its own context, but that would mean we have to
353 * switch to it just to submit the final frame, which has notable performance impact.
354 *
355 * We could "inject" a context through DRW_system_gpu_render_context_enable(), but that would
356 * have to work from the main thread, which is tricky to get working too. The preferable solution
357 * would be using a separate thread for VR drawing where a single context can stay active. */
358
359 return viewport_context->system_gpu_context_;
360}
361
362void *DRW_xr_blender_gpu_context_get()
363{
364 /* XXX: See comment on #DRW_system_gpu_context_get(). */
365
366 return viewport_context->blender_gpu_context_;
367}
368
369void DRW_xr_drawing_begin()
370{
371 /* XXX: See comment on #DRW_system_gpu_context_get(). */
372
375}
376
377void DRW_xr_drawing_end()
378{
379 /* XXX: See comment on #DRW_system_gpu_context_get(). */
380
382 DRW_lock_end();
383}
384
385#endif
386
388
389/* -------------------------------------------------------------------- */
416
418{
419 if (!BLI_thread_is_main()) {
420 return false;
421 }
422
423 if (GPU_context_active_get() != viewport_context->blender_gpu_context_) {
424 /* Context release is requested from the outside of the draw manager main draw loop, indicate
425 * this to the `DRW_gpu_context_activate()` so that it restores drawable of the window.
426 */
427 return false;
428 }
429
430 GPU_context_active_set(nullptr);
432
433 return true;
434}
435
436void DRW_gpu_context_activate(bool drw_state)
437{
438 if (!BLI_thread_is_main()) {
439 return;
440 }
441
442 if (drw_state) {
444 GPU_context_active_set(viewport_context->blender_gpu_context_);
445 }
446 else {
448 }
449}
450
#define BLI_assert(a)
Definition BLI_assert.h:46
TicketMutex * BLI_ticket_mutex_alloc(void)
Definition threads.cc:510
void BLI_ticket_mutex_unlock(TicketMutex *ticket)
Definition threads.cc:562
bool BLI_ticket_mutex_lock_check_recursive(TicketMutex *ticket)
Definition threads.cc:557
void BLI_ticket_mutex_lock(TicketMutex *ticket)
Definition threads.cc:552
void BLI_ticket_mutex_free(TicketMutex *ticket)
Definition threads.cc:520
int BLI_thread_is_main(void)
Definition threads.cc:179
#define UNUSED_VARS_NDEBUG(...)
bool GPU_use_main_context_workaround()
void GPU_render_end()
GPUContext * GPU_context_create(void *ghost_window, void *ghost_context)
void GPU_context_main_lock()
void GPU_context_begin_frame(GPUContext *ctx)
void GPU_render_begin()
GPUContext * GPU_context_active_get()
void GPU_context_main_unlock()
void GPU_context_discard(GPUContext *)
void GPU_context_end_frame(GPUContext *ctx)
void GPU_context_active_set(GPUContext *)
void GPU_flush()
Definition gpu_state.cc:305
TicketMutex * mutex_
void disable(bool restore=false)
GPUContext * blender_gpu_context_
void DRW_gpu_context_destroy()
static void drw_gpu_preview_context_disable()
void DRW_submission_end()
bool DRW_gpu_context_is_enabled()
void DRW_gpu_context_disable()
void DRW_gpu_context_disable_ex(bool restore)
void DRW_gpu_context_enable_ex(bool)
void DRW_system_gpu_render_context_enable(void *re_system_gpu_context)
void DRW_gpu_context_enable()
void DRW_gpu_context_create()
void DRW_gpu_context_activate(bool drw_state)
static TicketMutex * submission_mutex
void DRW_mutexes_init()
void DRW_render_context_disable(Render *render)
void DRW_blender_gpu_render_context_disable(void *)
static ContextShared * viewport_context
void DRW_mutexes_exit()
bool DRW_gpu_context_try_enable()
void DRW_system_gpu_render_context_disable(void *re_system_gpu_context)
void DRW_submission_start()
static void drw_gpu_preview_context_enable()
static TicketMutex * draw_mutex
bool DRW_gpu_context_release()
void DRW_lock_start()
void DRW_render_context_enable(Render *render)
static ContextShared * preview_context
void DRW_lock_end()
void DRW_blender_gpu_render_context_enable(void *re_gpu_context)
#define G(x, y, z)
void * RE_blender_gpu_context_ensure(Render *re)
void * RE_system_gpu_context_get(Render *re)
void WM_init_gpu()
void * WM_system_gpu_context_create()
void wm_window_reset_drawable()
void WM_system_gpu_context_dispose(void *context)
void WM_system_gpu_context_activate(void *context)
void WM_system_gpu_context_release(void *context)