Blender V4.5
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
126 /* Restore window drawable after disabling if restore is true. */
127 void disable(bool restore = false)
128 {
130
131 if (BLI_thread_is_main() && restore) {
133 }
134 else {
136 GPU_context_active_set(nullptr);
137 }
138 /* Render boundaries are opened and closed here as this may be
139 * called outside of an existing render loop. */
141
143 DRW_lock_end();
144 }
145};
146
148
149/* -------------------------------------------------------------------- */
155
160
162{
163 BLI_assert(viewport_context == nullptr); /* Ensure it's called once */
164
166
167 viewport_context = MEM_new<ContextShared>(__func__);
168 preview_context = MEM_new<ContextShared>(__func__);
169
170 /* Some part of the code assumes no context is left bound. */
171 GPU_context_active_set(nullptr);
173
174 /* Activate the window's context if any. */
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
251
252void DRW_system_gpu_render_context_enable(void *re_system_gpu_context)
253{
254 /* If thread is main you should use DRW_gpu_context_enable(). */
256
258 WM_system_gpu_context_activate(re_system_gpu_context);
259}
260
261void DRW_system_gpu_render_context_disable(void *re_system_gpu_context)
262{
263 WM_system_gpu_context_release(re_system_gpu_context);
264 DRW_lock_end();
265}
266
268{
269 /* If thread is main you should use DRW_gpu_context_enable(). */
271
272 GPU_context_active_set(static_cast<GPUContext *>(re_gpu_context));
273}
274
275void DRW_blender_gpu_render_context_disable(void * /*re_gpu_context*/)
276{
277 GPU_flush();
278 GPU_context_active_set(nullptr);
279}
280
282{
283 if (G.background && viewport_context == nullptr) {
284 WM_init_gpu();
285 }
286
288
292 return;
293 }
294
295 void *re_viewport_system_gpu_context = RE_system_gpu_context_get(render);
296
297 /* Changing Context */
298 if (re_viewport_system_gpu_context != nullptr) {
299 DRW_system_gpu_render_context_enable(re_viewport_system_gpu_context);
300 /* We need to query gpu context after a gl context has been bound. */
301 void *re_viewport_context = RE_blender_gpu_context_ensure(render);
302 DRW_blender_gpu_render_context_enable(re_viewport_context);
303 }
304 else {
306 }
307}
308
310{
315 return;
316 }
317
318 void *re_viewport_system_gpu_context = RE_system_gpu_context_get(render);
319
320 if (re_viewport_system_gpu_context != nullptr) {
321 void *re_viewport_context = RE_blender_gpu_context_ensure(render);
322 /* GPU rendering may occur during context disable. */
323 DRW_blender_gpu_render_context_disable(re_viewport_context);
325 DRW_system_gpu_render_context_disable(re_viewport_system_gpu_context);
326 }
327 else {
328 /* Usually the case for a preview job. The `Render` is created inside the render thread which
329 * is too late to create a GPU context. */
332 }
333}
334
336
337/* -------------------------------------------------------------------- */
340
341#ifdef WITH_XR_OPENXR
342
343void *DRW_system_gpu_context_get()
344{
345 /* XXX: There should really be no such getter, but for VR we currently can't easily avoid it.
346 * OpenXR needs some low level info for the GPU context that will be used for submitting the
347 * final frame-buffer. VR could in theory create its own context, but that would mean we have to
348 * switch to it just to submit the final frame, which has notable performance impact.
349 *
350 * We could "inject" a context through DRW_system_gpu_render_context_enable(), but that would
351 * have to work from the main thread, which is tricky to get working too. The preferable solution
352 * would be using a separate thread for VR drawing where a single context can stay active. */
353
354 return viewport_context->system_gpu_context_;
355}
356
357void *DRW_xr_blender_gpu_context_get()
358{
359 /* XXX: See comment on #DRW_system_gpu_context_get(). */
360
361 return viewport_context->blender_gpu_context_;
362}
363
364void DRW_xr_drawing_begin()
365{
366 /* XXX: See comment on #DRW_system_gpu_context_get(). */
367
370}
371
372void DRW_xr_drawing_end()
373{
374 /* XXX: See comment on #DRW_system_gpu_context_get(). */
375
377 DRW_lock_end();
378}
379
380#endif
381
383
384/* -------------------------------------------------------------------- */
411
413{
414 if (!BLI_thread_is_main()) {
415 return false;
416 }
417
418 if (GPU_context_active_get() != viewport_context->blender_gpu_context_) {
419 /* Context release is requested from the outside of the draw manager main draw loop, indicate
420 * this to the `DRW_gpu_context_activate()` so that it restores drawable of the window.
421 */
422 return false;
423 }
424
425 GPU_context_active_set(nullptr);
427
428 return true;
429}
430
431void DRW_gpu_context_activate(bool drw_state)
432{
433 if (!BLI_thread_is_main()) {
434 return;
435 }
436
437 if (drw_state) {
439 GPU_context_active_set(viewport_context->blender_gpu_context_);
440 }
441 else {
443 }
444}
445
#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()
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)