Blender V4.5
gpu_py_offscreen.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2015 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14
15#include <Python.h>
16
17#include "BLI_string.h"
18
19#include "BKE_global.hh"
20#include "BKE_lib_id.hh" /* For #BKE_id_is_in_global_main. */
21#include "BKE_scene.hh"
22
23#include "DNA_view3d_types.h"
24
25#include "GPU_context.hh"
26#include "GPU_framebuffer.hh"
27#include "GPU_state.hh"
28#include "GPU_texture.hh"
29#include "GPU_viewport.hh"
30
32
34
36#include "../generic/python_compat.hh" /* IWYU pragma: keep. */
37
38#include "gpu_py.hh"
39#include "gpu_py_texture.hh"
40
41#include "gpu_py_offscreen.hh" /* own include */
42
43/* Define the free method to avoid breakage. */
44#define BPYGPU_USE_GPUOBJ_FREE_METHOD
45
46/* -------------------------------------------------------------------- */
49
51 {GPU_RGBA8, "RGBA8"},
52 {GPU_RGBA16, "RGBA16"},
53 {GPU_RGBA16F, "RGBA16F"},
54 {GPU_RGBA32F, "RGBA32F"},
55 {0, nullptr},
56};
57
59{
60 if (UNLIKELY(py_ofs->ofs == nullptr)) {
61 PyErr_SetString(PyExc_ReferenceError,
63 "GPU offscreen was freed, no further access is valid"
64#else
65 "GPU offscreen: internal error"
66#endif
67 );
68 return -1;
69 }
70 return 0;
71}
72
73#define BPY_GPU_OFFSCREEN_CHECK_OBJ(bpygpu) \
74 { \
75 if (UNLIKELY(pygpu_offscreen_valid_check(bpygpu) == -1)) { \
76 return nullptr; \
77 } \
78 } \
79 ((void)0)
80
82
83/* -------------------------------------------------------------------- */
89
91 PyObject_HEAD /* Required Python macro. */
93 int level;
94 bool is_explicitly_bound; /* Bound by "bind" method. */
95};
96
98{
99 Py_DECREF(self->py_offscreen);
100 PyObject_DEL(self);
101}
102
104{
106
107 BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen);
108
109 if (!self->is_explicitly_bound) {
110 if (self->level != -1) {
111 PyErr_SetString(PyExc_RuntimeError, "Already in use");
112 return nullptr;
113 }
114
115 GPU_offscreen_bind(self->py_offscreen->ofs, true);
117 }
118
119 Py_RETURN_NONE;
120}
121
123 PyObject * /*args*/)
124{
126
127 BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen);
128
129 if (self->level == -1) {
130 PyErr_SetString(PyExc_RuntimeError, "Not yet in use\n");
131 return nullptr;
132 }
133
134 const int level = GPU_framebuffer_stack_level_get();
135 if (level != self->level) {
136 PyErr_Format(
137 PyExc_RuntimeError, "Level of bind mismatch, expected %d, got %d\n", self->level, level);
138 }
139
140 GPU_offscreen_unbind(self->py_offscreen->ofs, true);
141 Py_RETURN_NONE;
142}
143
144#ifdef __GNUC__
145# ifdef __clang__
146# pragma clang diagnostic push
147# pragma clang diagnostic ignored "-Wcast-function-type"
148# else
149# pragma GCC diagnostic push
150# pragma GCC diagnostic ignored "-Wcast-function-type"
151# endif
152#endif
153
155 {"__enter__", (PyCFunction)pygpu_offscreen_stack_context_enter, METH_NOARGS},
156 {"__exit__", (PyCFunction)pygpu_offscreen_stack_context_exit, METH_VARARGS},
157 {nullptr},
158};
159
160#ifdef __GNUC__
161# ifdef __clang__
162# pragma clang diagnostic pop
163# else
164# pragma GCC diagnostic pop
165# endif
166#endif
167
168static PyTypeObject PyGPUOffscreenStackContext_Type = {
169 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
170 /*tp_name*/ "GPUFrameBufferStackContext",
171 /*tp_basicsize*/ sizeof(OffScreenStackContext),
172 /*tp_itemsize*/ 0,
173 /*tp_dealloc*/ (destructor)pygpu_offscreen_stack_context__tp_dealloc,
174 /*tp_vectorcall_offset*/ 0,
175 /*tp_getattr*/ nullptr,
176 /*tp_setattr*/ nullptr,
177 /*tp_as_async*/ nullptr,
178 /*tp_repr*/ nullptr,
179 /*tp_as_number*/ nullptr,
180 /*tp_as_sequence*/ nullptr,
181 /*tp_as_mapping*/ nullptr,
182 /*tp_hash*/ nullptr,
183 /*tp_call*/ nullptr,
184 /*tp_str*/ nullptr,
185 /*tp_getattro*/ nullptr,
186 /*tp_setattro*/ nullptr,
187 /*tp_as_buffer*/ nullptr,
188 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
189 /*tp_doc*/ nullptr,
190 /*tp_traverse*/ nullptr,
191 /*tp_clear*/ nullptr,
192 /*tp_richcompare*/ nullptr,
193 /*tp_weaklistoffset*/ 0,
194 /*tp_iter*/ nullptr,
195 /*tp_iternext*/ nullptr,
197 /*tp_members*/ nullptr,
198 /*tp_getset*/ nullptr,
199 /*tp_base*/ nullptr,
200 /*tp_dict*/ nullptr,
201 /*tp_descr_get*/ nullptr,
202 /*tp_descr_set*/ nullptr,
203 /*tp_dictoffset*/ 0,
204 /*tp_init*/ nullptr,
205 /*tp_alloc*/ nullptr,
206 /*tp_new*/ nullptr,
207 /*tp_free*/ nullptr,
208 /*tp_is_gc*/ nullptr,
209 /*tp_bases*/ nullptr,
210 /*tp_mro*/ nullptr,
211 /*tp_cache*/ nullptr,
212 /*tp_subclasses*/ nullptr,
213 /*tp_weaklist*/ nullptr,
214 /*tp_del*/ nullptr,
215 /*tp_version_tag*/ 0,
216 /*tp_finalize*/ nullptr,
217 /*tp_vectorcall*/ nullptr,
218};
219
221 /* Wrap. */
222 pygpu_offscreen_bind_doc,
223 ".. function:: bind()\n"
224 "\n"
225 " Context manager to ensure balanced bind calls, even in the case of an error.\n");
227{
230 ret->py_offscreen = self;
231 ret->level = -1;
232 ret->is_explicitly_bound = false;
233 Py_INCREF(self);
234
236 ret->is_explicitly_bound = true;
237
238 return (PyObject *)ret;
239}
240
242 /* Wrap. */
243 pygpu_offscreen_unbind_doc,
244 ".. method:: unbind(restore=True)\n"
245 "\n"
246 " Unbind the offscreen object.\n"
247 "\n"
248 " :arg restore: Restore the OpenGL state, can only be used when the state has been "
249 "saved before.\n"
250 " :type restore: bool\n");
251static PyObject *pygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds)
252{
253 bool restore = true;
254
256
257 static const char *_keywords[] = {"restore", nullptr};
258 static _PyArg_Parser _parser = {
260 "|$" /* Optional keyword only arguments. */
261 "O&" /* `restore` */
262 ":unbind",
263 _keywords,
264 nullptr,
265 };
266 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, PyC_ParseBool, &restore)) {
267 return nullptr;
268 }
269
270 GPU_offscreen_unbind(self->ofs, restore);
272 Py_RETURN_NONE;
273}
274
276
277/* -------------------------------------------------------------------- */
280
281static PyObject *pygpu_offscreen__tp_new(PyTypeObject * /*self*/, PyObject *args, PyObject *kwds)
282{
284
285 GPUOffScreen *ofs = nullptr;
286 int width, height;
288 char err_out[256];
289
290 static const char *_keywords[] = {"width", "height", "format", nullptr};
291 static _PyArg_Parser _parser = {
293 "i" /* `width` */
294 "i" /* `height` */
295 "|$" /* Optional keyword only arguments. */
296 "O&" /* `format` */
297 ":GPUOffScreen.__new__",
298 _keywords,
299 nullptr,
300 };
301 if (!_PyArg_ParseTupleAndKeywordsFast(
302 args, kwds, &_parser, &width, &height, PyC_ParseStringEnum, &pygpu_textureformat))
303 {
304 return nullptr;
305 }
306
308 ofs = GPU_offscreen_create(width,
309 height,
310 true,
311 eGPUTextureFormat(pygpu_textureformat.value_found),
313 false,
314 err_out);
315 }
316 else {
317 STRNCPY(err_out, "No active GPU context found");
318 }
319
320 if (ofs == nullptr) {
321 PyErr_Format(PyExc_RuntimeError,
322 "gpu.offscreen.new(...) failed with '%s'",
323 err_out[0] ? err_out : "unknown error");
324 return nullptr;
325 }
326
328}
329
331 /* Wrap. */
332 pygpu_offscreen_width_doc,
333 "Width of the texture.\n"
334 "\n"
335 ":type: int");
336static PyObject *pygpu_offscreen_width_get(BPyGPUOffScreen *self, void * /*type*/)
337{
339 return PyLong_FromLong(GPU_offscreen_width(self->ofs));
340}
341
343 /* Wrap. */
344 pygpu_offscreen_height_doc,
345 "Height of the texture.\n"
346 "\n"
347 ":type: int");
348static PyObject *pygpu_offscreen_height_get(BPyGPUOffScreen *self, void * /*type*/)
349{
351 return PyLong_FromLong(GPU_offscreen_height(self->ofs));
352}
353
355 /* Wrap. */
356 pygpu_offscreen_color_texture_doc,
357 "OpenGL bindcode for the color texture.\n"
358 "\n"
359 ":type: int");
360static PyObject *pygpu_offscreen_color_texture_get(BPyGPUOffScreen *self, void * /*type*/)
361{
363 GPUTexture *texture = GPU_offscreen_color_texture(self->ofs);
364 return PyLong_FromLong(GPU_texture_opengl_bindcode(texture));
365}
366
368 /* Wrap. */
369 pygpu_offscreen_texture_color_doc,
370 "The color texture attached.\n"
371 "\n"
372 ":type: :class:`gpu.types.GPUTexture`");
379
381 /* Wrap. */
382 pygpu_offscreen_draw_view3d_doc,
383 ".. method:: draw_view3d(scene, view_layer, view3d, region, view_matrix, projection_matrix, "
384 "do_color_management=False, draw_background=True)\n"
385 "\n"
386 " Draw the 3d viewport in the offscreen object.\n"
387 "\n"
388 " :arg scene: Scene to draw.\n"
389 " :type scene: :class:`bpy.types.Scene`\n"
390 " :arg view_layer: View layer to draw.\n"
391 " :type view_layer: :class:`bpy.types.ViewLayer`\n"
392 " :arg view3d: 3D View to get the drawing settings from.\n"
393 " :type view3d: :class:`bpy.types.SpaceView3D`\n"
394 " :arg region: Region of the 3D View (required as temporary draw target).\n"
395 " :type region: :class:`bpy.types.Region`\n"
396 " :arg view_matrix: View Matrix (e.g. ``camera.matrix_world.inverted()``).\n"
397 " :type view_matrix: :class:`mathutils.Matrix`\n"
398 " :arg projection_matrix: Projection Matrix (e.g. ``camera.calc_matrix_camera(...)``).\n"
399 " :type projection_matrix: :class:`mathutils.Matrix`\n"
400 " :arg do_color_management: Color manage the output.\n"
401 " :type do_color_management: bool\n"
402 " :arg draw_background: Draw background.\n"
403 " :type draw_background: bool\n");
404static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds)
405{
406 MatrixObject *py_mat_view, *py_mat_projection;
407 PyObject *py_scene, *py_view_layer, *py_region, *py_view3d;
408
409 Depsgraph *depsgraph;
410 Scene *scene;
411 ViewLayer *view_layer;
412 View3D *v3d;
413 ARegion *region;
414
415 bool do_color_management = false;
416 bool draw_background = true;
417
419
420 static const char *_keywords[] = {
421 "scene",
422 "view_layer",
423 "view3d",
424 "region",
425 "view_matrix",
426 "projection_matrix",
427 "do_color_management",
428 "draw_background",
429 nullptr,
430 };
431 static _PyArg_Parser _parser = {
433 "O" /* `scene` */
434 "O" /* `view_layer` */
435 "O" /* `view3d` */
436 "O" /* `region` */
437 "O&" /* `view_matrix` */
438 "O&" /* `projection_matrix` */
439 "|$" /* Optional keyword only arguments. */
440 "O&" /* `do_color_management` */
441 "O&" /* `draw_background` */
442 ":draw_view3d",
443 _keywords,
444 nullptr,
445 };
446 if (!_PyArg_ParseTupleAndKeywordsFast(args,
447 kwds,
448 &_parser,
449 &py_scene,
450 &py_view_layer,
451 &py_view3d,
452 &py_region,
454 &py_mat_view,
456 &py_mat_projection,
458 &do_color_management,
460 &draw_background) ||
461 (!(scene = static_cast<Scene *>(PyC_RNA_AsPointer(py_scene, "Scene"))) ||
462 !(view_layer = static_cast<ViewLayer *>(PyC_RNA_AsPointer(py_view_layer, "ViewLayer"))) ||
463 !(v3d = static_cast<View3D *>(PyC_RNA_AsPointer(py_view3d, "SpaceView3D"))) ||
464 !(region = static_cast<ARegion *>(PyC_RNA_AsPointer(py_region, "Region")))))
465 {
466 return nullptr;
467 }
468
470 /* NOTE(@ideasman42): Nested draw calls could be supported.
471 * Adding support for this looks to be possible but non-trivial. */
472 PyErr_SetString(PyExc_RuntimeError, "Nested off-screen drawing not supported");
473 return nullptr;
474 }
475
477
478 depsgraph = BKE_scene_ensure_depsgraph(G_MAIN, scene, view_layer);
479
480 /* Disable 'bgl' state since it interfere with off-screen drawing, see: #84402. */
481 const bool is_bgl = GPU_bgl_get();
482 if (is_bgl) {
483 GPU_bgl_end();
484 }
485
486 GPU_offscreen_bind(self->ofs, true);
487
488 /* Cache the #GPUViewport so the frame-buffers and associated textures are
489 * not reallocated each time, see: #89204 */
490 if (!self->viewport) {
491 self->viewport = GPU_viewport_create();
492 }
493 else {
494 GPU_viewport_tag_update(self->viewport);
495 }
496
498 scene,
499 eDrawType(v3d->shading.type),
500 v3d,
501 region,
504 (const float(*)[4])py_mat_view->matrix,
505 (const float(*)[4])py_mat_projection->matrix,
506 true,
508 "",
509 do_color_management,
510 true,
511 self->ofs,
512 self->viewport);
513
514 GPU_offscreen_unbind(self->ofs, true);
515
516 if (is_bgl) {
518 }
519
520 Py_RETURN_NONE;
521}
522
523#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
525 /* Wrap. */
526 pygpu_offscreen_free_doc,
527 ".. method:: free()\n"
528 "\n"
529 " Free the offscreen object.\n"
530 " The framebuffer, texture and render objects will no longer be accessible.\n");
532{
534
535 if (self->viewport) {
536 GPU_viewport_free(self->viewport);
537 self->viewport = nullptr;
538 }
539
541 self->ofs = nullptr;
542 Py_RETURN_NONE;
543}
544#endif
545
547{
548 if (self->viewport) {
549 GPU_viewport_free(self->viewport);
550 }
551 if (self->ofs) {
553 }
554 Py_TYPE(self)->tp_free((PyObject *)self);
555}
556
557static PyGetSetDef pygpu_offscreen__tp_getseters[] = {
558 {"color_texture",
560 (setter) nullptr,
561 pygpu_offscreen_color_texture_doc,
562 nullptr},
563 {"texture_color",
565 (setter) nullptr,
566 pygpu_offscreen_texture_color_doc,
567 nullptr},
568 {"width",
570 (setter) nullptr,
571 pygpu_offscreen_width_doc,
572 nullptr},
573 {"height",
575 (setter) nullptr,
576 pygpu_offscreen_height_doc,
577 nullptr},
578 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
579};
580
581#ifdef __GNUC__
582# ifdef __clang__
583# pragma clang diagnostic push
584# pragma clang diagnostic ignored "-Wcast-function-type"
585# else
586# pragma GCC diagnostic push
587# pragma GCC diagnostic ignored "-Wcast-function-type"
588# endif
589#endif
590
591static PyMethodDef pygpu_offscreen__tp_methods[] = {
592 {"bind", (PyCFunction)pygpu_offscreen_bind, METH_NOARGS, pygpu_offscreen_bind_doc},
593 {"unbind",
594 (PyCFunction)pygpu_offscreen_unbind,
595 METH_VARARGS | METH_KEYWORDS,
596 pygpu_offscreen_unbind_doc},
597 {"draw_view3d",
598 (PyCFunction)pygpu_offscreen_draw_view3d,
599 METH_VARARGS | METH_KEYWORDS,
600 pygpu_offscreen_draw_view3d_doc},
601#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
602 {"free", (PyCFunction)pygpu_offscreen_free, METH_NOARGS, pygpu_offscreen_free_doc},
603#endif
604 {nullptr, nullptr, 0, nullptr},
605};
606
607#ifdef __GNUC__
608# ifdef __clang__
609# pragma clang diagnostic pop
610# else
611# pragma GCC diagnostic pop
612# endif
613#endif
614
616 /* Wrap. */
617 pygpu_offscreen__tp_doc,
618 ".. class:: GPUOffScreen(width, height, *, format='RGBA8')\n"
619 "\n"
620 " This object gives access to off screen buffers.\n"
621 "\n"
622 " :arg width: Horizontal dimension of the buffer.\n"
623 " :type width: int\n"
624 " :arg height: Vertical dimension of the buffer.\n"
625 " :type height: int\n"
626 " :arg format: Internal data format inside GPU memory for color attachment "
627 "texture. Possible values are:\n"
628 " `RGBA8`,\n"
629 " `RGBA16`,\n"
630 " `RGBA16F`,\n"
631 " `RGBA32F`,\n"
632 " :type format: str\n");
633PyTypeObject BPyGPUOffScreen_Type = {
634 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
635 /*tp_name*/ "GPUOffScreen",
636 /*tp_basicsize*/ sizeof(BPyGPUOffScreen),
637 /*tp_itemsize*/ 0,
638 /*tp_dealloc*/ (destructor)BPyGPUOffScreen__tp_dealloc,
639 /*tp_vectorcall_offset*/ 0,
640 /*tp_getattr*/ nullptr,
641 /*tp_setattr*/ nullptr,
642 /*tp_compare*/ nullptr,
643 /*tp_repr*/ nullptr,
644 /*tp_as_number*/ nullptr,
645 /*tp_as_sequence*/ nullptr,
646 /*tp_as_mapping*/ nullptr,
647 /*tp_hash*/ nullptr,
648 /*tp_call*/ nullptr,
649 /*tp_str*/ nullptr,
650 /*tp_getattro*/ nullptr,
651 /*tp_setattro*/ nullptr,
652 /*tp_as_buffer*/ nullptr,
653 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
654 /*tp_doc*/ pygpu_offscreen__tp_doc,
655 /*tp_traverse*/ nullptr,
656 /*tp_clear*/ nullptr,
657 /*tp_richcompare*/ nullptr,
658 /*tp_weaklistoffset*/ 0,
659 /*tp_iter*/ nullptr,
660 /*tp_iternext*/ nullptr,
661 /*tp_methods*/ pygpu_offscreen__tp_methods,
662 /*tp_members*/ nullptr,
663 /*tp_getset*/ pygpu_offscreen__tp_getseters,
664 /*tp_base*/ nullptr,
665 /*tp_dict*/ nullptr,
666 /*tp_descr_get*/ nullptr,
667 /*tp_descr_set*/ nullptr,
668 /*tp_dictoffset*/ 0,
669 /*tp_init*/ nullptr,
670 /*tp_alloc*/ nullptr,
671 /*tp_new*/ pygpu_offscreen__tp_new,
672 /*tp_free*/ nullptr,
673 /*tp_is_gc*/ nullptr,
674 /*tp_bases*/ nullptr,
675 /*tp_mro*/ nullptr,
676 /*tp_cache*/ nullptr,
677 /*tp_subclasses*/ nullptr,
678 /*tp_weaklist*/ nullptr,
679 /*tp_del*/ nullptr,
680 /*tp_version_tag*/ 0,
681 /*tp_finalize*/ nullptr,
682 /*tp_vectorcall*/ nullptr,
683};
684
686
687/* -------------------------------------------------------------------- */
690
692{
694
695 self = PyObject_New(BPyGPUOffScreen, &BPyGPUOffScreen_Type);
696 self->ofs = ofs;
697 self->viewport = nullptr;
698
699 return (PyObject *)self;
700}
701
703
704#undef BPY_GPU_OFFSCREEN_CHECK_OBJ
#define G_MAIN
bool BKE_id_is_in_global_main(ID *id)
Definition lib_id.cc:2480
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3427
#define BLI_assert(a)
Definition BLI_assert.h:46
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define UNLIKELY(x)
eDrawType
bool ED_view3d_draw_offscreen_check_nested()
void ED_view3d_draw_offscreen(Depsgraph *depsgraph, const Scene *scene, eDrawType drawtype, View3D *v3d, ARegion *region, int winx, int winy, const float viewmat[4][4], const float winmat[4][4], bool is_image_render, bool draw_background, const char *viewname, bool do_color_management, bool restore_rv3d_mats, GPUOffScreen *ofs, GPUViewport *viewport)
GPUContext * GPU_context_active_get()
int GPU_offscreen_width(const GPUOffScreen *offscreen)
void GPU_offscreen_bind(GPUOffScreen *offscreen, bool save)
uint GPU_framebuffer_stack_level_get()
int GPU_offscreen_height(const GPUOffScreen *offscreen)
GPUOffScreen * GPU_offscreen_create(int width, int height, bool with_depth_buffer, eGPUTextureFormat format, eGPUTextureUsage usage, bool clear, char err_out[256])
GPUTexture * GPU_offscreen_color_texture(const GPUOffScreen *offscreen)
void GPU_offscreen_free(GPUOffScreen *offscreen)
void GPU_offscreen_unbind(GPUOffScreen *offscreen, bool restore)
void GPU_bgl_start()
Definition gpu_state.cc:330
void GPU_bgl_end()
Definition gpu_state.cc:360
bool GPU_bgl_get()
Definition gpu_state.cc:374
void GPU_apply_state()
Definition gpu_state.cc:315
int GPU_texture_opengl_bindcode(const GPUTexture *texture)
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_HOST_READ
eGPUTextureFormat
@ GPU_RGBA32F
@ GPU_RGBA16F
@ GPU_RGBA16
@ GPU_RGBA8
GPUViewport * GPU_viewport_create()
void GPU_viewport_free(GPUViewport *viewport)
void GPU_viewport_tag_update(GPUViewport *viewport)
PyObject * self
BPy_StructRNA * depsgraph
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition gpu_py.hh:20
static PyMethodDef pygpu_offscreen_stack_context__tp_methods[]
static PyObject * pygpu_offscreen_color_texture_get(BPyGPUOffScreen *self, void *)
PyDoc_STRVAR(pygpu_offscreen_bind_doc, ".. function:: bind()\n" "\n" " Context manager to ensure balanced bind calls, even in the case of an error.\n")
PyObject * BPyGPUOffScreen_CreatePyObject(GPUOffScreen *ofs)
#define BPY_GPU_OFFSCREEN_CHECK_OBJ(bpygpu)
static PyMethodDef pygpu_offscreen__tp_methods[]
#define BPYGPU_USE_GPUOBJ_FREE_METHOD
static int pygpu_offscreen_valid_check(BPyGPUOffScreen *py_ofs)
static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self)
static PyObject * pygpu_offscreen_texture_color_get(BPyGPUOffScreen *self, void *)
PyTypeObject BPyGPUOffScreen_Type
static PyObject * pygpu_offscreen_width_get(BPyGPUOffScreen *self, void *)
static PyObject * pygpu_offscreen__tp_new(PyTypeObject *, PyObject *args, PyObject *kwds)
static PyObject * pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds)
static PyObject * pygpu_offscreen_bind(BPyGPUOffScreen *self)
static PyTypeObject PyGPUOffscreenStackContext_Type
static void pygpu_offscreen_stack_context__tp_dealloc(OffScreenStackContext *self)
static PyObject * pygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds)
static PyObject * pygpu_offscreen_free(BPyGPUOffScreen *self)
static PyObject * pygpu_offscreen_height_get(BPyGPUOffScreen *self, void *)
static PyGetSetDef pygpu_offscreen__tp_getseters[]
static const PyC_StringEnumItems pygpu_framebuffer_color_texture_formats[]
static PyObject * pygpu_offscreen_stack_context_enter(OffScreenStackContext *self)
static PyObject * pygpu_offscreen_stack_context_exit(OffScreenStackContext *self, PyObject *)
PyObject * BPyGPUTexture_CreatePyObject(GPUTexture *tex, bool shared_reference)
int Matrix_Parse4x4(PyObject *o, void *p)
void * PyC_RNA_AsPointer(PyObject *value, const char *type_name)
int PyC_ParseStringEnum(PyObject *o, void *p)
int PyC_ParseBool(PyObject *o, void *p)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
return ret
PyObject_HEAD GPUOffScreen * ofs
PyObject_HEAD BPyGPUOffScreen * py_offscreen
View3DShading shading
static void draw_background(const rcti *rect)