Blender V4.3
gpu_py_element.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12#include <Python.h>
13
14#include "GPU_index_buffer.hh"
15
16#include "MEM_guardedalloc.h"
17
20
21#include "gpu_py.hh"
22#include "gpu_py_element.hh" /* own include */
23
24/* -------------------------------------------------------------------- */
28static PyObject *pygpu_IndexBuf__tp_new(PyTypeObject * /*type*/, PyObject *args, PyObject *kwds)
29{
31
32 const char *error_prefix = "IndexBuf.__new__";
33 bool ok = true;
34
36 PyObject *seq;
37
38 uint verts_per_prim;
39 uint index_len;
40 GPUIndexBufBuilder builder;
41
42 static const char *_keywords[] = {"type", "seq", nullptr};
43 static _PyArg_Parser _parser = {
45 "$O" /* `type` */
46 "&O" /* `seq` */
47 ":IndexBuf.__new__",
48 _keywords,
49 nullptr,
50 };
51 if (!_PyArg_ParseTupleAndKeywordsFast(
52 args, kwds, &_parser, PyC_ParseStringEnum, &prim_type, &seq))
53 {
54 return nullptr;
55 }
56
57 verts_per_prim = GPU_indexbuf_primitive_len(GPUPrimType(prim_type.value_found));
58 if (verts_per_prim == -1) {
59 PyErr_Format(PyExc_ValueError,
60 "The argument 'type' must be "
61 "'POINTS', 'LINES', 'TRIS', 'LINES_ADJ' or 'TRIS_ADJ'");
62 return nullptr;
63 }
64
65 if (PyObject_CheckBuffer(seq)) {
66 Py_buffer pybuffer;
67
68 if (PyObject_GetBuffer(seq, &pybuffer, PyBUF_FORMAT | PyBUF_ND) == -1) {
69 /* PyObject_GetBuffer already handles error messages. */
70 return nullptr;
71 }
72
73 if (pybuffer.ndim != 1 && pybuffer.shape[1] != verts_per_prim) {
74 PyErr_Format(PyExc_ValueError, "Each primitive must exactly %d indices", verts_per_prim);
75 PyBuffer_Release(&pybuffer);
76 return nullptr;
77 }
78
79 if (pybuffer.itemsize != 4 ||
81 {
82 PyErr_Format(PyExc_ValueError, "Each index must be an 4-bytes integer value");
83 PyBuffer_Release(&pybuffer);
84 return nullptr;
85 }
86
87 index_len = pybuffer.shape[0];
88 if (pybuffer.ndim != 1) {
89 index_len *= pybuffer.shape[1];
90 }
91
92 /* The `vertex_len` parameter is only used for asserts in the Debug build. */
93 /* Not very useful in python since scripts are often tested in Release build. */
94 /* Use `INT_MAX` instead of the actual number of vertices. */
95 GPU_indexbuf_init(&builder, GPUPrimType(prim_type.value_found), index_len, INT_MAX);
96
97 uint *buf = static_cast<uint *>(pybuffer.buf);
98 for (uint i = index_len; i--; buf++) {
99 GPU_indexbuf_add_generic_vert(&builder, *buf);
100 }
101
102 PyBuffer_Release(&pybuffer);
103 }
104 else {
105 PyObject *seq_fast = PySequence_Fast(seq, error_prefix);
106
107 if (seq_fast == nullptr) {
108 return nullptr;
109 }
110
111 const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast);
112
113 PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast);
114
115 index_len = seq_len * verts_per_prim;
116
117 /* The `vertex_len` parameter is only used for asserts in the Debug build. */
118 /* Not very useful in python since scripts are often tested in Release build. */
119 /* Use `INT_MAX` instead of the actual number of vertices. */
120 GPU_indexbuf_init(&builder, GPUPrimType(prim_type.value_found), index_len, INT_MAX);
121
122 if (verts_per_prim == 1) {
123 for (uint i = 0; i < seq_len; i++) {
124 GPU_indexbuf_add_generic_vert(&builder, PyC_Long_AsU32(seq_items[i]));
125 }
126 }
127 else {
128 int values[4];
129 for (uint i = 0; i < seq_len; i++) {
130 PyObject *seq_fast_item = PySequence_Fast(seq_items[i], error_prefix);
131 if (seq_fast_item == nullptr) {
132 PyErr_Format(PyExc_TypeError,
133 "%s: expected a sequence, got %s",
134 error_prefix,
135 Py_TYPE(seq_items[i])->tp_name);
136 ok = false;
137 goto finally;
138 }
139
140 ok = PyC_AsArray_FAST(values,
141 sizeof(*values),
142 seq_fast_item,
143 verts_per_prim,
144 &PyLong_Type,
145 error_prefix) == 0;
146
147 if (ok) {
148 for (uint j = 0; j < verts_per_prim; j++) {
149 GPU_indexbuf_add_generic_vert(&builder, values[j]);
150 }
151 }
152 Py_DECREF(seq_fast_item);
153 }
154 }
155
156 if (PyErr_Occurred()) {
157 ok = false;
158 }
159
160 finally:
161
162 Py_DECREF(seq_fast);
163 }
164
165 if (ok == false) {
166 MEM_freeN(builder.data);
167 return nullptr;
168 }
169
171}
172
174{
176 Py_TYPE(self)->tp_free(self);
177}
178
180 /* Wrap. */
181 pygpu_IndexBuf__tp_doc,
182 ".. class:: GPUIndexBuf(type, seq)\n"
183 "\n"
184 " Contains an index buffer.\n"
185 "\n"
186 " :arg type: The primitive type this index buffer is composed of.\n"
187 " Possible values are [``POINTS``, ``LINES``, ``TRIS``, ``LINES_ADJ``, ``TRIS_ADJ``].\n"
188 " :type type: str\n"
189 " :arg seq: Indices this index buffer will contain.\n"
190 " Whether a 1D or 2D sequence is required depends on the type.\n"
191 " Optionally the sequence can support the buffer protocol.\n"
192 " :type seq: Buffer | Sequence[int] | Sequence[Sequence[int]]\n");
193PyTypeObject BPyGPUIndexBuf_Type = {
194 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
195 /*tp_name*/ "GPUIndexBuf",
196 /*tp_basicsize*/ sizeof(BPyGPUIndexBuf),
197 /*tp_itemsize*/ 0,
198 /*tp_dealloc*/ (destructor)pygpu_IndexBuf__tp_dealloc,
199 /*tp_vectorcall_offset*/ 0,
200 /*tp_getattr*/ nullptr,
201 /*tp_setattr*/ nullptr,
202 /*tp_as_async*/ nullptr,
203 /*tp_repr*/ nullptr,
204 /*tp_as_number*/ nullptr,
205 /*tp_as_sequence*/ nullptr,
206 /*tp_as_mapping*/ nullptr,
207 /*tp_hash*/ nullptr,
208 /*tp_call*/ nullptr,
209 /*tp_str*/ nullptr,
210 /*tp_getattro*/ nullptr,
211 /*tp_setattro*/ nullptr,
212 /*tp_as_buffer*/ nullptr,
213 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
214 /*tp_doc*/ pygpu_IndexBuf__tp_doc,
215 /*tp_traverse*/ nullptr,
216 /*tp_clear*/ nullptr,
217 /*tp_richcompare*/ nullptr,
218 /*tp_weaklistoffset*/ 0,
219 /*tp_iter*/ nullptr,
220 /*tp_iternext*/ nullptr,
221 /*tp_methods*/ nullptr,
222 /*tp_members*/ nullptr,
223 /*tp_getset*/ nullptr,
224 /*tp_base*/ nullptr,
225 /*tp_dict*/ nullptr,
226 /*tp_descr_get*/ nullptr,
227 /*tp_descr_set*/ nullptr,
228 /*tp_dictoffset*/ 0,
229 /*tp_init*/ nullptr,
230 /*tp_alloc*/ nullptr,
231 /*tp_new*/ pygpu_IndexBuf__tp_new,
232 /*tp_free*/ nullptr,
233 /*tp_is_gc*/ nullptr,
234 /*tp_bases*/ nullptr,
235 /*tp_mro*/ nullptr,
236 /*tp_cache*/ nullptr,
237 /*tp_subclasses*/ nullptr,
238 /*tp_weaklist*/ nullptr,
239 /*tp_del*/ nullptr,
240 /*tp_version_tag*/ 0,
241 /*tp_finalize*/ nullptr,
242 /*tp_vectorcall*/ nullptr,
243};
244
247/* -------------------------------------------------------------------- */
252{
254
255 self = PyObject_New(BPyGPUIndexBuf, &BPyGPUIndexBuf_Type);
256 self->elem = elem;
257
258 return (PyObject *)self;
259}
260
unsigned int uint
void GPU_indexbuf_discard(blender::gpu::IndexBuf *elem)
int GPU_indexbuf_primitive_len(GPUPrimType prim_type)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
blender::gpu::IndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *)
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *, uint v)
GPUPrimType
@ GPU_PRIM_NONE
Read Guarded memory(de)allocation.
PyObject * self
PyC_StringEnumItems bpygpu_primtype_items[]
Definition gpu_py.cc:26
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition gpu_py.hh:18
PyDoc_STRVAR(pygpu_IndexBuf__tp_doc, ".. class:: GPUIndexBuf(type, seq)\n" "\n" " Contains an index buffer.\n" "\n" " :arg type: The primitive type this index buffer is composed of.\n" " Possible values are [``POINTS``, ``LINES``, ``TRIS``, ``LINES_ADJ``, ``TRIS_ADJ``].\n" " :type type: str\n" " :arg seq: Indices this index buffer will contain.\n" " Whether a 1D or 2D sequence is required depends on the type.\n" " Optionally the sequence can support the buffer protocol.\n" " :type seq: Buffer | Sequence[int] | Sequence[Sequence[int]]\n")
static void pygpu_IndexBuf__tp_dealloc(BPyGPUIndexBuf *self)
PyObject * BPyGPUIndexBuf_CreatePyObject(blender::gpu::IndexBuf *elem)
static PyObject * pygpu_IndexBuf__tp_new(PyTypeObject *, PyObject *args, PyObject *kwds)
PyTypeObject BPyGPUIndexBuf_Type
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
char PyC_StructFmt_type_from_str(const char *typestr)
int PyC_ParseStringEnum(PyObject *o, void *p)
uint32_t PyC_Long_AsU32(PyObject *value)
int PyC_AsArray_FAST(void *array, const size_t array_item_size, PyObject *value_fast, const Py_ssize_t length, const PyTypeObject *type, const char *error_prefix)
bool PyC_StructFmt_type_is_float_any(char format)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()