Blender V4.5
gpu_py_vertex_format.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
11
12#include <Python.h>
13
15#include "../generic/python_compat.hh" /* IWYU pragma: keep. */
16
17#include "gpu_py.hh"
18#include "gpu_py_vertex_format.hh" /* own include */
19
20/* -------------------------------------------------------------------- */
25
27 {GPU_COMP_I8, "I8"},
28 {GPU_COMP_U8, "U8"},
29 {GPU_COMP_I16, "I16"},
30 {GPU_COMP_U16, "U16"},
31 {GPU_COMP_I32, "I32"},
32 {GPU_COMP_U32, "U32"},
33 {GPU_COMP_F32, "F32"},
34 {GPU_COMP_I10, "I10"},
35 {0, nullptr},
36};
37
38/* Only for pyGPU module. To be removed with 5.0. */
40
42 {GPU_FETCH_FLOAT, "FLOAT"},
43 {GPU_FETCH_INT, "INT"},
44 {GPU_FETCH_INT_TO_FLOAT_UNIT, "INT_TO_FLOAT_UNIT"},
45 {GPU_FETCH_INT_TO_FLOAT_DEPRECATED, "INT_TO_FLOAT"},
46 {0, nullptr},
47};
48
50
51/* -------------------------------------------------------------------- */
54
55static PyObject *pygpu_vertformat__tp_new(PyTypeObject * /*type*/, PyObject *args, PyObject *kwds)
56{
58
59 if (PyTuple_GET_SIZE(args) || (kwds && PyDict_Size(kwds))) {
60 PyErr_SetString(PyExc_ValueError, "This function takes no arguments");
61 return nullptr;
62 }
63 return BPyGPUVertFormat_CreatePyObject(nullptr);
64}
65
67{
68 if (type == GPU_COMP_I10) {
69 return 4; /* Always packed as 10_10_10_2. */
70 }
71 BLI_assert(type <= GPU_COMP_F32); /* Other types have irregular sizes (not bytes). */
72 const uint sizes[] = {1, 1, 2, 2, 4, 4, 4};
73 return len * sizes[type];
74}
75
77 /* Wrap. */
78 pygpu_vertformat_attr_add_doc,
79 ".. method:: attr_add(id, comp_type, len, fetch_mode)\n"
80 "\n"
81 " Add a new attribute to the format.\n"
82 "\n"
83 " :arg id: Name the attribute. Often `position`, `normal`, ...\n"
84 " :type id: str\n"
85 " :arg comp_type: The data type that will be used store the value in memory.\n"
86 " Possible values are `I8`, `U8`, `I16`, `U16`, `I32`, `U32`, `F32` and `I10`.\n"
87 " :type comp_type: str\n"
88 " :arg len: How many individual values the attribute consists of\n"
89 " (e.g. 2 for uv coordinates).\n"
90 " :type len: int\n"
91 " :arg fetch_mode: How values from memory will be converted when used in the shader.\n"
92 " This is mainly useful for memory optimizations when you want to store values with\n"
93 " reduced precision. E.g. you can store a float in only 1 byte but it will be\n"
94 " converted to a normal 4 byte float when used.\n"
95 " Possible values are `FLOAT`, `INT`, `INT_TO_FLOAT_UNIT` and `INT_TO_FLOAT`.\n"
96 " :type fetch_mode: str\n");
97static PyObject *pygpu_vertformat_attr_add(BPyGPUVertFormat *self, PyObject *args, PyObject *kwds)
98{
99 const char *id;
100 uint len;
103
104 if (self->fmt.attr_len == GPU_VERT_ATTR_MAX_LEN) {
105 PyErr_SetString(PyExc_ValueError, "Maximum attr reached " STRINGIFY(GPU_VERT_ATTR_MAX_LEN));
106 return nullptr;
107 }
108
109 static const char *_keywords[] = {"id", "comp_type", "len", "fetch_mode", nullptr};
110 static _PyArg_Parser _parser = {
112 "$" /* Keyword only arguments. */
113 "s" /* `id` */
114 "O&" /* `comp_type` */
115 "I" /* `len` */
116 "O&" /* `fetch_mode` */
117 ":attr_add",
118 _keywords,
119 nullptr,
120 };
121 if (!_PyArg_ParseTupleAndKeywordsFast(args,
122 kwds,
123 &_parser,
124 &id,
126 &comp_type,
127 &len,
129 &fetch_mode))
130 {
131 return nullptr;
132 }
133
134 GPUVertCompType comp_type_enum = GPUVertCompType(comp_type.value_found);
135 GPUVertFetchMode fetch_mode_enum = GPUVertFetchMode(fetch_mode.value_found);
136
137 if (len > 4) {
138 PyErr_WarnEx(
139 PyExc_DeprecationWarning,
140 "Using GPUVertFormat.attr_add(...) with component count greater than 4 is deprecated. "
141 "Use several attributes for each matrix columns instead.",
142 1);
143 }
144
145 if (attr_size(comp_type_enum, len) % 4 != 0) {
146 PyErr_WarnEx(PyExc_DeprecationWarning,
147 "Using GPUVertFormat.attr_add(...) with a format that is not 4 bytes aligned is "
148 "deprecated. Add padding components and/or higher precision integers.",
149 1);
150 }
151
152 bool int_to_float = (int(fetch_mode_enum) == int(GPU_FETCH_INT_TO_FLOAT_DEPRECATED));
153 /* Fetch int to float is not supported anymore.
154 * Simply store the data as float in the vertex buffer and convert inside `attr_fill`. */
155 if (int_to_float) {
156 if (comp_type_enum == GPU_COMP_F32) {
157 PyErr_Format(PyExc_RuntimeError,
158 "GPUVertFormat.attr_add(...) fetch_mode set to INT_TO_FLOAT but component type "
159 "is not integer.");
160 return nullptr;
161 }
162 comp_type_enum = GPU_COMP_F32;
163 fetch_mode_enum = GPU_FETCH_FLOAT;
164 PyErr_WarnEx(
165 PyExc_DeprecationWarning,
166 "Using GPUVertFormat.attr_add(...) with fetch_mode set to INT_TO_FLOAT is deprecated. "
167 "Use 'F32' component type with fetch_mode 'FLOAT' instead.",
168 1);
169 }
170
171 uint attr_id = GPU_vertformat_attr_add(&self->fmt, id, comp_type_enum, len, fetch_mode_enum);
172
173 self->fmt.attrs[attr_id].python_int_to_float = int_to_float;
174
175 return PyLong_FromLong(attr_id);
176}
177
178#ifdef __GNUC__
179# ifdef __clang__
180# pragma clang diagnostic push
181# pragma clang diagnostic ignored "-Wcast-function-type"
182# else
183# pragma GCC diagnostic push
184# pragma GCC diagnostic ignored "-Wcast-function-type"
185# endif
186#endif
187
188static PyMethodDef pygpu_vertformat__tp_methods[] = {
189 {"attr_add",
190 (PyCFunction)pygpu_vertformat_attr_add,
191 METH_VARARGS | METH_KEYWORDS,
192 pygpu_vertformat_attr_add_doc},
193 {nullptr, nullptr, 0, nullptr},
194};
195
196#ifdef __GNUC__
197# ifdef __clang__
198# pragma clang diagnostic pop
199# else
200# pragma GCC diagnostic pop
201# endif
202#endif
203
205{
206 Py_TYPE(self)->tp_free(self);
207}
208
210 /* Wrap. */
211 pygpu_vertformat__tp_doc,
212 ".. class:: GPUVertFormat()\n"
213 "\n"
214 " This object contains information about the structure of a vertex buffer.\n");
215PyTypeObject BPyGPUVertFormat_Type = {
216 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
217 /*tp_name*/ "GPUVertFormat",
218 /*tp_basicsize*/ sizeof(BPyGPUVertFormat),
219 /*tp_itemsize*/ 0,
220 /*tp_dealloc*/ (destructor)pygpu_vertformat__tp_dealloc,
221 /*tp_vectorcall_offset*/ 0,
222 /*tp_getattr*/ nullptr,
223 /*tp_setattr*/ nullptr,
224 /*tp_as_async*/ nullptr,
225 /*tp_repr*/ nullptr,
226 /*tp_as_number*/ nullptr,
227 /*tp_as_sequence*/ nullptr,
228 /*tp_as_mapping*/ nullptr,
229 /*tp_hash*/ nullptr,
230 /*tp_call*/ nullptr,
231 /*tp_str*/ nullptr,
232 /*tp_getattro*/ nullptr,
233 /*tp_setattro*/ nullptr,
234 /*tp_as_buffer*/ nullptr,
235 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
236 /*tp_doc*/ pygpu_vertformat__tp_doc,
237 /*tp_traverse*/ nullptr,
238 /*tp_clear*/ nullptr,
239 /*tp_richcompare*/ nullptr,
240 /*tp_weaklistoffset*/ 0,
241 /*tp_iter*/ nullptr,
242 /*tp_iternext*/ nullptr,
243 /*tp_methods*/ pygpu_vertformat__tp_methods,
244 /*tp_members*/ nullptr,
245 /*tp_getset*/ nullptr,
246 /*tp_base*/ nullptr,
247 /*tp_dict*/ nullptr,
248 /*tp_descr_get*/ nullptr,
249 /*tp_descr_set*/ nullptr,
250 /*tp_dictoffset*/ 0,
251 /*tp_init*/ nullptr,
252 /*tp_alloc*/ nullptr,
253 /*tp_new*/ pygpu_vertformat__tp_new,
254 /*tp_free*/ nullptr,
255 /*tp_is_gc*/ nullptr,
256 /*tp_bases*/ nullptr,
257 /*tp_mro*/ nullptr,
258 /*tp_cache*/ nullptr,
259 /*tp_subclasses*/ nullptr,
260 /*tp_weaklist*/ nullptr,
261 /*tp_del*/ nullptr,
262 /*tp_version_tag*/ 0,
263 /*tp_finalize*/ nullptr,
264 /*tp_vectorcall*/ nullptr,
265};
266
268
269/* -------------------------------------------------------------------- */
272
274{
276
278 if (fmt) {
279 self->fmt = *fmt;
280 }
281 else {
282 memset(&self->fmt, 0, sizeof(self->fmt));
283 }
284
285 return (PyObject *)self;
286}
287
#define BLI_assert(a)
Definition BLI_assert.h:46
unsigned int uint
#define STRINGIFY(x)
static constexpr int GPU_VERT_ATTR_MAX_LEN
GPUVertFetchMode
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
@ GPU_FETCH_INT
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
GPUVertCompType
@ GPU_COMP_U16
@ GPU_COMP_I10
@ GPU_COMP_F32
@ GPU_COMP_I32
@ GPU_COMP_I8
@ GPU_COMP_U32
@ GPU_COMP_I16
@ GPU_COMP_U8
PyObject * self
struct @064345207361167251075330302113175271221317160336::@201157344026354305110036153026103256267276205234 attr_id
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition gpu_py.hh:20
PyTypeObject BPyGPUVertFormat_Type
static PyObject * pygpu_vertformat_attr_add(BPyGPUVertFormat *self, PyObject *args, PyObject *kwds)
static PyObject * pygpu_vertformat__tp_new(PyTypeObject *, PyObject *args, PyObject *kwds)
PyObject * BPyGPUVertFormat_CreatePyObject(GPUVertFormat *fmt)
PyDoc_STRVAR(pygpu_vertformat_attr_add_doc, ".. method:: attr_add(id, comp_type, len, fetch_mode)\n" "\n" " Add a new attribute to the format.\n" "\n" " :arg id: Name the attribute. Often `position`, `normal`, ...\n" " :type id: str\n" " :arg comp_type: The data type that will be used store the value in memory.\n" " Possible values are `I8`, `U8`, `I16`, `U16`, `I32`, `U32`, `F32` and `I10`.\n" " :type comp_type: str\n" " :arg len: How many individual values the attribute consists of\n" " (e.g. 2 for uv coordinates).\n" " :type len: int\n" " :arg fetch_mode: How values from memory will be converted when used in the shader.\n" " This is mainly useful for memory optimizations when you want to store values with\n" " reduced precision. E.g. you can store a float in only 1 byte but it will be\n" " converted to a normal 4 byte float when used.\n" " Possible values are `FLOAT`, `INT`, `INT_TO_FLOAT_UNIT` and `INT_TO_FLOAT`.\n" " :type fetch_mode: str\n")
static PyMethodDef pygpu_vertformat__tp_methods[]
static void pygpu_vertformat__tp_dealloc(BPyGPUVertFormat *self)
static PyC_StringEnumItems pygpu_vertcomptype_items[]
@ GPU_FETCH_INT_TO_FLOAT_DEPRECATED
static uint attr_size(GPUVertCompType type, int len)
static PyC_StringEnumItems pygpu_vertfetchmode_items[]
int PyC_ParseStringEnum(PyObject *o, void *p)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
uint len