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
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define PROGRAM_NO_OPTI 0
|
#define PROGRAM_NO_OPTI 0
|
||||||
|
#define USE_PY_REFERENCES 1
|
||||||
|
|
||||||
#if defined(NDEBUG)
|
#if defined(NDEBUG)
|
||||||
# define TRUST_NO_ONE 0
|
# define TRUST_NO_ONE 0
|
||||||
|
@@ -209,6 +209,11 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb,
|
|||||||
void (*callback)(void *userData, int level),
|
void (*callback)(void *userData, int level),
|
||||||
void *userData);
|
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);
|
void GPU_framebuffer_push(GPUFrameBuffer *fb);
|
||||||
GPUFrameBuffer *GPU_framebuffer_pop(void);
|
GPUFrameBuffer *GPU_framebuffer_pop(void);
|
||||||
uint GPU_framebuffer_stack_level_get(void);
|
uint GPU_framebuffer_stack_level_get(void);
|
||||||
|
@@ -269,6 +269,12 @@ bool GPU_texture_cube(const GPUTexture *tex);
|
|||||||
bool GPU_texture_depth(const GPUTexture *tex);
|
bool GPU_texture_depth(const GPUTexture *tex);
|
||||||
bool GPU_texture_stencil(const GPUTexture *tex);
|
bool GPU_texture_stencil(const GPUTexture *tex);
|
||||||
bool GPU_texture_integer(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);
|
int GPU_texture_opengl_bindcode(const GPUTexture *tex);
|
||||||
|
|
||||||
void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size);
|
void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size);
|
||||||
|
@@ -71,6 +71,12 @@ FrameBuffer::~FrameBuffer()
|
|||||||
reinterpret_cast<Texture *>(attachment.tex)->detach_from(this);
|
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);
|
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
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@@ -100,6 +100,15 @@ class FrameBuffer {
|
|||||||
bool scissor_test_ = false;
|
bool scissor_test_ = false;
|
||||||
bool dirty_state_ = true;
|
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:
|
public:
|
||||||
FrameBuffer(const char *name);
|
FrameBuffer(const char *name);
|
||||||
virtual ~FrameBuffer();
|
virtual ~FrameBuffer();
|
||||||
|
@@ -60,6 +60,12 @@ Texture::~Texture()
|
|||||||
fb_[i]->attachment_remove(fb_attachment_[i]);
|
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)
|
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;
|
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 */
|
/* TODO remove */
|
||||||
int GPU_texture_opengl_bindcode(const GPUTexture *tex)
|
int GPU_texture_opengl_bindcode(const GPUTexture *tex)
|
||||||
{
|
{
|
||||||
|
@@ -80,6 +80,13 @@ class Texture {
|
|||||||
int refcount = 1;
|
int refcount = 1;
|
||||||
/** Width & Height (of source data), optional. */
|
/** Width & Height (of source data), optional. */
|
||||||
int src_w = 0, src_h = 0;
|
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:
|
protected:
|
||||||
/* ---- Texture format (immutable after init). ---- */
|
/* ---- Texture format (immutable after init). ---- */
|
||||||
|
@@ -46,13 +46,7 @@
|
|||||||
static int pygpu_framebuffer_valid_check(BPyGPUFrameBuffer *bpygpu_fb)
|
static int pygpu_framebuffer_valid_check(BPyGPUFrameBuffer *bpygpu_fb)
|
||||||
{
|
{
|
||||||
if (UNLIKELY(bpygpu_fb->fb == NULL)) {
|
if (UNLIKELY(bpygpu_fb->fb == NULL)) {
|
||||||
PyErr_SetString(PyExc_ReferenceError,
|
PyErr_SetString(PyExc_ReferenceError, "GPU framebuffer was freed, no further access is valid");
|
||||||
#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
|
|
||||||
"GPU framebuffer was freed, no further access is valid"
|
|
||||||
#else
|
|
||||||
"GPU framebuffer: internal error"
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -68,10 +62,6 @@ static int pygpu_framebuffer_valid_check(BPyGPUFrameBuffer *bpygpu_fb)
|
|||||||
|
|
||||||
static void pygpu_framebuffer_free_if_possible(GPUFrameBuffer *fb)
|
static void pygpu_framebuffer_free_if_possible(GPUFrameBuffer *fb)
|
||||||
{
|
{
|
||||||
if (!fb) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GPU_is_init()) {
|
if (GPU_is_init()) {
|
||||||
GPU_framebuffer_free(fb);
|
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 */
|
/* Keep less than or equal to #FRAMEBUFFER_STACK_DEPTH */
|
||||||
#define GPU_PY_FRAMEBUFFER_STACK_LEN 16
|
#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");
|
GPUFrameBuffer *fb_python = GPU_framebuffer_create("fb_python");
|
||||||
GPU_framebuffer_config_array(fb_python, config, color_attachements_len + 1);
|
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,
|
PyDoc_STRVAR(pygpu_framebuffer_is_bound_doc,
|
||||||
@@ -459,15 +464,14 @@ PyDoc_STRVAR(pygpu_framebuffer_free_doc,
|
|||||||
static PyObject *pygpu_framebuffer_free(BPyGPUFrameBuffer *self)
|
static PyObject *pygpu_framebuffer_free(BPyGPUFrameBuffer *self)
|
||||||
{
|
{
|
||||||
PYGPU_FRAMEBUFFER_CHECK_OBJ(self);
|
PYGPU_FRAMEBUFFER_CHECK_OBJ(self);
|
||||||
pygpu_framebuffer_free_if_possible(self->fb);
|
pygpu_framebuffer_free_safe(self);
|
||||||
self->fb = NULL;
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void BPyGPUFrameBuffer__tp_dealloc(BPyGPUFrameBuffer *self)
|
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);
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,13 +535,35 @@ PyTypeObject BPyGPUFrameBuffer_Type = {
|
|||||||
/** \name Public API
|
/** \name Public API
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
PyObject *BPyGPUFrameBuffer_CreatePyObject(GPUFrameBuffer *fb)
|
PyObject *BPyGPUFrameBuffer_CreatePyObject(GPUFrameBuffer *fb, bool shared_reference)
|
||||||
{
|
{
|
||||||
BPyGPUFrameBuffer *self;
|
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 = PyObject_New(BPyGPUFrameBuffer, &BPyGPUFrameBuffer_Type);
|
||||||
self->fb = fb;
|
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;
|
return (PyObject *)self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -28,6 +28,11 @@ extern PyTypeObject BPyGPUFrameBuffer_Type;
|
|||||||
|
|
||||||
typedef struct BPyGPUFrameBuffer {
|
typedef struct BPyGPUFrameBuffer {
|
||||||
PyObject_HEAD struct GPUFrameBuffer *fb;
|
PyObject_HEAD struct GPUFrameBuffer *fb;
|
||||||
|
|
||||||
|
#if GPU_USE_PY_REFERENCES
|
||||||
|
bool shared_reference;
|
||||||
|
#endif
|
||||||
} BPyGPUFrameBuffer;
|
} BPyGPUFrameBuffer;
|
||||||
|
|
||||||
PyObject *BPyGPUFrameBuffer_CreatePyObject(struct GPUFrameBuffer *fb) ATTR_NONNULL(1);
|
PyObject *BPyGPUFrameBuffer_CreatePyObject(struct GPUFrameBuffer *fb, bool shared_reference)
|
||||||
|
ATTR_NONNULL(1);
|
||||||
|
@@ -247,7 +247,7 @@ static PyObject *pygpu_texture__tp_new(PyTypeObject *UNUSED(self), PyObject *arg
|
|||||||
return NULL;
|
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`");
|
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)
|
static void BPyGPUTexture__tp_dealloc(BPyGPUTexture *self)
|
||||||
{
|
{
|
||||||
if (self->tex) {
|
if (self->tex) {
|
||||||
|
#if GPU_USE_PY_REFERENCES
|
||||||
|
GPU_texture_py_reference_set(self->tex, NULL);
|
||||||
|
#endif
|
||||||
GPU_texture_free(self->tex);
|
GPU_texture_free(self->tex);
|
||||||
}
|
}
|
||||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||||
@@ -535,10 +538,7 @@ static PyObject *pygpu_texture_from_image(PyObject *UNUSED(self), PyObject *arg)
|
|||||||
BKE_imageuser_default(&iuser);
|
BKE_imageuser_default(&iuser);
|
||||||
GPUTexture *tex = BKE_image_get_gpu_texture(ima, &iuser, NULL);
|
GPUTexture *tex = BKE_image_get_gpu_texture(ima, &iuser, NULL);
|
||||||
|
|
||||||
/* Increase the texture reference count. */
|
return BPyGPUTexture_CreatePyObject(tex, true);
|
||||||
GPU_texture_ref(tex);
|
|
||||||
|
|
||||||
return BPyGPUTexture_CreatePyObject(tex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct PyMethodDef pygpu_texture__m_methods[] = {
|
static struct PyMethodDef pygpu_texture__m_methods[] = {
|
||||||
@@ -595,13 +595,33 @@ PyObject *bpygpu_texture_init(void)
|
|||||||
/** \name Public API
|
/** \name Public API
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
PyObject *BPyGPUTexture_CreatePyObject(GPUTexture *tex)
|
PyObject *BPyGPUTexture_CreatePyObject(GPUTexture *tex, bool shared_reference)
|
||||||
{
|
{
|
||||||
BPyGPUTexture *self;
|
BPyGPUTexture *self;
|
||||||
|
|
||||||
|
if (shared_reference) {
|
||||||
|
#if GPU_USE_PY_REFERENCES
|
||||||
|
void **ref = GPU_texture_py_reference_get(tex);
|
||||||
|
if (ref) {
|
||||||
|
/* Retrieve BPyGPUTexture reference. */
|
||||||
|
self = POINTER_OFFSET(ref, -offsetof(BPyGPUTexture, tex));
|
||||||
|
BLI_assert(self->tex == tex);
|
||||||
|
Py_INCREF(self);
|
||||||
|
return (PyObject *)self;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GPU_texture_ref(tex);
|
||||||
|
}
|
||||||
|
|
||||||
self = PyObject_New(BPyGPUTexture, &BPyGPUTexture_Type);
|
self = PyObject_New(BPyGPUTexture, &BPyGPUTexture_Type);
|
||||||
self->tex = tex;
|
self->tex = tex;
|
||||||
|
|
||||||
|
#if GPU_USE_PY_REFERENCES
|
||||||
|
BLI_assert(GPU_texture_py_reference_get(tex) == NULL);
|
||||||
|
GPU_texture_py_reference_set(tex, &self->tex);
|
||||||
|
#endif
|
||||||
|
|
||||||
return (PyObject *)self;
|
return (PyObject *)self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,4 +33,5 @@ typedef struct BPyGPUTexture {
|
|||||||
int bpygpu_ParseTexture(PyObject *o, void *p);
|
int bpygpu_ParseTexture(PyObject *o, void *p);
|
||||||
PyObject *bpygpu_texture_init(void);
|
PyObject *bpygpu_texture_init(void);
|
||||||
|
|
||||||
PyObject *BPyGPUTexture_CreatePyObject(struct GPUTexture *tex) ATTR_NONNULL(1);
|
PyObject *BPyGPUTexture_CreatePyObject(struct GPUTexture *tex, bool weak_reference)
|
||||||
|
ATTR_NONNULL(1);
|
||||||
|
Submodule source/tools updated: f99d29ae3e...2afbb8ec47
Reference in New Issue
Block a user