Python GPU: Add new methods to port the code templates in the manual
This commit adds a new API tha allow to replace the bgl API in the exemples on: https://docs.blender.org/api/current/gpu.html **Overview (New API):** ``` gpu.state: active_framebuffer_get GPUFramebuffer: read_color GPUOffscreen: texture_color ``` Reviewed By: brecht Differential Revision: https://developer.blender.org/D11031
This commit is contained in:
parent
04b6296e81
commit
2510bd3a5f
Notes:
blender-bot
2023-02-14 04:20:36 +01:00
Referenced by commit 048f1a1b8b
, GPU: remove unused member from FrameBuffer
|
@ -487,7 +487,7 @@ void **GPU_framebuffer_py_reference_get(GPUFrameBuffer *gpu_fb)
|
|||
|
||||
void GPU_framebuffer_py_reference_set(GPUFrameBuffer *gpu_fb, void **py_ref)
|
||||
{
|
||||
BLI_assert(ref == nullptr || unwrap(gpu_fb)->py_ref == nullptr);
|
||||
BLI_assert(py_ref == nullptr || unwrap(gpu_fb)->py_ref == nullptr);
|
||||
unwrap(gpu_fb)->py_ref = py_ref;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -109,6 +109,11 @@ class FrameBuffer {
|
|||
void **py_ref = nullptr;
|
||||
#endif
|
||||
|
||||
public:
|
||||
/* Reference of a pointer that needs to be cleaned when deallocating the frame-buffer.
|
||||
* Points to BPyGPUFrameBuffer::fb */
|
||||
void **ref = nullptr;
|
||||
|
||||
public:
|
||||
FrameBuffer(const char *name);
|
||||
virtual ~FrameBuffer();
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include "gpu_py.h"
|
||||
#include "gpu_py_texture.h"
|
||||
|
||||
#include "gpu_py.h"
|
||||
#include "gpu_py_buffer.h"
|
||||
#include "gpu_py_framebuffer.h" /* own include */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -455,6 +457,100 @@ static PyObject *pygpu_framebuffer_viewport_get(BPyGPUFrameBuffer *self, void *U
|
|||
return ret;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
pygpu_framebuffer_read_color_doc,
|
||||
".. function:: read_color(x, y, xsize, ysize, channels, slot, format, data=data)\n"
|
||||
"\n"
|
||||
" Read a block of pixels from the frame buffer.\n"
|
||||
"\n"
|
||||
" :param x, y: Lower left corner of a rectangular block of pixels.\n"
|
||||
" :param xsize, ysize: Dimensions of the pixel rectangle.\n"
|
||||
" :type x, y, xsize, ysize: int\n"
|
||||
" :param channels: Number of components to read.\n"
|
||||
" :type channels: int\n"
|
||||
" :param slot: The framebuffer slot to read data from.\n"
|
||||
" :type slot: int\n"
|
||||
" :param format: The format that describes the content of a single channel.\n"
|
||||
" Possible values are `FLOAT`, `INT`, `UINT`, `UBYTE`, `UINT_24_8` and `10_11_11_REV`.\n"
|
||||
" :type type: str\n"
|
||||
" :arg data: Optional Buffer object to fill with the pixels values.\n"
|
||||
" :type data: :class:`gpu.types.Buffer`\n"
|
||||
" :return: The Buffer with the read pixels.\n"
|
||||
" :rtype: :class:`gpu.types.Buffer`\n");
|
||||
static PyObject *pygpu_framebuffer_read_color(BPyGPUFrameBuffer *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
PYGPU_FRAMEBUFFER_CHECK_OBJ(self);
|
||||
int x, y, w, h, channels;
|
||||
uint slot;
|
||||
struct PyC_StringEnum pygpu_dataformat = {bpygpu_dataformat_items, GPU_RGBA8};
|
||||
BPyGPUBuffer *py_buffer = NULL;
|
||||
|
||||
static const char *_keywords[] = {
|
||||
"x", "y", "xsize", "ysize", "channels", "slot", "format", "data", NULL};
|
||||
static _PyArg_Parser _parser = {"iiiiiIO&|$O!:GPUTexture.__new__", _keywords, 0};
|
||||
if (!_PyArg_ParseTupleAndKeywordsFast(args,
|
||||
kwds,
|
||||
&_parser,
|
||||
&x,
|
||||
&y,
|
||||
&w,
|
||||
&h,
|
||||
&channels,
|
||||
&slot,
|
||||
PyC_ParseStringEnum,
|
||||
&pygpu_dataformat,
|
||||
&BPyGPU_BufferType,
|
||||
&py_buffer)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!IN_RANGE_INCL(channels, 1, 4)) {
|
||||
PyErr_SetString(PyExc_AttributeError, "Color channels must be 1, 2, 3 or 4");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (slot >= BPYGPU_FB_MAX_COLOR_ATTACHMENT) {
|
||||
PyErr_SetString(PyExc_ValueError, "slot overflow");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (py_buffer) {
|
||||
if (pygpu_dataformat.value_found != py_buffer->format) {
|
||||
PyErr_SetString(PyExc_AttributeError,
|
||||
"the format of the buffer is different from that specified");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t size_curr = bpygpu_Buffer_size(py_buffer);
|
||||
size_t size_expected = w * h * channels *
|
||||
GPU_texture_dataformat_size(pygpu_dataformat.value_found);
|
||||
if (size_curr < size_expected) {
|
||||
PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
py_buffer = BPyGPU_Buffer_CreatePyObject(
|
||||
pygpu_dataformat.value_found, (Py_ssize_t[3]){h, w, channels}, 3, NULL);
|
||||
BLI_assert(bpygpu_Buffer_size(py_buffer) ==
|
||||
w * h * channels * GPU_texture_dataformat_size(pygpu_dataformat.value_found));
|
||||
}
|
||||
|
||||
GPU_framebuffer_read_color(self->fb,
|
||||
x,
|
||||
y,
|
||||
w,
|
||||
h,
|
||||
channels,
|
||||
(int)slot,
|
||||
pygpu_dataformat.value_found,
|
||||
py_buffer->buf.as_void);
|
||||
|
||||
return (PyObject *)py_buffer;
|
||||
}
|
||||
|
||||
#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
|
||||
PyDoc_STRVAR(pygpu_framebuffer_free_doc,
|
||||
".. method:: free()\n"
|
||||
|
@ -498,6 +594,10 @@ static struct PyMethodDef pygpu_framebuffer__tp_methods[] = {
|
|||
(PyCFunction)pygpu_framebuffer_viewport_get,
|
||||
METH_NOARGS,
|
||||
pygpu_framebuffer_viewport_get_doc},
|
||||
{"read_color",
|
||||
(PyCFunction)pygpu_framebuffer_read_color,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
pygpu_framebuffer_read_color_doc},
|
||||
#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
|
||||
{"free", (PyCFunction)pygpu_framebuffer_free, METH_NOARGS, pygpu_framebuffer_free_doc},
|
||||
#endif
|
||||
|
@ -556,6 +656,10 @@ PyObject *BPyGPUFrameBuffer_CreatePyObject(GPUFrameBuffer *fb, bool shared_refer
|
|||
|
||||
self = PyObject_New(BPyGPUFrameBuffer, &BPyGPUFrameBuffer_Type);
|
||||
self->fb = fb;
|
||||
self->weak_reference = weak_reference;
|
||||
|
||||
BLI_assert(GPU_framebuffer_reference_get(fb) == NULL);
|
||||
GPU_framebuffer_reference_set(fb, &self->fb);
|
||||
|
||||
#if GPU_USE_PY_REFERENCES
|
||||
self->shared_reference = shared_reference;
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
#include "../generic/py_capi_utils.h"
|
||||
|
||||
#include "gpu_py.h"
|
||||
#include "gpu_py_texture.h"
|
||||
|
||||
#include "gpu_py_offscreen.h" /* own include */
|
||||
|
||||
/* Define the free method to avoid breakage. */
|
||||
|
@ -264,6 +266,18 @@ static PyObject *pygpu_offscreen_color_texture_get(BPyGPUOffScreen *self, void *
|
|||
return PyLong_FromLong(GPU_texture_opengl_bindcode(texture));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(pygpu_offscreen_texture_color_doc,
|
||||
"The color texture attached.\n"
|
||||
"\n"
|
||||
":type: :class:`gpu.types.GPUTexture`");
|
||||
static PyObject *pygpu_offscreen_texture_color_get(BPyGPUOffScreen *self, void *UNUSED(type))
|
||||
{
|
||||
BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
|
||||
GPUTexture *texture = GPU_offscreen_color_texture(self->ofs);
|
||||
GPU_texture_ref(texture);
|
||||
return BPyGPUTexture_CreatePyObject(texture);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
pygpu_offscreen_draw_view3d_doc,
|
||||
".. method:: draw_view3d(scene, view_layer, view3d, region, view_matrix, projection_matrix)\n"
|
||||
|
@ -385,6 +399,11 @@ static PyGetSetDef pygpu_offscreen__tp_getseters[] = {
|
|||
(setter)NULL,
|
||||
pygpu_offscreen_color_texture_doc,
|
||||
NULL},
|
||||
{"texture_color",
|
||||
(getter)pygpu_offscreen_texture_color_get,
|
||||
(setter)NULL,
|
||||
pygpu_offscreen_texture_color_doc,
|
||||
NULL},
|
||||
{"width", (getter)pygpu_offscreen_width_get, (setter)NULL, pygpu_offscreen_width_doc, NULL},
|
||||
{"height", (getter)pygpu_offscreen_height_get, (setter)NULL, pygpu_offscreen_height_doc, NULL},
|
||||
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
|
||||
|
|
|
@ -25,11 +25,13 @@
|
|||
|
||||
#include <Python.h>
|
||||
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_state.h"
|
||||
|
||||
#include "../generic/py_capi_utils.h"
|
||||
#include "../generic/python_utildefines.h"
|
||||
|
||||
#include "gpu_py_framebuffer.h"
|
||||
#include "gpu_py_state.h" /* own include */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -334,6 +336,16 @@ static PyObject *pygpu_state_program_point_size_set(PyObject *UNUSED(self), PyOb
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(pygpu_state_framebuffer_active_get_doc,
|
||||
".. function:: framebuffer_active_get(enable)\n"
|
||||
"\n"
|
||||
" Return the active framefuffer in context.\n");
|
||||
static PyObject *pygpu_state_framebuffer_active_get(PyObject *UNUSED(self))
|
||||
{
|
||||
GPUFrameBuffer *fb = GPU_framebuffer_active_get();
|
||||
return BPyGPUFrameBuffer_CreatePyObject(fb, true);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -396,6 +408,10 @@ static struct PyMethodDef pygpu_state__tp_methods[] = {
|
|||
(PyCFunction)pygpu_state_program_point_size_set,
|
||||
METH_O,
|
||||
pygpu_state_program_point_size_set_doc},
|
||||
{"active_framebuffer_get",
|
||||
(PyCFunction)pygpu_state_framebuffer_active_get,
|
||||
METH_NOARGS,
|
||||
pygpu_state_framebuffer_active_get_doc},
|
||||
{NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue