diff options
author | Germano Cavalcante <germano.costa@ig.com.br> | 2021-04-30 16:48:55 +0300 |
---|---|---|
committer | Germano Cavalcante <germano.costa@ig.com.br> | 2021-04-30 16:49:54 +0300 |
commit | 2510bd3a5f35d14f5e0e098c79a776916d273223 (patch) | |
tree | cce1a1d6664293fa491ab3f4a6c57ae80fb51c52 | |
parent | 04b6296e8165736d17fb5167e45a93178f9f71c2 (diff) |
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
-rw-r--r-- | source/blender/gpu/intern/gpu_framebuffer.cc | 2 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_framebuffer_private.hh | 5 | ||||
-rw-r--r-- | source/blender/python/gpu/gpu_py_framebuffer.c | 104 | ||||
-rw-r--r-- | source/blender/python/gpu/gpu_py_offscreen.c | 19 | ||||
-rw-r--r-- | source/blender/python/gpu/gpu_py_state.c | 16 |
5 files changed, 145 insertions, 1 deletions
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index f593a5e4182..487835a9d35 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -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 diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh index 6e4be6de42a..d6a30677840 100644 --- a/source/blender/gpu/intern/gpu_framebuffer_private.hh +++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh @@ -110,6 +110,11 @@ class FrameBuffer { #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(); diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c index 0e58327737a..96a7491e861 100644 --- a/source/blender/python/gpu/gpu_py_framebuffer.c +++ b/source/blender/python/gpu/gpu_py_framebuffer.c @@ -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; diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 9e9a0b9066a..8359e5282fe 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -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 */ diff --git a/source/blender/python/gpu/gpu_py_state.c b/source/blender/python/gpu/gpu_py_state.c index 6b0fade8d1c..173c5afba56 100644 --- a/source/blender/python/gpu/gpu_py_state.c +++ b/source/blender/python/gpu/gpu_py_state.c @@ -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}, }; |