Blender  V3.3
gpu_py_uniformbuffer.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
12 #include <Python.h>
13 
14 #include "BLI_string.h"
15 
16 #include "GPU_context.h"
17 #include "GPU_uniform_buffer.h"
18 
19 #include "../generic/py_capi_utils.h"
20 
21 #include "gpu_py.h"
22 
23 #include "gpu_py_uniformbuffer.h" /* own include */
24 
25 /* -------------------------------------------------------------------- */
30 {
31  if (UNLIKELY(bpygpu_ub->ubo == NULL)) {
32  PyErr_SetString(PyExc_ReferenceError,
34  "GPU uniform buffer was freed, no further access is valid");
35 #else
36 
37  "GPU uniform buffer: internal error");
38 #endif
39  return -1;
40  }
41  return 0;
42 }
43 
44 #define BPYGPU_UNIFORMBUF_CHECK_OBJ(bpygpu) \
45  { \
46  if (UNLIKELY(pygpu_uniformbuffer_valid_check(bpygpu) == -1)) { \
47  return NULL; \
48  } \
49  } \
50  ((void)0)
51 
54 /* -------------------------------------------------------------------- */
58 static PyObject *pygpu_uniformbuffer__tp_new(PyTypeObject *UNUSED(self),
59  PyObject *args,
60  PyObject *kwds)
61 {
63 
64  GPUUniformBuf *ubo = NULL;
65  PyObject *pybuffer_obj;
66  char err_out[256] = "unknown error. See console";
67 
68  static const char *_keywords[] = {"data", NULL};
69  static _PyArg_Parser _parser = {
70  "O" /* `data` */
71  ":GPUUniformBuf.__new__",
72  _keywords,
73  0,
74  };
75  if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &pybuffer_obj)) {
76  return NULL;
77  }
78 
79  if (!GPU_context_active_get()) {
80  STRNCPY(err_out, "No active GPU context found");
81  }
82  else {
83  Py_buffer pybuffer;
84  if (PyObject_GetBuffer(pybuffer_obj, &pybuffer, PyBUF_SIMPLE) == -1) {
85  /* PyObject_GetBuffer raise a PyExc_BufferError */
86  return NULL;
87  }
88 
89  if ((pybuffer.len % 16) != 0) {
90  STRNCPY(err_out, "UBO is not padded to size of vec4");
91  }
92  else {
93  ubo = GPU_uniformbuf_create_ex(pybuffer.len, pybuffer.buf, "python_uniformbuffer");
94  }
95  PyBuffer_Release(&pybuffer);
96  }
97 
98  if (ubo == NULL) {
99  PyErr_Format(PyExc_RuntimeError, "GPUUniformBuf.__new__(...) failed with '%s'", err_out);
100  return NULL;
101  }
102 
104 }
105 
106 PyDoc_STRVAR(pygpu_uniformbuffer_update_doc,
107  ".. method:: update(data)\n"
108  "\n"
109  " Update the data of the uniform buffer object.\n");
110 static PyObject *pygpu_uniformbuffer_update(BPyGPUUniformBuf *self, PyObject *obj)
111 {
113 
114  Py_buffer pybuffer;
115  if (PyObject_GetBuffer(obj, &pybuffer, PyBUF_SIMPLE) == -1) {
116  /* PyObject_GetBuffer raise a PyExc_BufferError */
117  return NULL;
118  }
119 
120  GPU_uniformbuf_update(self->ubo, pybuffer.buf);
121  PyBuffer_Release(&pybuffer);
122  Py_RETURN_NONE;
123 }
124 
125 #ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
126 PyDoc_STRVAR(pygpu_uniformbuffer_free_doc,
127  ".. method::free()\n"
128  "\n"
129  " Free the uniform buffer object.\n"
130  " The uniform buffer object will no longer be accessible.\n");
131 static PyObject *pygpu_uniformbuffer_free(BPyGPUUniformBuf *self)
132 {
134 
136  self->ubo = NULL;
137  Py_RETURN_NONE;
138 }
139 #endif
140 
142 {
143  if (self->ubo) {
145  }
146  Py_TYPE(self)->tp_free((PyObject *)self);
147 }
148 
149 static PyGetSetDef pygpu_uniformbuffer__tp_getseters[] = {
150  {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
151 };
152 
153 static struct PyMethodDef pygpu_uniformbuffer__tp_methods[] = {
154  {"update", (PyCFunction)pygpu_uniformbuffer_update, METH_O, pygpu_uniformbuffer_update_doc},
155 #ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
156  {"free", (PyCFunction)pygpu_uniformbuffer_free, METH_NOARGS, pygpu_uniformbuffer_free_doc},
157 #endif
158  {NULL, NULL, 0, NULL},
159 };
160 
161 PyDoc_STRVAR(pygpu_uniformbuffer__tp_doc,
162  ".. class:: GPUUniformBuf(data)\n"
163  "\n"
164  " This object gives access to off uniform buffers.\n"
165  "\n"
166  " :arg data: Data to fill the buffer.\n"
167  " :type data: object exposing buffer interface\n");
168 PyTypeObject BPyGPUUniformBuf_Type = {
169  PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUUniformBuf",
170  .tp_basicsize = sizeof(BPyGPUUniformBuf),
171  .tp_dealloc = (destructor)BPyGPUUniformBuf__tp_dealloc,
172  .tp_flags = Py_TPFLAGS_DEFAULT,
173  .tp_doc = pygpu_uniformbuffer__tp_doc,
174  .tp_methods = pygpu_uniformbuffer__tp_methods,
176  .tp_new = pygpu_uniformbuffer__tp_new,
177 };
178 
181 /* -------------------------------------------------------------------- */
186 {
187  BPyGPUUniformBuf *self;
188 
189  self = PyObject_New(BPyGPUUniformBuf, &BPyGPUUniformBuf_Type);
190  self->ubo = ubo;
191 
192  return (PyObject *)self;
193 }
194 
197 #undef BPYGPU_UNIFORMBUF_CHECK_OBJ
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
#define UNUSED(x)
#define UNLIKELY(x)
GPUContext * GPU_context_active_get(void)
Definition: gpu_context.cc:142
struct GPUUniformBuf GPUUniformBuf
GPUUniformBuf * GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name)
void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data)
void GPU_uniformbuf_free(GPUUniformBuf *ubo)
PyObject * self
Definition: bpy_driver.c:165
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition: gpu_py.h:14
#define BPYGPU_USE_GPUOBJ_FREE_METHOD
static int pygpu_uniformbuffer_valid_check(BPyGPUUniformBuf *bpygpu_ub)
static PyGetSetDef pygpu_uniformbuffer__tp_getseters[]
static PyObject * pygpu_uniformbuffer__tp_new(PyTypeObject *UNUSED(self), PyObject *args, PyObject *kwds)
PyDoc_STRVAR(pygpu_uniformbuffer_update_doc, ".. method:: update(data)\n" "\n" " Update the data of the uniform buffer object.\n")
#define BPYGPU_UNIFORMBUF_CHECK_OBJ(bpygpu)
PyObject * BPyGPUUniformBuf_CreatePyObject(GPUUniformBuf *ubo)
static void BPyGPUUniformBuf__tp_dealloc(BPyGPUUniformBuf *self)
PyTypeObject BPyGPUUniformBuf_Type
static PyObject * pygpu_uniformbuffer_update(BPyGPUUniformBuf *self, PyObject *obj)
static struct PyMethodDef pygpu_uniformbuffer__tp_methods[]
struct BPyGPUUniformBuf BPyGPUUniformBuf
PyObject_HEAD struct GPUUniformBuf * ubo