Blender  V3.3
gpu_py_vertex_buffer.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
10 #include <Python.h>
11 
12 #include "GPU_vertex_buffer.h"
13 
14 #include "BLI_math.h"
15 
16 #include "MEM_guardedalloc.h"
17 
18 #include "../generic/py_capi_utils.h"
19 #include "../generic/python_utildefines.h"
20 
21 #include "gpu_py_vertex_buffer.h" /* own include */
22 #include "gpu_py_vertex_format.h"
23 
24 /* -------------------------------------------------------------------- */
28 #define PYGPU_AS_NATIVE_SWITCH(attr) \
29  switch (attr->comp_type) { \
30  case GPU_COMP_I8: { \
31  PY_AS_NATIVE(int8_t, PyC_Long_AsI8); \
32  break; \
33  } \
34  case GPU_COMP_U8: { \
35  PY_AS_NATIVE(uint8_t, PyC_Long_AsU8); \
36  break; \
37  } \
38  case GPU_COMP_I16: { \
39  PY_AS_NATIVE(int16_t, PyC_Long_AsI16); \
40  break; \
41  } \
42  case GPU_COMP_U16: { \
43  PY_AS_NATIVE(uint16_t, PyC_Long_AsU16); \
44  break; \
45  } \
46  case GPU_COMP_I32: { \
47  PY_AS_NATIVE(int32_t, PyC_Long_AsI32); \
48  break; \
49  } \
50  case GPU_COMP_U32: { \
51  PY_AS_NATIVE(uint32_t, PyC_Long_AsU32); \
52  break; \
53  } \
54  case GPU_COMP_F32: { \
55  PY_AS_NATIVE(float, PyFloat_AsDouble); \
56  break; \
57  } \
58  default: \
59  BLI_assert_unreachable(); \
60  break; \
61  } \
62  ((void)0)
63 
64 /* No error checking, callers must run PyErr_Occurred */
65 static void pygpu_fill_format_elem(void *data_dst_void, PyObject *py_src, const GPUVertAttr *attr)
66 {
67 #define PY_AS_NATIVE(ty_dst, py_as_native) \
68  { \
69  ty_dst *data_dst = data_dst_void; \
70  *data_dst = py_as_native(py_src); \
71  } \
72  ((void)0)
73 
75 
76 #undef PY_AS_NATIVE
77 }
78 
79 /* No error checking, callers must run PyErr_Occurred */
80 static void pygpu_fill_format_sequence(void *data_dst_void,
81  PyObject *py_seq_fast,
82  const GPUVertAttr *attr)
83 {
84  const uint len = attr->comp_len;
85  PyObject **value_fast_items = PySequence_Fast_ITEMS(py_seq_fast);
86 
90 #define PY_AS_NATIVE(ty_dst, py_as_native) \
91  ty_dst *data_dst = data_dst_void; \
92  for (uint i = 0; i < len; i++) { \
93  data_dst[i] = py_as_native(value_fast_items[i]); \
94  } \
95  ((void)0)
96 
98 
99 #undef PY_AS_NATIVE
100 }
101 
102 #undef PYGPU_AS_NATIVE_SWITCH
103 #undef WARN_TYPE_LIMIT_PUSH
104 #undef WARN_TYPE_LIMIT_POP
105 
107  uint data_id,
108  PyObject *seq,
109  const char *error_prefix)
110 {
111  const char *exc_str_size_mismatch = "Expected a %s of size %d, got %u";
112 
113  bool ok = true;
114  const GPUVertAttr *attr = &GPU_vertbuf_get_format(vbo)->attrs[data_id];
115  uint vert_len = GPU_vertbuf_get_vertex_len(vbo);
116 
117  if (PyObject_CheckBuffer(seq)) {
118  Py_buffer pybuffer;
119 
120  if (PyObject_GetBuffer(seq, &pybuffer, PyBUF_STRIDES | PyBUF_ND) == -1) {
121  /* PyObject_GetBuffer raise a PyExc_BufferError */
122  return false;
123  }
124 
125  const uint comp_len = pybuffer.ndim == 1 ? 1 : (uint)pybuffer.shape[1];
126 
127  if (pybuffer.shape[0] != vert_len) {
128  PyErr_Format(
129  PyExc_ValueError, exc_str_size_mismatch, "sequence", vert_len, pybuffer.shape[0]);
130  ok = false;
131  }
132  else if (comp_len != attr->comp_len) {
133  PyErr_Format(PyExc_ValueError, exc_str_size_mismatch, "component", attr->comp_len, comp_len);
134  ok = false;
135  }
136  else {
137  GPU_vertbuf_attr_fill_stride(vbo, data_id, pybuffer.strides[0], pybuffer.buf);
138  }
139 
140  PyBuffer_Release(&pybuffer);
141  }
142  else {
143  GPUVertBufRaw data_step;
144  GPU_vertbuf_attr_get_raw_data(vbo, data_id, &data_step);
145 
146  PyObject *seq_fast = PySequence_Fast(seq, "Vertex buffer fill");
147  if (seq_fast == NULL) {
148  return false;
149  }
150 
151  const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast);
152 
153  if (seq_len != vert_len) {
154  PyErr_Format(PyExc_ValueError, exc_str_size_mismatch, "sequence", vert_len, seq_len);
155  }
156 
157  PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast);
158 
159  if (attr->comp_len == 1) {
160  for (uint i = 0; i < seq_len; i++) {
161  uchar *data = (uchar *)GPU_vertbuf_raw_step(&data_step);
162  PyObject *item = seq_items[i];
163  pygpu_fill_format_elem(data, item, attr);
164  }
165  }
166  else {
167  for (uint i = 0; i < seq_len; i++) {
168  uchar *data = (uchar *)GPU_vertbuf_raw_step(&data_step);
169  PyObject *seq_fast_item = PySequence_Fast(seq_items[i], error_prefix);
170 
171  if (seq_fast_item == NULL) {
172  ok = false;
173  goto finally;
174  }
175  if (PySequence_Fast_GET_SIZE(seq_fast_item) != attr->comp_len) {
176  PyErr_Format(PyExc_ValueError,
177  exc_str_size_mismatch,
178  "sequence",
179  attr->comp_len,
180  PySequence_Fast_GET_SIZE(seq_fast_item));
181  ok = false;
182  Py_DECREF(seq_fast_item);
183  goto finally;
184  }
185 
186  /* May trigger error, check below */
187  pygpu_fill_format_sequence(data, seq_fast_item, attr);
188  Py_DECREF(seq_fast_item);
189  }
190  }
191 
192  if (PyErr_Occurred()) {
193  ok = false;
194  }
195 
196  finally:
197 
198  Py_DECREF(seq_fast);
199  }
200  return ok;
201 }
202 
204  int id,
205  PyObject *py_seq_data,
206  const char *error_prefix)
207 {
208  if (id < 0 || id >= GPU_vertbuf_get_format(buf)->attr_len) {
209  PyErr_Format(PyExc_ValueError, "Format id %d out of range", id);
210  return 0;
211  }
212 
213  if (GPU_vertbuf_get_data(buf) == NULL) {
214  PyErr_SetString(PyExc_ValueError, "Can't fill, static buffer already in use");
215  return 0;
216  }
217 
218  if (!pygpu_vertbuf_fill_impl(buf, (uint)id, py_seq_data, error_prefix)) {
219  return 0;
220  }
221 
222  return 1;
223 }
224 
227 /* -------------------------------------------------------------------- */
231 static PyObject *pygpu_vertbuf__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
232 {
233  struct {
234  PyObject *py_fmt;
235  uint len;
236  } params;
237 
238  static const char *_keywords[] = {"format", "len", NULL};
239  static _PyArg_Parser _parser = {
240  "O!" /* `format` */
241  "I" /* `len` */
242  ":GPUVertBuf.__new__",
243  _keywords,
244  0,
245  };
246  if (!_PyArg_ParseTupleAndKeywordsFast(
247  args, kwds, &_parser, &BPyGPUVertFormat_Type, &params.py_fmt, &params.len)) {
248  return NULL;
249  }
250 
251  const GPUVertFormat *fmt = &((BPyGPUVertFormat *)params.py_fmt)->fmt;
253 
254  GPU_vertbuf_data_alloc(vbo, params.len);
255 
256  return BPyGPUVertBuf_CreatePyObject(vbo);
257 }
258 
259 PyDoc_STRVAR(pygpu_vertbuf_attr_fill_doc,
260  ".. method:: attr_fill(id, data)\n"
261  "\n"
262  " Insert data into the buffer for a single attribute.\n"
263  "\n"
264  " :param id: Either the name or the id of the attribute.\n"
265  " :type id: int or str\n"
266  " :param data: Sequence of data that should be stored in the buffer\n"
267  " :type data: sequence of floats, ints, vectors or matrices\n");
268 static PyObject *pygpu_vertbuf_attr_fill(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds)
269 {
270  PyObject *data;
271  PyObject *identifier;
272 
273  static const char *_keywords[] = {"id", "data", NULL};
274  static _PyArg_Parser _parser = {
275  "O" /* `id` */
276  "O" /* `data` */
277  ":attr_fill",
278  _keywords,
279  0,
280  };
281  if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &identifier, &data)) {
282  return NULL;
283  }
284 
285  int id;
286 
287  if (PyLong_Check(identifier)) {
288  id = PyLong_AsLong(identifier);
289  }
290  else if (PyUnicode_Check(identifier)) {
292  const char *name = PyUnicode_AsUTF8(identifier);
294  if (id == -1) {
295  PyErr_SetString(PyExc_ValueError, "Unknown attribute name");
296  return NULL;
297  }
298  }
299  else {
300  PyErr_SetString(PyExc_TypeError, "expected int or str type as identifier");
301  return NULL;
302  }
303 
304  if (!pygpu_vertbuf_fill(self->buf, id, data, "GPUVertBuf.attr_fill")) {
305  return NULL;
306  }
307 
308  Py_RETURN_NONE;
309 }
310 
311 static struct PyMethodDef pygpu_vertbuf__tp_methods[] = {
312  {"attr_fill",
313  (PyCFunction)pygpu_vertbuf_attr_fill,
314  METH_VARARGS | METH_KEYWORDS,
315  pygpu_vertbuf_attr_fill_doc},
316  {NULL, NULL, 0, NULL},
317 };
318 
320 {
322  Py_TYPE(self)->tp_free(self);
323 }
324 
325 PyDoc_STRVAR(pygpu_vertbuf__tp_doc,
326  ".. class:: GPUVertBuf(format, len)\n"
327  "\n"
328  " Contains a VBO.\n"
329  "\n"
330  " :param format: Vertex format.\n"
331  " :type buf: :class:`gpu.types.GPUVertFormat`\n"
332  " :param len: Amount of vertices that will fit into this buffer.\n"
333  " :type type: `int`\n");
334 PyTypeObject BPyGPUVertBuf_Type = {
335  PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUVertBuf",
336  .tp_basicsize = sizeof(BPyGPUVertBuf),
337  .tp_dealloc = (destructor)pygpu_vertbuf__tp_dealloc,
338  .tp_flags = Py_TPFLAGS_DEFAULT,
339  .tp_doc = pygpu_vertbuf__tp_doc,
340  .tp_methods = pygpu_vertbuf__tp_methods,
341  .tp_new = pygpu_vertbuf__tp_new,
342 };
343 
346 /* -------------------------------------------------------------------- */
351 {
352  BPyGPUVertBuf *self;
353 
354  self = PyObject_New(BPyGPUVertBuf, &BPyGPUVertBuf_Type);
355  self->buf = buf;
356 
357  return (PyObject *)self;
358 }
359 
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED(x)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
const GPUVertFormat * GPU_vertbuf_get_format(const GPUVertBuf *verts)
uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts)
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_discard(GPUVertBuf *)
struct GPUVertBuf GPUVertBuf
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
void GPU_vertbuf_attr_fill_stride(GPUVertBuf *, uint a_idx, uint stride, const void *data)
void * GPU_vertbuf_get_data(const GPUVertBuf *verts)
GPU_INLINE void * GPU_vertbuf_raw_step(GPUVertBufRaw *a)
void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *, uint a_idx, GPUVertBufRaw *access)
int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name)
Read Guarded memory(de)allocation.
PyObject * self
Definition: bpy_driver.c:165
int len
Definition: draw_manager.c:108
PyTypeObject BPyGPUVertBuf_Type
static PyObject * pygpu_vertbuf__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
static int pygpu_vertbuf_fill(GPUVertBuf *buf, int id, PyObject *py_seq_data, const char *error_prefix)
static struct PyMethodDef pygpu_vertbuf__tp_methods[]
PyObject * BPyGPUVertBuf_CreatePyObject(GPUVertBuf *buf)
#define PYGPU_AS_NATIVE_SWITCH(attr)
static void pygpu_fill_format_sequence(void *data_dst_void, PyObject *py_seq_fast, const GPUVertAttr *attr)
static PyObject * pygpu_vertbuf_attr_fill(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds)
static void pygpu_fill_format_elem(void *data_dst_void, PyObject *py_src, const GPUVertAttr *attr)
PyDoc_STRVAR(pygpu_vertbuf_attr_fill_doc, ".. method:: attr_fill(id, data)\n" "\n" " Insert data into the buffer for a single attribute.\n" "\n" " :param id: Either the name or the id of the attribute.\n" " :type id: int or str\n" " :param data: Sequence of data that should be stored in the buffer\n" " :type data: sequence of floats, ints, vectors or matrices\n")
static void pygpu_vertbuf__tp_dealloc(BPyGPUVertBuf *self)
static bool pygpu_vertbuf_fill_impl(GPUVertBuf *vbo, uint data_id, PyObject *seq, const char *error_prefix)
struct BPyGPUVertBuf BPyGPUVertBuf
PyTypeObject BPyGPUVertFormat_Type
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
format
Definition: logImageCore.h:38
GPUVertAttr attrs[GPU_VERT_ATTR_MAX_LEN]