Blender V5.0
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_utf8.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 {int(blender::gpu::TextureFormat::UNORM_8_8_8_8), "RGBA8"},
52 {int(blender::gpu::TextureFormat::UNORM_16_16_16_16), "RGBA16"},
53 {int(blender::gpu::TextureFormat::SFLOAT_16_16_16_16), "RGBA16F"},
54 {int(blender::gpu::TextureFormat::SFLOAT_32_32_32_32), "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 int(blender::gpu::TextureFormat::UNORM_8_8_8_8)};
289 char err_out[256];
290
291 static const char *_keywords[] = {"width", "height", "format", nullptr};
292 static _PyArg_Parser _parser = {
294 "i" /* `width` */
295 "i" /* `height` */
296 "|$" /* Optional keyword only arguments. */
297 "O&" /* `format` */
298 ":GPUOffScreen.__new__",
299 _keywords,
300 nullptr,
301 };
302 if (!_PyArg_ParseTupleAndKeywordsFast(
303 args, kwds, &_parser, &width, &height, PyC_ParseStringEnum, &pygpu_textureformat))
304 {
305 return nullptr;
306 }
307
309 ofs = GPU_offscreen_create(width,
310 height,
311 true,
312 blender::gpu::TextureFormat(pygpu_textureformat.value_found),
314 false,
315 err_out);
316 }
317 else {
318 STRNCPY_UTF8(err_out, "No active GPU context found");
319 }
320
321 if (ofs == nullptr) {
322 PyErr_Format(PyExc_RuntimeError,
323 "gpu.offscreen.new(...) failed with '%s'",
324 err_out[0] ? err_out : "unknown error");
325 return nullptr;
326 }
327
329}
330
332 /* Wrap. */
333 pygpu_offscreen_width_doc,
334 "Width of the texture.\n"
335 "\n"
336 ":type: int\n");
337static PyObject *pygpu_offscreen_width_get(BPyGPUOffScreen *self, void * /*type*/)
338{
340 return PyLong_FromLong(GPU_offscreen_width(self->ofs));
341}
342
344 /* Wrap. */
345 pygpu_offscreen_height_doc,
346 "Height of the texture.\n"
347 "\n"
348 ":type: int\n");
349static PyObject *pygpu_offscreen_height_get(BPyGPUOffScreen *self, void * /*type*/)
350{
352 return PyLong_FromLong(GPU_offscreen_height(self->ofs));
353}
354
356 /* Wrap. */
357 pygpu_offscreen_texture_color_doc,
358 "The color texture attached.\n"
359 "\n"
360 ":type: :class:`gpu.types.GPUTexture`\n");
367
369 /* Wrap. */
370 pygpu_offscreen_draw_view3d_doc,
371 ".. method:: draw_view3d(scene, view_layer, view3d, region, view_matrix, projection_matrix, "
372 "*, do_color_management=False, draw_background=True)\n"
373 "\n"
374 " Draw the 3d viewport in the offscreen object.\n"
375 "\n"
376 " :arg scene: Scene to draw.\n"
377 " :type scene: :class:`bpy.types.Scene`\n"
378 " :arg view_layer: View layer to draw.\n"
379 " :type view_layer: :class:`bpy.types.ViewLayer`\n"
380 " :arg view3d: 3D View to get the drawing settings from.\n"
381 " :type view3d: :class:`bpy.types.SpaceView3D`\n"
382 " :arg region: Region of the 3D View (required as temporary draw target).\n"
383 " :type region: :class:`bpy.types.Region`\n"
384 " :arg view_matrix: View Matrix (e.g. ``camera.matrix_world.inverted()``).\n"
385 " :type view_matrix: :class:`mathutils.Matrix`\n"
386 " :arg projection_matrix: Projection Matrix (e.g. ``camera.calc_matrix_camera(...)``).\n"
387 " :type projection_matrix: :class:`mathutils.Matrix`\n"
388 " :arg do_color_management: Color manage the output.\n"
389 " :type do_color_management: bool\n"
390 " :arg draw_background: Draw background.\n"
391 " :type draw_background: bool\n");
392static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds)
393{
394 MatrixObject *py_mat_view, *py_mat_projection;
395 PyObject *py_scene, *py_view_layer, *py_region, *py_view3d;
396
397 Depsgraph *depsgraph;
398 Scene *scene;
399 ViewLayer *view_layer;
400 View3D *v3d;
401 ARegion *region;
402
403 bool do_color_management = false;
404 bool draw_background = true;
405
407
408 static const char *_keywords[] = {
409 "scene",
410 "view_layer",
411 "view3d",
412 "region",
413 "view_matrix",
414 "projection_matrix",
415 "do_color_management",
416 "draw_background",
417 nullptr,
418 };
419 static _PyArg_Parser _parser = {
421 "O" /* `scene` */
422 "O" /* `view_layer` */
423 "O" /* `view3d` */
424 "O" /* `region` */
425 "O&" /* `view_matrix` */
426 "O&" /* `projection_matrix` */
427 "|$" /* Optional keyword only arguments. */
428 "O&" /* `do_color_management` */
429 "O&" /* `draw_background` */
430 ":draw_view3d",
431 _keywords,
432 nullptr,
433 };
434 if (!_PyArg_ParseTupleAndKeywordsFast(args,
435 kwds,
436 &_parser,
437 &py_scene,
438 &py_view_layer,
439 &py_view3d,
440 &py_region,
442 &py_mat_view,
444 &py_mat_projection,
446 &do_color_management,
448 &draw_background) ||
449 (!(scene = static_cast<Scene *>(PyC_RNA_AsPointer(py_scene, "Scene"))) ||
450 !(view_layer = static_cast<ViewLayer *>(PyC_RNA_AsPointer(py_view_layer, "ViewLayer"))) ||
451 !(v3d = static_cast<View3D *>(PyC_RNA_AsPointer(py_view3d, "SpaceView3D"))) ||
452 !(region = static_cast<ARegion *>(PyC_RNA_AsPointer(py_region, "Region")))))
453 {
454 return nullptr;
455 }
456
458 /* NOTE(@ideasman42): Nested draw calls could be supported.
459 * Adding support for this looks to be possible but non-trivial. */
460 PyErr_SetString(PyExc_RuntimeError, "Nested off-screen drawing not supported");
461 return nullptr;
462 }
463
465
466 depsgraph = BKE_scene_ensure_depsgraph(G_MAIN, scene, view_layer);
467
468 GPU_offscreen_bind(self->ofs, true);
469
470 /* Cache the #GPUViewport so the frame-buffers and associated textures are
471 * not reallocated each time, see: #89204 */
472 if (!self->viewport) {
473 self->viewport = GPU_viewport_create();
474 }
475 else {
476 GPU_viewport_tag_update(self->viewport);
477 }
478
480 scene,
481 eDrawType(v3d->shading.type),
482 v3d,
483 region,
486 (const float (*)[4])py_mat_view->matrix,
487 (const float (*)[4])py_mat_projection->matrix,
488 true,
490 "",
491 do_color_management,
492 true,
493 self->ofs,
494 self->viewport);
495
496 GPU_offscreen_unbind(self->ofs, true);
497
498 Py_RETURN_NONE;
499}
500
501#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
503 /* Wrap. */
504 pygpu_offscreen_free_doc,
505 ".. method:: free()\n"
506 "\n"
507 " Free the offscreen object.\n"
508 " The framebuffer, texture and render objects will no longer be accessible.\n");
510{
512
513 if (self->viewport) {
514 GPU_viewport_free(self->viewport);
515 self->viewport = nullptr;
516 }
517
519 self->ofs = nullptr;
520 Py_RETURN_NONE;
521}
522#endif
523
525{
526 if (self->viewport) {
527 GPU_viewport_free(self->viewport);
528 }
529 if (self->ofs) {
531 }
532 Py_TYPE(self)->tp_free((PyObject *)self);
533}
534
535static PyGetSetDef pygpu_offscreen__tp_getseters[] = {
536 {"texture_color",
538 (setter) nullptr,
539 pygpu_offscreen_texture_color_doc,
540 nullptr},
541 {"width",
543 (setter) nullptr,
544 pygpu_offscreen_width_doc,
545 nullptr},
546 {"height",
548 (setter) nullptr,
549 pygpu_offscreen_height_doc,
550 nullptr},
551 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
552};
553
554#ifdef __GNUC__
555# ifdef __clang__
556# pragma clang diagnostic push
557# pragma clang diagnostic ignored "-Wcast-function-type"
558# else
559# pragma GCC diagnostic push
560# pragma GCC diagnostic ignored "-Wcast-function-type"
561# endif
562#endif
563
564static PyMethodDef pygpu_offscreen__tp_methods[] = {
565 {"bind", (PyCFunction)pygpu_offscreen_bind, METH_NOARGS, pygpu_offscreen_bind_doc},
566 {"unbind",
567 (PyCFunction)pygpu_offscreen_unbind,
568 METH_VARARGS | METH_KEYWORDS,
569 pygpu_offscreen_unbind_doc},
570 {"draw_view3d",
571 (PyCFunction)pygpu_offscreen_draw_view3d,
572 METH_VARARGS | METH_KEYWORDS,
573 pygpu_offscreen_draw_view3d_doc},
574#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
575 {"free", (PyCFunction)pygpu_offscreen_free, METH_NOARGS, pygpu_offscreen_free_doc},
576#endif
577 {nullptr, nullptr, 0, nullptr},
578};
579
580#ifdef __GNUC__
581# ifdef __clang__
582# pragma clang diagnostic pop
583# else
584# pragma GCC diagnostic pop
585# endif
586#endif
587
589 /* Wrap. */
590 pygpu_offscreen__tp_doc,
591 ".. class:: GPUOffScreen(width, height, *, format='RGBA8')\n"
592 "\n"
593 " This object gives access to off screen buffers.\n"
594 "\n"
595 " :arg width: Horizontal dimension of the buffer.\n"
596 " :type width: int\n"
597 " :arg height: Vertical dimension of the buffer.\n"
598 " :type height: int\n"
599 " :arg format: Internal data format inside GPU memory for color attachment "
600 "texture. Possible values are:\n"
601 " ``RGBA8``,\n"
602 " ``RGBA16``,\n"
603 " ``RGBA16F``,\n"
604 " ``RGBA32F``.\n"
605 " :type format: str\n");
606PyTypeObject BPyGPUOffScreen_Type = {
607 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
608 /*tp_name*/ "GPUOffScreen",
609 /*tp_basicsize*/ sizeof(BPyGPUOffScreen),
610 /*tp_itemsize*/ 0,
611 /*tp_dealloc*/ (destructor)BPyGPUOffScreen__tp_dealloc,
612 /*tp_vectorcall_offset*/ 0,
613 /*tp_getattr*/ nullptr,
614 /*tp_setattr*/ nullptr,
615 /*tp_compare*/ nullptr,
616 /*tp_repr*/ nullptr,
617 /*tp_as_number*/ nullptr,
618 /*tp_as_sequence*/ nullptr,
619 /*tp_as_mapping*/ nullptr,
620 /*tp_hash*/ nullptr,
621 /*tp_call*/ nullptr,
622 /*tp_str*/ nullptr,
623 /*tp_getattro*/ nullptr,
624 /*tp_setattro*/ nullptr,
625 /*tp_as_buffer*/ nullptr,
626 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
627 /*tp_doc*/ pygpu_offscreen__tp_doc,
628 /*tp_traverse*/ nullptr,
629 /*tp_clear*/ nullptr,
630 /*tp_richcompare*/ nullptr,
631 /*tp_weaklistoffset*/ 0,
632 /*tp_iter*/ nullptr,
633 /*tp_iternext*/ nullptr,
634 /*tp_methods*/ pygpu_offscreen__tp_methods,
635 /*tp_members*/ nullptr,
636 /*tp_getset*/ pygpu_offscreen__tp_getseters,
637 /*tp_base*/ nullptr,
638 /*tp_dict*/ nullptr,
639 /*tp_descr_get*/ nullptr,
640 /*tp_descr_set*/ nullptr,
641 /*tp_dictoffset*/ 0,
642 /*tp_init*/ nullptr,
643 /*tp_alloc*/ nullptr,
644 /*tp_new*/ pygpu_offscreen__tp_new,
645 /*tp_free*/ nullptr,
646 /*tp_is_gc*/ nullptr,
647 /*tp_bases*/ nullptr,
648 /*tp_mro*/ nullptr,
649 /*tp_cache*/ nullptr,
650 /*tp_subclasses*/ nullptr,
651 /*tp_weaklist*/ nullptr,
652 /*tp_del*/ nullptr,
653 /*tp_version_tag*/ 0,
654 /*tp_finalize*/ nullptr,
655 /*tp_vectorcall*/ nullptr,
656};
657
659
660/* -------------------------------------------------------------------- */
663
665{
667
668 self = PyObject_New(BPyGPUOffScreen, &BPyGPUOffScreen_Type);
669 self->ofs = ofs;
670 self->viewport = nullptr;
671
672 return (PyObject *)self;
673}
674
676
677#undef BPY_GPU_OFFSCREEN_CHECK_OBJ
#define G_MAIN
bool BKE_id_is_in_global_main(ID *id)
Definition lib_id.cc:2500
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3416
#define BLI_assert(a)
Definition BLI_assert.h:46
#define STRNCPY_UTF8(dst, src)
#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()
blender::gpu::Texture * GPU_offscreen_color_texture(const GPUOffScreen *offscreen)
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, blender::gpu::TextureFormat format, eGPUTextureUsage usage, bool clear, char err_out[256])
void GPU_offscreen_free(GPUOffScreen *offscreen)
void GPU_offscreen_unbind(GPUOffScreen *offscreen, bool restore)
void GPU_apply_state()
Definition gpu_state.cc:315
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_HOST_READ
GPUViewport * GPU_viewport_create()
void GPU_viewport_free(GPUViewport *viewport)
void GPU_viewport_tag_update(GPUViewport *viewport)
PyObject * self
BPy_StructRNA * depsgraph
nullptr float
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition gpu_py.hh:20
static PyMethodDef pygpu_offscreen_stack_context__tp_methods[]
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(blender::gpu::Texture *tex, bool shared_reference)
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
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.
Py_DECREF(oname)
#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)