39 PyErr_SetString(PyExc_ReferenceError,
"GPU framebuffer was freed, no further access is valid");
45#define PYGPU_FRAMEBUFFER_CHECK_OBJ(bpygpu) \
47 if (UNLIKELY(pygpu_framebuffer_valid_check(bpygpu) == -1)) { \
59 printf(
"PyFramebuffer freed after the context has been destroyed.\n");
66#ifndef GPU_NO_USE_PY_REFERENCES
68 if (!
self->shared_reference)
79#define GPU_PY_FRAMEBUFFER_STACK_LEN 16
97 PyErr_SetString(PyExc_RuntimeError,
"Minimum framebuffer stack depth reached");
102 PyErr_SetString(PyExc_RuntimeError,
"Framebuffer is not bound");
137 if (
self->level != -1) {
138 PyErr_SetString(PyExc_RuntimeError,
"Already in use");
156 if (
self->level == -1) {
157 fprintf(stderr,
"Not yet in use\n");
162 if (level !=
self->level) {
163 fprintf(stderr,
"Level of bind mismatch, expected %d, got %d\n",
self->level, level);
174# pragma clang diagnostic push
175# pragma clang diagnostic ignored "-Wcast-function-type"
177# pragma GCC diagnostic push
178# pragma GCC diagnostic ignored "-Wcast-function-type"
190# pragma clang diagnostic pop
192# pragma GCC diagnostic pop
197 PyVarObject_HEAD_INIT(
nullptr, 0)
198 "GPUFrameBufferStackContext",
250 pygpu_framebuffer_bind_doc,
251 ".. function:: bind()\n"
253 " Context manager to ensure balanced bind calls, even in the case of an error.\n");
261 return (PyObject *)
ret;
278 if (!o || o == Py_None) {
287 const char *c_texture =
"texture";
288 const char *c_layer =
"layer";
289 const char *c_mip =
"mip";
290 PyObject *key, *value;
292 while (PyDict_Next(o, &
pos, &key, &value)) {
293 if (!PyUnicode_Check(key)) {
294 PyErr_SetString(PyExc_TypeError,
"keywords must be strings");
298 if (c_texture && PyUnicode_CompareWithASCIIString(key, c_texture) == 0) {
305 else if (c_layer && PyUnicode_CompareWithASCIIString(key, c_layer) == 0) {
308 tmp_attach.
layer = PyLong_AsLong(value);
309 if (tmp_attach.
layer == -1 && PyErr_Occurred()) {
313 else if (c_mip && PyUnicode_CompareWithASCIIString(key, c_mip) == 0) {
316 tmp_attach.
mip = PyLong_AsLong(value);
317 if (tmp_attach.
mip == -1 && PyErr_Occurred()) {
323 PyExc_TypeError,
"'%U' is an invalid keyword argument for this attribute", key);
329 *r_attach = tmp_attach;
338 PyErr_SetString(PyExc_RuntimeError,
"No active GPU context found");
342 PyObject *depth_attachment =
nullptr;
343 PyObject *color_attachements =
nullptr;
344 static const char *_keywords[] = {
"depth_slot",
"color_slots",
nullptr};
345 static _PyArg_Parser _parser = {
350 ":GPUFrameBuffer.__new__",
354 if (!_PyArg_ParseTupleAndKeywordsFast(
355 args, kwds, &_parser, &depth_attachment, &color_attachements))
362#define BPYGPU_FB_MAX_COLOR_ATTACHMENT 6
370 PyErr_SetString(PyExc_ValueError,
"Depth texture with incompatible format");
374 int color_attachements_len = 0;
375 if (color_attachements && color_attachements != Py_None) {
376 if (PySequence_Check(color_attachements)) {
377 color_attachements_len = PySequence_Size(color_attachements);
379 PyErr_SetString(PyExc_AttributeError,
384 for (
int i = 0;
i < color_attachements_len;
i++) {
385 PyObject *o = PySequence_GetItem(color_attachements,
i);
397 color_attachements_len = 1;
409 pygpu_framebuffer_is_bound_doc,
410 "Checks if this is the active frame-buffer in the context.");
419 pygpu_framebuffer_clear_doc,
420 ".. method:: clear(*, color=None, depth=None, stencil=None)\n"
422 " Fill color, depth and stencil textures with specific value.\n"
423 " Common values: color=(0.0, 0.0, 0.0, 1.0), depth=1.0, stencil=0.\n"
425 " :arg color: Sequence of 3 or 4 floats representing ``(r, g, b, a)``.\n"
426 " :type color: Sequence[float]\n"
427 " :arg depth: depth value.\n"
428 " :type depth: float\n"
429 " :arg stencil: stencil value.\n"
430 " :type stencil: int\n");
439 PyObject *py_col =
nullptr;
440 PyObject *py_depth =
nullptr;
441 PyObject *py_stencil =
nullptr;
443 static const char *_keywords[] = {
"color",
"depth",
"stencil",
nullptr};
444 static _PyArg_Parser _parser = {
454 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &py_col, &py_depth, &py_stencil)) {
459 float col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
463 if (py_col && py_col != Py_None) {
465 col, 3, 4, py_col,
"gpu::FrameBuffer.clear(), invalid 'color' arg") == -1)
472 if (py_depth && py_depth != Py_None) {
473 depth = PyFloat_AsDouble(py_depth);
474 if (PyErr_Occurred()) {
480 if (py_stencil && py_stencil != Py_None) {
493 pygpu_framebuffer_viewport_set_doc,
494 ".. function:: viewport_set(x, y, xsize, ysize)\n"
496 " Set the viewport for this framebuffer object.\n"
497 " Note: The viewport state is not saved upon framebuffer rebind.\n"
499 " :arg x, y: lower left corner of the viewport_set rectangle, in pixels.\n"
501 " :arg xsize, ysize: width and height of the viewport_set.\n"
502 " :type xsize, ysize: int\n");
507 int x,
y, xsize, ysize;
508 if (!PyArg_ParseTuple(args,
"iiii:viewport_set", &
x, &
y, &xsize, &ysize)) {
518 pygpu_framebuffer_viewport_get_doc,
519 ".. function:: viewport_get()\n"
521 " Returns position and dimension to current viewport.\n");
528 PyObject *
ret = PyTuple_New(4);
530 PyLong_FromLong(viewport[0]),
531 PyLong_FromLong(viewport[1]),
532 PyLong_FromLong(viewport[2]),
533 PyLong_FromLong(viewport[3]));
539 pygpu_framebuffer_read_color_doc,
540 ".. function:: read_color(x, y, xsize, ysize, channels, slot, format, *, data=data)\n"
542 " Read a block of pixels from the frame buffer.\n"
544 " :arg x, y: Lower left corner of a rectangular block of pixels.\n"
545 " :arg xsize, ysize: Dimensions of the pixel rectangle.\n"
546 " :type x, y, xsize, ysize: int\n"
547 " :arg channels: Number of components to read.\n"
548 " :type channels: int\n"
549 " :arg slot: The framebuffer slot to read data from.\n"
551 " :arg format: The format that describes the content of a single channel.\n"
552 " Possible values are ``FLOAT``, ``INT``, ``UINT``, ``UBYTE``, ``UINT_24_8`` & "
553 "``10_11_11_REV``.\n"
554 " ``UINT_24_8`` is deprecated, use ``FLOAT`` instead.\n"
555 " :type format: str\n"
556 " :arg data: Optional Buffer object to fill with the pixels values.\n"
557 " :type data: :class:`gpu.types.Buffer`\n"
558 " :return: The Buffer with the read pixels.\n"
559 " :rtype: :class:`gpu.types.Buffer`\n");
565 int x,
y,
w, h, channels;
568 int(blender::gpu::TextureFormat::UNORM_8_8_8_8)};
571 static const char *_keywords[] = {
572 "x",
"y",
"xsize",
"ysize",
"channels",
"slot",
"format",
"data",
nullptr};
573 static _PyArg_Parser _parser = {
588 if (!_PyArg_ParseTupleAndKeywordsFast(args,
606 PyErr_WarnEx(PyExc_DeprecationWarning,
"`UINT_24_8` is deprecated, use `FLOAT` instead", 1);
610 PyErr_SetString(PyExc_AttributeError,
"Color channels must be 1, 2, 3 or 4");
615 PyErr_SetString(PyExc_ValueError,
"slot overflow");
621 PyErr_SetString(PyExc_AttributeError,
622 "the format of the buffer is different from that specified");
627 size_t size_expected =
w * h * channels *
630 if (size_curr < size_expected) {
631 PyErr_SetString(PyExc_BufferError,
"the buffer size is smaller than expected");
634 Py_INCREF(py_buffer);
637 const Py_ssize_t shape[3] = {h,
w, channels};
640 size_t(
w) *
size_t(h) *
size_t(channels) *
654 return (PyObject *)py_buffer;
659 pygpu_framebuffer_read_depth_doc,
660 ".. function:: read_depth(x, y, xsize, ysize, *, data=data)\n"
662 " Read a pixel depth block from the frame buffer.\n"
664 " :arg x, y: Lower left corner of a rectangular block of pixels.\n"
666 " :arg xsize, ysize: Dimensions of the pixel rectangle.\n"
667 " :type xsize, ysize: int\n"
668 " :arg data: Optional Buffer object to fill with the pixels values.\n"
669 " :type data: :class:`gpu.types.Buffer`\n"
670 " :return: The Buffer with the read pixels.\n"
671 " :rtype: :class:`gpu.types.Buffer`\n");
680 static const char *_keywords[] = {
"x",
"y",
"xsize",
"ysize",
"data",
nullptr};
681 static _PyArg_Parser _parser = {
693 if (!_PyArg_ParseTupleAndKeywordsFast(
701 PyErr_SetString(PyExc_AttributeError,
"the format of the buffer must be 'GPU_DATA_FLOAT'");
707 if (size_curr < size_expected) {
708 PyErr_SetString(PyExc_BufferError,
"the buffer size is smaller than expected");
711 Py_INCREF(py_buffer);
714 const Py_ssize_t shape[2] = {h,
w};
722 return (PyObject *)py_buffer;
725#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
728 pygpu_framebuffer_free_doc,
729 ".. method:: free()\n"
731 " Free the framebuffer object.\n"
732 " The framebuffer will no longer be accessible.\n");
744 Py_TYPE(
self)->tp_free((PyObject *)
self);
751 pygpu_framebuffer_is_bound_doc,
753 {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr}
758# pragma clang diagnostic push
759# pragma clang diagnostic ignored "-Wcast-function-type"
761# pragma GCC diagnostic push
762# pragma GCC diagnostic ignored "-Wcast-function-type"
770 METH_VARARGS | METH_KEYWORDS,
771 pygpu_framebuffer_clear_doc},
775 pygpu_framebuffer_viewport_set_doc},
779 pygpu_framebuffer_viewport_get_doc},
782 METH_VARARGS | METH_KEYWORDS,
783 pygpu_framebuffer_read_color_doc},
786 METH_VARARGS | METH_KEYWORDS,
787 pygpu_framebuffer_read_depth_doc},
788#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
789 {
"free", (PyCFunction)pygpu_framebuffer_free, METH_NOARGS, pygpu_framebuffer_free_doc},
791 {
nullptr,
nullptr, 0,
nullptr},
796# pragma clang diagnostic pop
798# pragma GCC diagnostic pop
806 pygpu_framebuffer__tp_doc,
807 ".. class:: GPUFrameBuffer(*, depth_slot=None, color_slots=None)\n"
809 " This object gives access to framebuffer functionalities.\n"
810 " When a 'layer' is specified in a argument, a single layer of a 3D or array "
811 "texture is attached to the frame-buffer.\n"
812 " For cube map textures, layer is translated into a cube map face.\n"
814 " :arg depth_slot: GPUTexture to attach or a ``dict`` containing keywords: "
815 "'texture', 'layer' and 'mip'.\n"
816 " :type depth_slot: :class:`gpu.types.GPUTexture` | dict[] | None\n"
817 " :arg color_slots: Tuple where each item can be a GPUTexture or a ``dict`` "
818 "containing keywords: 'texture', 'layer' and 'mip'.\n"
819 " :type color_slots: :class:`gpu.types.GPUTexture` | "
820 "dict[str, int | :class:`gpu.types.GPUTexture`] | "
821 "Sequence[:class:`gpu.types.GPUTexture` | dict[str, int | "
822 ":class:`gpu.types.GPUTexture`]] | "
825 PyVarObject_HEAD_INIT(
nullptr, 0)
845 pygpu_framebuffer__tp_doc,
886#ifndef GPU_NO_USE_PY_REFERENCES
887 if (shared_reference) {
894 return (PyObject *)
self;
904#ifndef GPU_NO_USE_PY_REFERENCES
905 self->shared_reference = shared_reference;
911 return (PyObject *)
self;
916#undef PYGPU_FRAMEBUFFER_CHECK_OBJ
#define POINTER_OFFSET(v, ofs)
#define IN_RANGE_INCL(a, b, c)
GPUContext * GPU_context_active_get()
blender::gpu::FrameBuffer * GPU_framebuffer_create(const char *name)
void GPU_framebuffer_read_color(blender::gpu::FrameBuffer *fb, int x, int y, int width, int height, int channels, int slot, eGPUDataFormat data_format, void *r_data)
void ** GPU_framebuffer_py_reference_get(blender::gpu::FrameBuffer *fb)
void GPU_framebuffer_py_reference_set(blender::gpu::FrameBuffer *fb, void **py_ref)
#define GPU_ATTACHMENT_NONE
void GPU_framebuffer_free(blender::gpu::FrameBuffer *fb)
uint GPU_framebuffer_stack_level_get()
void GPU_framebuffer_viewport_set(blender::gpu::FrameBuffer *fb, int x, int y, int width, int height)
blender::gpu::FrameBuffer * GPU_framebuffer_pop()
bool GPU_framebuffer_bound(blender::gpu::FrameBuffer *fb)
void GPU_framebuffer_read_depth(blender::gpu::FrameBuffer *fb, int x, int y, int width, int height, eGPUDataFormat data_format, void *r_data)
void GPU_framebuffer_push(blender::gpu::FrameBuffer *fb)
void GPU_framebuffer_config_array(blender::gpu::FrameBuffer *fb, const GPUAttachment *config, int config_len)
void GPU_framebuffer_clear(blender::gpu::FrameBuffer *fb, GPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, unsigned int clear_stencil)
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
void GPU_framebuffer_viewport_get(blender::gpu::FrameBuffer *fb, int r_viewport[4])
blender::gpu::FrameBuffer * GPU_framebuffer_active_get()
size_t GPU_texture_dataformat_size(eGPUDataFormat data_format)
bool GPU_texture_has_depth_format(const blender::gpu::Texture *texture)
@ GPU_DATA_UINT_24_8_DEPRECATED
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
PyC_StringEnumItems bpygpu_dataformat_items[]
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
PyTypeObject BPyGPU_BufferType
BPyGPUBuffer * BPyGPU_Buffer_CreatePyObject(const int format, const Py_ssize_t *shape, const int shape_len, void *buffer)
size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer)
static PyObject * pygpu_framebuffer_viewport_get(BPyGPUFrameBuffer *self, void *)
static bool pygpu_framebuffer_stack_push_and_bind_or_error(blender::gpu::FrameBuffer *fb)
static PyTypeObject FramebufferStackContext_Type
#define PYGPU_FRAMEBUFFER_CHECK_OBJ(bpygpu)
PyObject * BPyGPUFrameBuffer_CreatePyObject(blender::gpu::FrameBuffer *fb, bool shared_reference)
static void pygpu_framebuffer_stack_context__tp_dealloc(PyFrameBufferStackContext *self)
#define BPYGPU_FB_MAX_COLOR_ATTACHMENT
static PyObject * pygpu_framebuffer_is_bound(BPyGPUFrameBuffer *self, void *)
static void pygpu_framebuffer_free_if_possible(blender::gpu::FrameBuffer *fb)
static PyObject * pygpu_framebuffer_stack_context_enter(PyFrameBufferStackContext *self)
static PyObject * pygpu_framebuffer_clear(BPyGPUFrameBuffer *self, PyObject *args, PyObject *kwds)
static PyMethodDef pygpu_framebuffer__tp_methods[]
#define GPU_PY_FRAMEBUFFER_STACK_LEN
static PyObject * pygpu_framebuffer_stack_context_exit(PyFrameBufferStackContext *self, PyObject *)
static bool pygpu_framebuffer_stack_pop_and_restore_or_error(blender::gpu::FrameBuffer *fb)
static void pygpu_framebuffer_free_safe(BPyGPUFrameBuffer *self)
static PyObject * pygpu_framebuffer_bind(BPyGPUFrameBuffer *self)
static PyObject * pygpu_framebuffer__tp_new(PyTypeObject *, PyObject *args, PyObject *kwds)
static PyObject * pygpu_framebuffer_viewport_set(BPyGPUFrameBuffer *self, PyObject *args, void *)
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_read_color(BPyGPUFrameBuffer *self, PyObject *args, PyObject *kwds)
PyTypeObject BPyGPUFrameBuffer_Type
static PyObject * pygpu_framebuffer_read_depth(BPyGPUFrameBuffer *self, PyObject *args, PyObject *kwds)
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)
int PyC_ParseStringEnum(PyObject *o, void *p)
uint32_t PyC_Long_AsU32(PyObject *value)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
#define PyTuple_SET_ITEMS(op_arg,...)
union BPyGPUBuffer::@121060215011127262115351146023070133300154361035 buf
PyObject_HEAD blender::gpu::FrameBuffer * fb
blender::gpu::Texture * tex
PyObject_HEAD BPyGPUFrameBuffer * py_fb