[Bf-blender-cvs] [04b6296e816] master: Python GPU: Add reference of PyObject GPU object to the GPU object itself

Germano Cavalcante noreply at git.blender.org
Fri Apr 30 15:42:21 CEST 2021


Commit: 04b6296e8165736d17fb5167e45a93178f9f71c2
Author: Germano Cavalcante
Date:   Thu Apr 29 14:48:59 2021 -0300
Branches: master
https://developer.blender.org/rB04b6296e8165736d17fb5167e45a93178f9f71c2

Python GPU: Add reference of PyObject GPU object to the GPU object itself

Instead of creating different python wrappers for the same GPU object,
return the same `PyObject` created earlier.

This also allows for more secure access to existing GPU objects.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D11044

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

M	source/blender/gpu/GPU_common.h
M	source/blender/gpu/GPU_framebuffer.h
M	source/blender/gpu/GPU_texture.h
M	source/blender/gpu/intern/gpu_framebuffer.cc
M	source/blender/gpu/intern/gpu_framebuffer_private.hh
M	source/blender/gpu/intern/gpu_texture.cc
M	source/blender/gpu/intern/gpu_texture_private.hh
M	source/blender/python/gpu/gpu_py_framebuffer.c
M	source/blender/python/gpu/gpu_py_framebuffer.h
M	source/blender/python/gpu/gpu_py_texture.c
M	source/blender/python/gpu/gpu_py_texture.h
M	source/tools

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

diff --git a/source/blender/gpu/GPU_common.h b/source/blender/gpu/GPU_common.h
index 1be74701176..bc57a381f00 100644
--- a/source/blender/gpu/GPU_common.h
+++ b/source/blender/gpu/GPU_common.h
@@ -24,6 +24,7 @@
 #pragma once
 
 #define PROGRAM_NO_OPTI 0
+#define USE_PY_REFERENCES 1
 
 #if defined(NDEBUG)
 #  define TRUST_NO_ONE 0
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index af94c1fb0e6..ccab80c5702 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -209,6 +209,11 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb,
                                           void (*callback)(void *userData, int level),
                                           void *userData);
 
+#if USE_PY_REFERENCES
+void **GPU_framebuffer_py_reference_get(GPUFrameBuffer *gpu_fb);
+void GPU_framebuffer_py_reference_set(GPUFrameBuffer *gpu_fb, void **py_ref);
+#endif
+
 void GPU_framebuffer_push(GPUFrameBuffer *fb);
 GPUFrameBuffer *GPU_framebuffer_pop(void);
 uint GPU_framebuffer_stack_level_get(void);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index d9a01663de0..21d3070e252 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -269,6 +269,12 @@ bool GPU_texture_cube(const GPUTexture *tex);
 bool GPU_texture_depth(const GPUTexture *tex);
 bool GPU_texture_stencil(const GPUTexture *tex);
 bool GPU_texture_integer(const GPUTexture *tex);
+
+#if USE_PY_REFERENCES
+void **GPU_texture_py_reference_get(GPUTexture *tex);
+void GPU_texture_py_reference_set(GPUTexture *tex, void **py_ref);
+#endif
+
 int GPU_texture_opengl_bindcode(const GPUTexture *tex);
 
 void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size);
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 1e3cf479462..f593a5e4182 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -71,6 +71,12 @@ FrameBuffer::~FrameBuffer()
       reinterpret_cast<Texture *>(attachment.tex)->detach_from(this);
     }
   }
+
+#if USE_PY_REFERENCES
+  if (this->py_ref) {
+    *this->py_ref = nullptr;
+  }
+#endif
 }
 
 /** \} */
@@ -473,6 +479,19 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *gpu_fb,
   unwrap(gpu_fb)->recursive_downsample(max_lvl, callback, userData);
 }
 
+#if USE_PY_REFERENCES
+void **GPU_framebuffer_py_reference_get(GPUFrameBuffer *gpu_fb)
+{
+  return unwrap(gpu_fb)->py_ref;
+}
+
+void GPU_framebuffer_py_reference_set(GPUFrameBuffer *gpu_fb, void **py_ref)
+{
+  BLI_assert(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 d63d72cf4f7..6e4be6de42a 100644
--- a/source/blender/gpu/intern/gpu_framebuffer_private.hh
+++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh
@@ -100,6 +100,15 @@ class FrameBuffer {
   bool scissor_test_ = false;
   bool dirty_state_ = true;
 
+#if USE_PY_REFERENCES
+ public:
+  /**
+   * Reference of a pointer that needs to be cleaned when deallocating the frame-buffer.
+   * Points to #BPyGPUFrameBuffer.fb
+   */
+  void **py_ref = nullptr;
+#endif
+
  public:
   FrameBuffer(const char *name);
   virtual ~FrameBuffer();
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index c3e9058c6c7..b0b0fb970d7 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -60,6 +60,12 @@ Texture::~Texture()
       fb_[i]->attachment_remove(fb_attachment_[i]);
     }
   }
+
+#if USE_PY_REFERENCES
+  if (this->py_ref) {
+    *this->py_ref = nullptr;
+  }
+#endif
 }
 
 bool Texture::init_1D(int w, int layers, eGPUTextureFormat format)
