[Bf-blender-cvs] [2510bd3a5f3] master: Python GPU: Add new methods to port the code templates in the manual

Germano Cavalcante noreply at git.blender.org
Fri Apr 30 15:52:23 CEST 2021


Commit: 2510bd3a5f35d14f5e0e098c79a776916d273223
Author: Germano Cavalcante
Date:   Fri Apr 30 10:48:55 2021 -0300
Branches: master
https://developer.blender.org/rB2510bd3a5f35d14f5e0e098c79a776916d273223

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

===================================================================

M	source/blender/gpu/intern/gpu_framebuffer.cc
M	source/blender/gpu/intern/gpu_framebuffer_private.hh
M	source/blender/python/gpu/gpu_py_framebuffer.c
M	source/blender/python/gpu/gpu_py_offscreen.c
M	source/blender/python/gpu/gpu_py_state.c

===================================================================

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
@@ -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();
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},
 };



More information about the Bf-blender-cvs mailing list