Blender  V3.3
gpu_py_framebuffer.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
13 #include <Python.h>
14 
15 #include "GPU_context.h"
16 #include "GPU_framebuffer.h"
17 #include "GPU_init_exit.h"
18 
19 #include "../generic/py_capi_utils.h"
20 #include "../generic/python_utildefines.h"
21 #include "../mathutils/mathutils.h"
22 
23 #include "gpu_py.h"
24 #include "gpu_py_buffer.h"
25 #include "gpu_py_framebuffer.h" /* own include */
26 #include "gpu_py_texture.h"
27 
28 /* -------------------------------------------------------------------- */
33 {
34  if (UNLIKELY(bpygpu_fb->fb == NULL)) {
35  PyErr_SetString(PyExc_ReferenceError, "GPU framebuffer was freed, no further access is valid");
36  return -1;
37  }
38  return 0;
39 }
40 
41 #define PYGPU_FRAMEBUFFER_CHECK_OBJ(bpygpu) \
42  { \
43  if (UNLIKELY(pygpu_framebuffer_valid_check(bpygpu) == -1)) { \
44  return NULL; \
45  } \
46  } \
47  ((void)0)
48 
50 {
51  if (GPU_is_init()) {
53  }
54  else {
55  printf("PyFramebuffer freed after the context has been destroyed.\n");
56  }
57 }
58 
60 {
61  if (self->fb) {
62 #ifndef GPU_NO_USE_PY_REFERENCES
64  if (!self->shared_reference)
65 #endif
66  {
68  }
69 
70  self->fb = NULL;
71  }
72 }
73 
74 /* Keep less than or equal to #FRAMEBUFFER_STACK_DEPTH */
75 #define GPU_PY_FRAMEBUFFER_STACK_LEN 16
76 
78 {
80  PyErr_SetString(
81  PyExc_RuntimeError,
82  "Maximum framebuffer stack depth " STRINGIFY(GPU_PY_FRAMEBUFFER_STACK_LEN) " reached");
83  return false;
84  }
87  return true;
88 }
89 
91 {
93  PyErr_SetString(PyExc_RuntimeError, "Minimum framebuffer stack depth reached");
94  return false;
95  }
96 
97  if (fb && !GPU_framebuffer_bound(fb)) {
98  PyErr_SetString(PyExc_RuntimeError, "Framebuffer is not bound");
99  return false;
100  }
101 
102  GPUFrameBuffer *fb_prev = GPU_framebuffer_pop();
103  GPU_framebuffer_bind(fb_prev);
104  return true;
105 }
106 
109 /* -------------------------------------------------------------------- */
116 typedef struct {
117  PyObject_HEAD /* Required Python macro. */
119  int level;
121 
123 {
124  Py_DECREF(self->py_fb);
125  PyObject_DEL(self);
126 }
127 
129 {
131 
132  /* sanity - should never happen */
133  if (self->level != -1) {
134  PyErr_SetString(PyExc_RuntimeError, "Already in use");
135  return NULL;
136  }
137 
139  return NULL;
140  }
141 
142  self->level = GPU_framebuffer_stack_level_get();
143  Py_RETURN_NONE;
144 }
145 
147  PyObject *UNUSED(args))
148 {
150 
151  /* sanity - should never happen */
152  if (self->level == -1) {
153  fprintf(stderr, "Not yet in use\n");
154  return NULL;
155  }
156 
157  const int level = GPU_framebuffer_stack_level_get();
158  if (level != self->level) {
159  fprintf(stderr, "Level of bind mismatch, expected %d, got %d\n", self->level, level);
160  }
161 
163  return NULL;
164  }
165  Py_RETURN_NONE;
166 }
167 
169  {"__enter__", (PyCFunction)pygpu_framebuffer_stack_context_enter, METH_NOARGS},
170  {"__exit__", (PyCFunction)pygpu_framebuffer_stack_context_exit, METH_VARARGS},
171  {NULL},
172 };
173 
174 static PyTypeObject FramebufferStackContext_Type = {
175  PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUFrameBufferStackContext",
176  .tp_basicsize = sizeof(PyFrameBufferStackContext),
177  .tp_dealloc = (destructor)pygpu_framebuffer_stack_context__tp_dealloc,
178  .tp_flags = Py_TPFLAGS_DEFAULT,
180 };
181 
182 PyDoc_STRVAR(pygpu_framebuffer_bind_doc,
183  ".. function:: bind()\n"
184  "\n"
185  " Context manager to ensure balanced bind calls, even in the case of an error.\n");
187 {
190  ret->py_fb = self;
191  ret->level = -1;
192  Py_INCREF(self);
193  return (PyObject *)ret;
194 }
195 
198 /* -------------------------------------------------------------------- */
202 /* Fill in the GPUAttachment according to the PyObject parameter.
203  * PyObject *o can be NULL, Py_None, BPyGPUTexture or a dictionary containing the keyword "texture"
204  * and the optional keywords "layer" and "mip".
205  * Returns false on error. In this case, a python message will be raised and GPUAttachment will not
206  * be touched. */
207 static bool pygpu_framebuffer_new_parse_arg(PyObject *o, GPUAttachment *r_attach)
208 {
209  GPUAttachment tmp_attach = GPU_ATTACHMENT_NONE;
210 
211  if (!o || o == Py_None) {
212  /* Pass. */;
213  }
214  else if (BPyGPUTexture_Check(o)) {
215  if (!bpygpu_ParseTexture(o, &tmp_attach.tex)) {
216  return false;
217  }
218  }
219  else {
220  const char *c_texture = "texture";
221  const char *c_layer = "layer";
222  const char *c_mip = "mip";
223  PyObject *key, *value;
224  Py_ssize_t pos = 0;
225  while (PyDict_Next(o, &pos, &key, &value)) {
226  if (!PyUnicode_Check(key)) {
227  PyErr_SetString(PyExc_TypeError, "keywords must be strings");
228  return false;
229  }
230 
231  if (c_texture && _PyUnicode_EqualToASCIIString(key, c_texture)) {
232  /* Compare only once. */
233  c_texture = NULL;
234  if (!bpygpu_ParseTexture(value, &tmp_attach.tex)) {
235  return false;
236  }
237  }
238  else if (c_layer && _PyUnicode_EqualToASCIIString(key, c_layer)) {
239  /* Compare only once. */
240  c_layer = NULL;
241  tmp_attach.layer = PyLong_AsLong(value);
242  if (tmp_attach.layer == -1 && PyErr_Occurred()) {
243  return false;
244  }
245  }
246  else if (c_mip && _PyUnicode_EqualToASCIIString(key, c_mip)) {
247  /* Compare only once. */
248  c_mip = NULL;
249  tmp_attach.mip = PyLong_AsLong(value);
250  if (tmp_attach.mip == -1 && PyErr_Occurred()) {
251  return false;
252  }
253  }
254  else {
255  PyErr_Format(
256  PyExc_TypeError, "'%U' is an invalid keyword argument for this attribute", key);
257  return false;
258  }
259  }
260  }
261 
262  *r_attach = tmp_attach;
263  return true;
264 }
265 
266 static PyObject *pygpu_framebuffer__tp_new(PyTypeObject *UNUSED(self),
267  PyObject *args,
268  PyObject *kwds)
269 {
271  if (!GPU_context_active_get()) {
272  PyErr_SetString(PyExc_RuntimeError, "No active GPU context found");
273  return NULL;
274  }
275 
276  PyObject *depth_attachment = NULL;
277  PyObject *color_attachements = NULL;
278  static const char *_keywords[] = {"depth_slot", "color_slots", NULL};
279  static _PyArg_Parser _parser = {
280  "|$" /* Optional keyword only arguments. */
281  "O" /* `depth_slot` */
282  "O" /* `color_slots` */
283  ":GPUFrameBuffer.__new__",
284  _keywords,
285  0,
286  };
287  if (!_PyArg_ParseTupleAndKeywordsFast(
288  args, kwds, &_parser, &depth_attachment, &color_attachements)) {
289  return NULL;
290  }
291 
292  /* Keep in sync with #GPU_FB_MAX_COLOR_ATTACHMENT.
293  * TODO: share the define. */
294 #define BPYGPU_FB_MAX_COLOR_ATTACHMENT 6
295 
297 
298  if (!pygpu_framebuffer_new_parse_arg(depth_attachment, &config[0])) {
299  return NULL;
300  }
301  if (config[0].tex && !GPU_texture_depth(config[0].tex)) {
302  PyErr_SetString(PyExc_ValueError, "Depth texture with incompatible format");
303  return NULL;
304  }
305 
306  int color_attachements_len = 0;
307  if (color_attachements && color_attachements != Py_None) {
308  if (PySequence_Check(color_attachements)) {
309  color_attachements_len = PySequence_Size(color_attachements);
310  if (color_attachements_len > BPYGPU_FB_MAX_COLOR_ATTACHMENT) {
311  PyErr_SetString(
312  PyExc_AttributeError,
313  "too many attachements, max is " STRINGIFY(BPYGPU_FB_MAX_COLOR_ATTACHMENT));
314  return NULL;
315  }
316 
317  for (int i = 0; i < color_attachements_len; i++) {
318  PyObject *o = PySequence_GetItem(color_attachements, i);
319  bool ok = pygpu_framebuffer_new_parse_arg(o, &config[i + 1]);
320  Py_DECREF(o);
321  if (!ok) {
322  return NULL;
323  }
324  }
325  }
326  else {
327  if (!pygpu_framebuffer_new_parse_arg(color_attachements, &config[1])) {
328  return NULL;
329  }
330  color_attachements_len = 1;
331  }
332  }
333 
334  GPUFrameBuffer *fb_python = GPU_framebuffer_create("fb_python");
335  GPU_framebuffer_config_array(fb_python, config, color_attachements_len + 1);
336 
337  return BPyGPUFrameBuffer_CreatePyObject(fb_python, false);
338 }
339 
340 PyDoc_STRVAR(pygpu_framebuffer_is_bound_doc,
341  "Checks if this is the active framebuffer in the context.");
343 {
345  return PyBool_FromLong(GPU_framebuffer_bound(self->fb));
346 }
347 
348 PyDoc_STRVAR(pygpu_framebuffer_clear_doc,
349  ".. method:: clear(color=None, depth=None, stencil=None)\n"
350  "\n"
351  " Fill color, depth and stencil textures with specific value.\n"
352  " Common values: color=(0.0, 0.0, 0.0, 1.0), depth=1.0, stencil=0.\n"
353  "\n"
354  " :arg color: float sequence each representing ``(r, g, b, a)``.\n"
355  " :type color: sequence of 3 or 4 floats\n"
356  " :arg depth: depth value.\n"
357  " :type depth: float\n"
358  " :arg stencil: stencil value.\n"
359  " :type stencil: int\n");
360 static PyObject *pygpu_framebuffer_clear(BPyGPUFrameBuffer *self, PyObject *args, PyObject *kwds)
361 {
363 
364  if (!GPU_framebuffer_bound(self->fb)) {
365  return NULL;
366  }
367 
368  PyObject *py_col = NULL;
369  PyObject *py_depth = NULL;
370  PyObject *py_stencil = NULL;
371 
372  static const char *_keywords[] = {"color", "depth", "stencil", NULL};
373  static _PyArg_Parser _parser = {
374  "|$" /* Optional keyword only arguments. */
375  "O" /* `color` */
376  "O" /* `depth` */
377  "O" /* `stencil` */
378  ":clear",
379  _keywords,
380  0,
381  };
382  if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &py_col, &py_depth, &py_stencil)) {
383  return NULL;
384  }
385 
386  eGPUFrameBufferBits buffers = 0;
387  float col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
388  float depth = 1.0f;
389  uint stencil = 0;
390 
391  if (py_col && py_col != Py_None) {
392  if (mathutils_array_parse(col, 3, 4, py_col, "GPUFrameBuffer.clear(), invalid 'color' arg") ==
393  -1) {
394  return NULL;
395  }
396  buffers |= GPU_COLOR_BIT;
397  }
398 
399  if (py_depth && py_depth != Py_None) {
400  depth = PyFloat_AsDouble(py_depth);
401  if (PyErr_Occurred()) {
402  return NULL;
403  }
404  buffers |= GPU_DEPTH_BIT;
405  }
406 
407  if (py_stencil && py_stencil != Py_None) {
408  if ((stencil = PyC_Long_AsU32(py_stencil)) == (uint)-1) {
409  return NULL;
410  }
411  buffers |= GPU_STENCIL_BIT;
412  }
413 
414  GPU_framebuffer_clear(self->fb, buffers, col, depth, stencil);
415  Py_RETURN_NONE;
416 }
417 
418 PyDoc_STRVAR(pygpu_framebuffer_viewport_set_doc,
419  ".. function:: viewport_set(x, y, xsize, ysize)\n"
420  "\n"
421  " Set the viewport for this framebuffer object.\n"
422  " Note: The viewport state is not saved upon framebuffer rebind.\n"
423  "\n"
424  " :param x, y: lower left corner of the viewport_set rectangle, in pixels.\n"
425  " :param xsize, ysize: width and height of the viewport_set.\n"
426  " :type x, y, xsize, ysize: int\n");
428  PyObject *args,
429  void *UNUSED(type))
430 {
431  int x, y, xsize, ysize;
432  if (!PyArg_ParseTuple(args, "iiii:viewport_set", &x, &y, &xsize, &ysize)) {
433  return NULL;
434  }
435 
436  GPU_framebuffer_viewport_set(self->fb, x, y, xsize, ysize);
437  Py_RETURN_NONE;
438 }
439 
440 PyDoc_STRVAR(pygpu_framebuffer_viewport_get_doc,
441  ".. function:: viewport_get()\n"
442  "\n"
443  " Returns position and dimension to current viewport.\n");
445 {
447  int viewport[4];
448  GPU_framebuffer_viewport_get(self->fb, viewport);
449 
450  PyObject *ret = PyTuple_New(4);
452  PyLong_FromLong(viewport[0]),
453  PyLong_FromLong(viewport[1]),
454  PyLong_FromLong(viewport[2]),
455  PyLong_FromLong(viewport[3]));
456  return ret;
457 }
458 
460  pygpu_framebuffer_read_color_doc,
461  ".. function:: read_color(x, y, xsize, ysize, channels, slot, format, data=data)\n"
462  "\n"
463  " Read a block of pixels from the frame buffer.\n"
464  "\n"
465  " :param x, y: Lower left corner of a rectangular block of pixels.\n"
466  " :param xsize, ysize: Dimensions of the pixel rectangle.\n"
467  " :type x, y, xsize, ysize: int\n"
468  " :param channels: Number of components to read.\n"
469  " :type channels: int\n"
470  " :param slot: The framebuffer slot to read data from.\n"
471  " :type slot: int\n"
472  " :param format: The format that describes the content of a single channel.\n"
473  " Possible values are `FLOAT`, `INT`, `UINT`, `UBYTE`, `UINT_24_8` and `10_11_11_REV`.\n"
474  " :type type: str\n"
475  " :arg data: Optional Buffer object to fill with the pixels values.\n"
476  " :type data: :class:`gpu.types.Buffer`\n"
477  " :return: The Buffer with the read pixels.\n"
478  " :rtype: :class:`gpu.types.Buffer`\n");
480  PyObject *args,
481  PyObject *kwds)
482 {
484  int x, y, w, h, channels;
485  uint slot;
486  struct PyC_StringEnum pygpu_dataformat = {bpygpu_dataformat_items, GPU_RGBA8};
487  BPyGPUBuffer *py_buffer = NULL;
488 
489  static const char *_keywords[] = {
490  "x", "y", "xsize", "ysize", "channels", "slot", "format", "data", NULL};
491  static _PyArg_Parser _parser = {
492  "i" /* `x` */
493  "i" /* `y` */
494  "i" /* `xsize` */
495  "i" /* `ysize` */
496  "i" /* `channels` */
497  "I" /* `slot` */
498  "O&" /* `format` */
499  "|$" /* Optional keyword only arguments. */
500  "O!" /* `data` */
501  ":read_color",
502  _keywords,
503  0,
504  };
505  if (!_PyArg_ParseTupleAndKeywordsFast(args,
506  kwds,
507  &_parser,
508  &x,
509  &y,
510  &w,
511  &h,
512  &channels,
513  &slot,
515  &pygpu_dataformat,
517  &py_buffer)) {
518  return NULL;
519  }
520 
521  if (!IN_RANGE_INCL(channels, 1, 4)) {
522  PyErr_SetString(PyExc_AttributeError, "Color channels must be 1, 2, 3 or 4");
523  return NULL;
524  }
525 
526  if (slot >= BPYGPU_FB_MAX_COLOR_ATTACHMENT) {
527  PyErr_SetString(PyExc_ValueError, "slot overflow");
528  return NULL;
529  }
530 
531  if (py_buffer) {
532  if (pygpu_dataformat.value_found != py_buffer->format) {
533  PyErr_SetString(PyExc_AttributeError,
534  "the format of the buffer is different from that specified");
535  return NULL;
536  }
537 
538  size_t size_curr = bpygpu_Buffer_size(py_buffer);
539  size_t size_expected = w * h * channels *
540  GPU_texture_dataformat_size(pygpu_dataformat.value_found);
541  if (size_curr < size_expected) {
542  PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected");
543  return NULL;
544  }
545  Py_INCREF(py_buffer);
546  }
547  else {
548  py_buffer = BPyGPU_Buffer_CreatePyObject(
549  pygpu_dataformat.value_found, (Py_ssize_t[3]){h, w, channels}, 3, NULL);
550  BLI_assert(bpygpu_Buffer_size(py_buffer) ==
551  w * h * channels * GPU_texture_dataformat_size(pygpu_dataformat.value_found));
552  }
553 
555  x,
556  y,
557  w,
558  h,
559  channels,
560  (int)slot,
561  pygpu_dataformat.value_found,
562  py_buffer->buf.as_void);
563 
564  return (PyObject *)py_buffer;
565 }
566 
567 PyDoc_STRVAR(pygpu_framebuffer_read_depth_doc,
568  ".. function:: read_depth(x, y, xsize, ysize, data=data)\n"
569  "\n"
570  " Read a pixel depth block from the frame buffer.\n"
571  "\n"
572  " :param x, y: Lower left corner of a rectangular block of pixels.\n"
573  " :param xsize, ysize: Dimensions of the pixel rectangle.\n"
574  " :type x, y, xsize, ysize: int\n"
575  " :arg data: Optional Buffer object to fill with the pixels values.\n"
576  " :type data: :class:`gpu.types.Buffer`\n"
577  " :return: The Buffer with the read pixels.\n"
578  " :rtype: :class:`gpu.types.Buffer`\n");
580  PyObject *args,
581  PyObject *kwds)
582 {
584  int x, y, w, h;
585  BPyGPUBuffer *py_buffer = NULL;
586 
587  static const char *_keywords[] = {"x", "y", "xsize", "ysize", "data", NULL};
588  static _PyArg_Parser _parser = {
589  "i" /* `x` */
590  "i" /* `y` */
591  "i" /* `xsize` */
592  "i" /* `ysize` */
593  "|$" /* Optional keyword only arguments. */
594  "O!" /* `data` */
595  ":read_depth",
596  _keywords,
597  0,
598  };
599  if (!_PyArg_ParseTupleAndKeywordsFast(
600  args, kwds, &_parser, &x, &y, &w, &h, &BPyGPU_BufferType, &py_buffer)) {
601  return NULL;
602  }
603 
604  if (py_buffer) {
605  if (py_buffer->format != GPU_DATA_FLOAT) {
606  PyErr_SetString(PyExc_AttributeError, "the format of the buffer must be 'GPU_DATA_FLOAT'");
607  return NULL;
608  }
609 
610  size_t size_curr = bpygpu_Buffer_size(py_buffer);
611  size_t size_expected = w * h * GPU_texture_dataformat_size(GPU_DATA_FLOAT);
612  if (size_curr < size_expected) {
613  PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected");
614  return NULL;
615  }
616  Py_INCREF(py_buffer);
617  }
618  else {
619  py_buffer = BPyGPU_Buffer_CreatePyObject(GPU_DATA_FLOAT, (Py_ssize_t[]){h, w}, 2, NULL);
620  BLI_assert(bpygpu_Buffer_size(py_buffer) ==
622  }
623 
624  GPU_framebuffer_read_depth(self->fb, x, y, w, h, GPU_DATA_FLOAT, py_buffer->buf.as_void);
625 
626  return (PyObject *)py_buffer;
627 }
628 
629 #ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
630 PyDoc_STRVAR(pygpu_framebuffer_free_doc,
631  ".. method:: free()\n"
632  "\n"
633  " Free the framebuffer object.\n"
634  " The framebuffer will no longer be accessible.\n");
635 static PyObject *pygpu_framebuffer_free(BPyGPUFrameBuffer *self)
636 {
639  Py_RETURN_NONE;
640 }
641 #endif
642 
644 {
646  Py_TYPE(self)->tp_free((PyObject *)self);
647 }
648 
649 static PyGetSetDef pygpu_framebuffer__tp_getseters[] = {
650  {"is_bound",
652  (setter)NULL,
653  pygpu_framebuffer_is_bound_doc,
654  NULL},
655  {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
656 };
657 
658 static struct PyMethodDef pygpu_framebuffer__tp_methods[] = {
659  {"bind", (PyCFunction)pygpu_framebuffer_bind, METH_NOARGS, pygpu_framebuffer_bind_doc},
660  {"clear",
661  (PyCFunction)pygpu_framebuffer_clear,
662  METH_VARARGS | METH_KEYWORDS,
663  pygpu_framebuffer_clear_doc},
664  {"viewport_set",
665  (PyCFunction)pygpu_framebuffer_viewport_set,
666  METH_NOARGS,
667  pygpu_framebuffer_viewport_set_doc},
668  {"viewport_get",
669  (PyCFunction)pygpu_framebuffer_viewport_get,
670  METH_NOARGS,
671  pygpu_framebuffer_viewport_get_doc},
672  {"read_color",
673  (PyCFunction)pygpu_framebuffer_read_color,
674  METH_VARARGS | METH_KEYWORDS,
675  pygpu_framebuffer_read_color_doc},
676  {"read_depth",
677  (PyCFunction)pygpu_framebuffer_read_depth,
678  METH_VARARGS | METH_KEYWORDS,
679  pygpu_framebuffer_read_depth_doc},
680 #ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
681  {"free", (PyCFunction)pygpu_framebuffer_free, METH_NOARGS, pygpu_framebuffer_free_doc},
682 #endif
683  {NULL, NULL, 0, NULL},
684 };
685 
686 PyDoc_STRVAR(pygpu_framebuffer__tp_doc,
687  ".. class:: GPUFrameBuffer(depth_slot=None, color_slots=None)\n"
688  "\n"
689  " This object gives access to framebuffer functionallities.\n"
690  " When a 'layer' is specified in a argument, a single layer of a 3D or array "
691  "texture is attached to the frame-buffer.\n"
692  " For cube map textures, layer is translated into a cube map face.\n"
693  "\n"
694  " :arg depth_slot: GPUTexture to attach or a `dict` containing keywords: "
695  "'texture', 'layer' and 'mip'.\n"
696  " :type depth_slot: :class:`gpu.types.GPUTexture`, dict or Nonetype\n"
697  " :arg color_slots: Tuple where each item can be a GPUTexture or a `dict` "
698  "containing keywords: 'texture', 'layer' and 'mip'.\n"
699  " :type color_slots: tuple or Nonetype\n");
700 PyTypeObject BPyGPUFrameBuffer_Type = {
701  PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUFrameBuffer",
702  .tp_basicsize = sizeof(BPyGPUFrameBuffer),
703  .tp_dealloc = (destructor)BPyGPUFrameBuffer__tp_dealloc,
704  .tp_flags = Py_TPFLAGS_DEFAULT,
705  .tp_doc = pygpu_framebuffer__tp_doc,
706  .tp_methods = pygpu_framebuffer__tp_methods,
707  .tp_getset = pygpu_framebuffer__tp_getseters,
708  .tp_new = pygpu_framebuffer__tp_new,
709 };
710 
713 /* -------------------------------------------------------------------- */
717 PyObject *BPyGPUFrameBuffer_CreatePyObject(GPUFrameBuffer *fb, bool shared_reference)
718 {
719  BPyGPUFrameBuffer *self;
720 
721 #ifndef GPU_NO_USE_PY_REFERENCES
722  if (shared_reference) {
723  void **ref = GPU_framebuffer_py_reference_get(fb);
724  if (ref) {
725  /* Retrieve BPyGPUFrameBuffer reference. */
726  self = (BPyGPUFrameBuffer *)POINTER_OFFSET(ref, -offsetof(BPyGPUFrameBuffer, fb));
727  BLI_assert(self->fb == fb);
728  Py_INCREF(self);
729  return (PyObject *)self;
730  }
731  }
732 #else
733  UNUSED_VARS(shared_reference);
734 #endif
735 
736  self = PyObject_New(BPyGPUFrameBuffer, &BPyGPUFrameBuffer_Type);
737  self->fb = fb;
738 
739 #ifndef GPU_NO_USE_PY_REFERENCES
740  self->shared_reference = shared_reference;
741 
743  GPU_framebuffer_py_reference_set(fb, (void **)&self->fb);
744 #endif
745 
746  return (PyObject *)self;
747 }
748 
751 #undef PYGPU_FRAMEBUFFER_CHECK_OBJ
#define BLI_assert(a)
Definition: BLI_assert.h:46
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED_VARS(...)
#define STRINGIFY(x)
#define UNUSED(x)
#define UNLIKELY(x)
#define POINTER_OFFSET(v, ofs)
#define IN_RANGE_INCL(a, b, c)
GPUContext * GPU_context_active_get(void)
Definition: gpu_context.cc:142
struct GPUFrameBuffer GPUFrameBuffer
eGPUFrameBufferBits
@ GPU_DEPTH_BIT
@ GPU_STENCIL_BIT
@ GPU_COLOR_BIT
GPUFrameBuffer * GPU_framebuffer_active_get(void)
void GPU_framebuffer_free(GPUFrameBuffer *fb)
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
GPUFrameBuffer * GPU_framebuffer_create(const char *name)
bool GPU_is_init(void)
Definition: gpu_init_exit.c:63
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
size_t GPU_texture_dataformat_size(eGPUDataFormat data_format)
Definition: gpu_texture.cc:722
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:171
@ GPU_RGBA8
Definition: GPU_texture.h:87
bool GPU_texture_depth(const GPUTexture *tex)
Definition: gpu_texture.cc:644
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
PyObject * self
Definition: bpy_driver.c:165
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
uint pos
uint col
void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb, eGPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, uint clear_stencil)
void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb, const GPUAttachment *config, int config_len)
void GPU_framebuffer_read_color(GPUFrameBuffer *gpu_fb, int x, int y, int w, int h, int channels, int slot, eGPUDataFormat format, void *data)
void GPU_framebuffer_py_reference_set(GPUFrameBuffer *gpu_fb, void **py_ref)
void ** GPU_framebuffer_py_reference_get(GPUFrameBuffer *gpu_fb)
void GPU_framebuffer_viewport_get(GPUFrameBuffer *gpu_fb, int r_viewport[4])
uint GPU_framebuffer_stack_level_get()
void GPU_framebuffer_push(GPUFrameBuffer *fb)
void GPU_framebuffer_viewport_set(GPUFrameBuffer *gpu_fb, int x, int y, int width, int height)
void GPU_framebuffer_read_depth(GPUFrameBuffer *gpu_fb, int x, int y, int w, int h, eGPUDataFormat format, void *data)
GPUFrameBuffer * GPU_framebuffer_pop()
struct PyC_StringEnumItems bpygpu_dataformat_items[]
Definition: gpu_py.c:38
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition: gpu_py.h:14
BPyGPUBuffer * BPyGPU_Buffer_CreatePyObject(const int format, const Py_ssize_t *shape, const int shape_len, void *buffer)
PyTypeObject BPyGPU_BufferType
size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer)
static bool pygpu_framebuffer_stack_pop_and_restore_or_error(GPUFrameBuffer *fb)
static PyObject * pygpu_framebuffer_clear(BPyGPUFrameBuffer *self, PyObject *args, PyObject *kwds)
static PyObject * pygpu_framebuffer_viewport_get(BPyGPUFrameBuffer *self, void *UNUSED(type))
static PyTypeObject FramebufferStackContext_Type
static PyObject * pygpu_framebuffer_is_bound(BPyGPUFrameBuffer *self, void *UNUSED(type))
#define PYGPU_FRAMEBUFFER_CHECK_OBJ(bpygpu)
static void pygpu_framebuffer_stack_context__tp_dealloc(PyFrameBufferStackContext *self)
static void pygpu_framebuffer_free_if_possible(GPUFrameBuffer *fb)
#define BPYGPU_FB_MAX_COLOR_ATTACHMENT
static PyObject * pygpu_framebuffer_viewport_set(BPyGPUFrameBuffer *self, PyObject *args, void *UNUSED(type))
static PyObject * pygpu_framebuffer_bind(BPyGPUFrameBuffer *self)
static bool pygpu_framebuffer_stack_push_and_bind_or_error(GPUFrameBuffer *fb)
static struct PyMethodDef pygpu_framebuffer__tp_methods[]
#define GPU_PY_FRAMEBUFFER_STACK_LEN
PyObject * BPyGPUFrameBuffer_CreatePyObject(GPUFrameBuffer *fb, bool shared_reference)
static PyObject * pygpu_framebuffer_read_depth(BPyGPUFrameBuffer *self, PyObject *args, PyObject *kwds)
static PyObject * pygpu_framebuffer_stack_context_enter(PyFrameBufferStackContext *self)
static void pygpu_framebuffer_free_safe(BPyGPUFrameBuffer *self)
static PyObject * pygpu_framebuffer_read_color(BPyGPUFrameBuffer *self, PyObject *args, PyObject *kwds)
static PyObject * pygpu_framebuffer_stack_context_exit(PyFrameBufferStackContext *self, PyObject *UNUSED(args))
static bool pygpu_framebuffer_new_parse_arg(PyObject *o, GPUAttachment *r_attach)
static PyGetSetDef pygpu_framebuffer__tp_getseters[]
PyDoc_STRVAR(pygpu_framebuffer_bind_doc, ".. function:: bind()\n" "\n" " Context manager to ensure balanced bind calls, even in the case of an error.\n")
static int pygpu_framebuffer_valid_check(BPyGPUFrameBuffer *bpygpu_fb)
static void BPyGPUFrameBuffer__tp_dealloc(BPyGPUFrameBuffer *self)
static PyMethodDef pygpu_framebuffer_stack_context__tp_methods[]
static PyObject * pygpu_framebuffer__tp_new(PyTypeObject *UNUSED(self), PyObject *args, PyObject *kwds)
PyTypeObject BPyGPUFrameBuffer_Type
struct BPyGPUFrameBuffer BPyGPUFrameBuffer
int bpygpu_ParseTexture(PyObject *o, void *p)
#define BPyGPUTexture_Check(v)
BLI_INLINE float fb(float length, float L)
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition: mathutils.c:98
int PyC_ParseStringEnum(PyObject *o, void *p)
uint32_t PyC_Long_AsU32(PyObject *value)
#define PyTuple_SET_ITEMS(op_arg,...)
return ret
void * as_void
Definition: gpu_py_buffer.h:32
union BPyGPUBuffer::@1155 buf
PyObject_HEAD struct GPUFrameBuffer * fb
struct GPUTexture * tex
PyObject_HEAD BPyGPUFrameBuffer * py_fb