@@ -581,6 +587,19 @@ bool GPU_texture_array(const GPUTexture *tex)
   return (reinterpret_cast<const Texture *>(tex)->type_get() & GPU_TEXTURE_ARRAY) != 0;
 }
 
+#if USE_PY_REFERENCES
+void **GPU_texture_py_reference_get(GPUTexture *tex)
+{
+  return unwrap(tex)->py_ref;
+}
+
+void GPU_texture_py_reference_set(GPUTexture *tex, void **py_ref)
+{
+  BLI_assert(py_ref == nullptr || unwrap(tex)->py_ref == nullptr);
+  unwrap(tex)->py_ref = py_ref;
+}
+#endif
+
 /* TODO remove */
 int GPU_texture_opengl_bindcode(const GPUTexture *tex)
 {
diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh
index 3d808bce152..9f185e03493 100644
--- a/source/blender/gpu/intern/gpu_texture_private.hh
+++ b/source/blender/gpu/intern/gpu_texture_private.hh
@@ -80,6 +80,13 @@ class Texture {
   int refcount = 1;
   /** Width & Height (of source data), optional. */
   int src_w = 0, src_h = 0;
+#if USE_PY_REFERENCES
+  /**
+   * Reference of a pointer that needs to be cleaned when deallocating the texture.
+   * Points to #BPyGPUTexture.tex
+   */
+  void **py_ref = nullptr;
+#endif
 
  protected:
   /* ---- Texture format (immutable after init). ---- */
diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c
index bc393aaafa4..0e58327737a 100644
--- a/source/blender/python/gpu/gpu_py_framebuffer.c
+++ b/source/blender/python/gpu/gpu_py_framebuffer.c
@@ -46,13 +46,7 @@
 static int pygpu_framebuffer_valid_check(BPyGPUFrameBuffer *bpygpu_fb)
 {
   if (UNLIKELY(bpygpu_fb->fb == NULL)) {
-    PyErr_SetString(PyExc_ReferenceError,
-#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
-                    "GPU framebuffer was freed, no further access is valid"
-#else
-                    "GPU framebuffer: internal error"
-#endif
-    );
+    PyErr_SetString(PyExc_ReferenceError, "GPU framebuffer was freed, no further access is valid");
     return -1;
   }
   return 0;
@@ -68,10 +62,6 @@ static int pygpu_framebuffer_valid_check(BPyGPUFrameBuffer *bpygpu_fb)
 
 static void pygpu_framebuffer_free_if_possible(GPUFrameBuffer *fb)
 {
-  if (!fb) {
-    return;
-  }
-
   if (GPU_is_init()) {
     GPU_framebuffer_free(fb);
   }
@@ -80,6 +70,21 @@ static void pygpu_framebuffer_free_if_possible(GPUFrameBuffer *fb)
   }
 }
 
+static void pygpu_framebuffer_free_safe(BPyGPUFrameBuffer *self)
+{
+  if (self->fb) {
+#if GPU_USE_PY_REFERENCES
+    GPU_framebuffer_py_reference_set(self->fb, NULL);
+    if (!self->shared_reference)
+#endif
+    {
+      pygpu_framebuffer_free_if_possible(self->fb);
+    }
+
+    self->fb = NULL;
+  }
+}
+
 /* Keep less than or equal to #FRAMEBUFFER_STACK_DEPTH */
 #define GPU_PY_FRAMEBUFFER_STACK_LEN 16
 
@@ -336,7 +341,7 @@ static PyObject *pygpu_framebuffer__tp_new(PyTypeObject *UNUSED(self),
   GPUFrameBuffer *fb_python = GPU_framebuffer_create("fb_python");
   GPU_framebuffer_config_array(fb_python, config, color_attachements_len + 1);
 
-  return BPyGPUFrameBuffer_CreatePyObject(fb_python);
+  return BPyGPUFrameBuffer_CreatePyObject(fb_python, false);
 }
 
 PyDoc_STRVAR(pygpu_framebuffer_is_bound_doc,
@@ -459,15 +464,14 @@ PyDoc_STRVAR(pygpu_framebuffer_free_doc,
 static PyObject *pygpu_framebuffer_free(BPyGPUFrameBuffer *self)
 {
   PYGPU_FRAMEBUFFER_CHECK_OBJ(self);
-  pygpu_framebuffer_free_if_possible(self->fb);
-  self->fb = NULL;
+  pygpu_framebuffer_free_safe(self);
   Py_RETURN_NONE;
 }
 #endif
 
 static void BPyGPUFrameBuffer__tp_dealloc(BPyGPUFrameBuffer *self)
 {
-  pygpu_framebuffer_free_if_possible(self->fb);
+  pygpu_framebuffer_free_safe(self);
   Py_TYPE(self)->tp_free((PyObject *)self);
 }
 
@@ -531,13 +535,35 @@ PyTypeObject BPyGPUFrameBuffer_Type = {
 /** \name Public API
  * \{ */
 
-PyObject *BPyGPUFrameBuffer_CreatePyObject(GPUFrameBuffer *fb)
+PyObject *BPyGPUFrameBuffer_CreatePyObject(GPUFrameBuffer *fb, bool shared_reference)
 {
   BPyGPUFrameBuffer *self;
 
+#if GPU_USE_PY_REFERENCES
+  if (shared_reference) {
+    void **ref = GPU_framebuffer_py_reference_get(fb);
+    if (ref) {
+      /* Retrieve BPyGPUFrameBuffer reference. */
+      self = POINTER_OFFSET(ref, -offsetof(BPyGPUFrameBuffer, fb));
+      BLI_assert(self->fb == fb);
+      Py_INCREF(self);
+      return (PyObject *)self;
+    }
+  }
+#else
+  UNUSED_VARS(shared_reference);
+#endif
+
   self = PyObject_New(BPyGPUFrameBuffer, &BPyGPUFrameBuffer_Type);
   self->fb = fb;
 
+#if GPU_USE_PY_REFERENCES
+  self->shared_reference = shared_reference;
+
+  BLI_assert(GPU_framebuffer_py_reference_get(fb) == NULL);
+  GPU_framebuffer_py_reference_set(fb, &self->fb);
+#endif
+
   return (PyObject *)self;
 }
 
diff --git a/source/blender/python/gpu/gpu_py_framebuffer.h b/source/blender/python/gpu/gpu_py_framebuffer.h
index 7113e7c35aa..0049cc2fac7 100644
--- a/source/blender/python/gpu/gpu_py_framebuffer.h
+++ b/source/blender/python/gpu/gpu_py_framebuffer.h
@@ -28,6 +28,11 @@ extern PyTypeObject BPyGPUFrameBuffer_Type;
 
 typedef struct BPyGPUFrameBuffer {
   PyObject_HEAD struct GPUFrameBuffer *fb;
+
+#if GPU_USE_PY_REFERENCES
+  bool shared_reference;
+#endif
 } BPyGPUFrameBuffer;
 
-PyObject *BPyGPUFrameBuffer_CreatePyObject(struct GPUFrameBuffer *fb) ATTR_NONNULL(1);
+PyObject *BPyGPUFrameBuffer_CreatePyObject(struct GPUFrameBuffer *fb, bool shared_reference)
+    ATTR_NONNULL(1);
diff --git a/source/blender/python/gpu/gpu_py_texture.c b/source/blender/python/gpu/gpu_py_texture.c
index 1ae65c1dd11..9cc6a9df8fa 100644
--- a/source/blender/python/gpu/gpu_py_texture.c
+++ b/source/blender/python/gpu/gpu_py_texture.c
@@ -247,7 +247,7 @@ static PyObject *pygpu_texture__tp_new(PyTypeObject *UNUSED(self), PyObject *arg
     return NULL;
   }
 
-  return BPyGPUTexture_CreatePyObject(tex);
+  return BPyGPUTexture_CreatePyObject(tex, false);
 }
 
 PyDoc_STRVAR(pygpu_texture_width_doc, "Width of the texture.\n\n:type: `int`");
@@ -412,6 +412,9 @@ static PyObject *pygpu_texture_free(BPyGPUTexture *self)
 static void BPyGPUTexture__tp_dealloc(BPyGPUTexture *self)
 {
   if (self->tex) {
+#if GPU_USE_PY_REFERENCES
+    GPU_texture_py_reference_set(self->tex, NULL);
+#endif
     GPU_texture_free(self->tex);
   }
   Py_TYPE(self)->tp_free((PyObject *)self);
@

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list