Blender V5.0
gpu_py_batch.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2015 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14
15#include <Python.h>
16
17#include "BLI_utildefines.h"
18
19#include "GPU_batch.hh"
20#include "GPU_state.hh"
21
23#include "../generic/python_compat.hh" /* IWYU pragma: keep. */
24
25#include "gpu_py.hh"
26#include "gpu_py_element.hh"
27#include "gpu_py_shader.hh"
29
30#include "gpu_py_batch.hh" /* own include */
31
32/* -------------------------------------------------------------------- */
35
37{
38 if (!self->batch->shader) {
39 PyErr_SetString(PyExc_RuntimeError, "batch does not have any program assigned to it");
40 return false;
41 }
42 return true;
43}
44
46
47/* -------------------------------------------------------------------- */
50
51static PyObject *pygpu_batch__tp_new(PyTypeObject * /*type*/, PyObject *args, PyObject *kwds)
52{
54
55 const char *exc_str_missing_arg = "GPUBatch.__new__() missing required argument '%s' (pos %d)";
56
58 BPyGPUVertBuf *py_vertbuf = nullptr;
59 BPyGPUIndexBuf *py_indexbuf = nullptr;
60
61 static const char *_keywords[] = {"type", "buf", "elem", nullptr};
62 static _PyArg_Parser _parser = {
64 "|$" /* Optional keyword only arguments. */
65 "O&" /* `type` */
66 "O!" /* `buf` */
67 "O!" /* `elem` */
68 ":GPUBatch.__new__",
69 _keywords,
70 nullptr,
71 };
72 if (!_PyArg_ParseTupleAndKeywordsFast(args,
73 kwds,
74 &_parser,
76 &prim_type,
78 &py_vertbuf,
80 &py_indexbuf))
81 {
82 return nullptr;
83 }
84
86 if (prim_type.value_found == GPU_PRIM_LINE_LOOP) {
87 PyErr_WarnEx(PyExc_DeprecationWarning,
88 "'LINE_LOOP' is deprecated. Please use 'LINE_STRIP' and close the segment.",
89 1);
90 }
91 else if (prim_type.value_found == GPU_PRIM_TRI_FAN) {
92 PyErr_WarnEx(
93 PyExc_DeprecationWarning,
94 "'TRI_FAN' is deprecated. Please use 'TRI_STRIP' or 'TRIS' and try modifying your "
95 "vertices or indices to match the topology.",
96 1);
97 }
98
99 if (py_vertbuf == nullptr) {
100 PyErr_Format(PyExc_TypeError, exc_str_missing_arg, _keywords[1], 2);
101 return nullptr;
102 }
103
104 blender::gpu::Batch *batch = GPU_batch_create(GPUPrimType(prim_type.value_found),
105 py_vertbuf->buf,
106 py_indexbuf ? py_indexbuf->elem : nullptr);
107
109
110#ifdef USE_GPU_PY_REFERENCES
111 ret->references = PyList_New(py_indexbuf ? 2 : 1);
112 PyList_SET_ITEM(ret->references, 0, (PyObject *)py_vertbuf);
113 Py_INCREF(py_vertbuf);
114
115 if (py_indexbuf != nullptr) {
116 PyList_SET_ITEM(ret->references, 1, (PyObject *)py_indexbuf);
117 Py_INCREF(py_indexbuf);
118 }
119
120 BLI_assert(!PyObject_GC_IsTracked((PyObject *)ret));
121 PyObject_GC_Track(ret);
122#endif
123
124 return (PyObject *)ret;
125}
126
128 /* Wrap. */
129 pygpu_batch_vertbuf_add_doc, ".. method:: vertbuf_add(buf)\n"
130"\n"
131" Add another vertex buffer to the Batch.\n"
132" It is not possible to add more vertices to the batch using this method.\n"
133" Instead it can be used to add more attributes to the existing vertices.\n"
134" A good use case would be when you have a separate\n"
135" vertex buffer for vertex positions and vertex normals.\n"
136" Current a batch can have at most " STRINGIFY(GPU_BATCH_VBO_MAX_LEN) " vertex buffers.\n"
137"\n"
138" :arg buf: The vertex buffer that will be added to the batch.\n"
139" :type buf: :class:`gpu.types.GPUVertBuf`\n"
140);
142{
143 if (!BPyGPUVertBuf_Check(py_buf)) {
144 PyErr_Format(PyExc_TypeError, "Expected a GPUVertBuf, got %s", Py_TYPE(py_buf)->tp_name);
145 return nullptr;
146 }
147
148 if (GPU_vertbuf_get_vertex_len(self->batch->verts[0]) != GPU_vertbuf_get_vertex_len(py_buf->buf))
149 {
150 PyErr_Format(PyExc_TypeError,
151 "Expected %d length, got %d",
152 GPU_vertbuf_get_vertex_len(self->batch->verts[0]),
154 return nullptr;
155 }
156
157 if (self->batch->verts[GPU_BATCH_VBO_MAX_LEN - 1] != nullptr) {
158 PyErr_SetString(
159 PyExc_RuntimeError,
160 "Maximum number of vertex buffers exceeded: " STRINGIFY(GPU_BATCH_VBO_MAX_LEN));
161 return nullptr;
162 }
163
164#ifdef USE_GPU_PY_REFERENCES
165 /* Hold user */
166 PyList_Append(self->references, (PyObject *)py_buf);
167#endif
168
169 GPU_batch_vertbuf_add(self->batch, py_buf->buf, false);
170 Py_RETURN_NONE;
171}
172
174 /* Wrap. */
175 pygpu_batch_program_set_doc,
176 ".. method:: program_set(program)\n"
177 "\n"
178 " Assign a shader to this batch that will be used for drawing when not overwritten later.\n"
179 " Note: This method has to be called in the draw context that the batch will be drawn in.\n"
180 " This function does not need to be called when you always\n"
181 " set the shader when calling :meth:`gpu.types.GPUBatch.draw`.\n"
182 "\n"
183 " :arg program: The program/shader the batch will use in future draw calls.\n"
184 " :type program: :class:`gpu.types.GPUShader`\n");
186{
187 static bool deprecation_warning_issued = false;
188
189 /* Deprecation warning raised when calling `gpu.types.GPUBatch.program_set`. */
190 if (!deprecation_warning_issued) {
191 PyErr_WarnEx(PyExc_DeprecationWarning,
192 "Calls to GPUBatch.program_set are deprecated."
193 "Please set the shader via the 'program' parameter when calling "
194 "GPUBatch.draw/draw_instanced/draw_range.",
195 1);
196 deprecation_warning_issued = true;
197 }
198
199 if (!BPyGPUShader_Check(py_shader)) {
200 PyErr_Format(PyExc_TypeError, "Expected a GPUShader, got %s", Py_TYPE(py_shader)->tp_name);
201 return nullptr;
202 }
203
204 blender::gpu::Shader *shader = py_shader->shader;
205 GPU_batch_set_shader(self->batch, shader);
206
207#ifdef USE_GPU_PY_REFERENCES
208 /* Remove existing user (if any), hold new user. */
209 int i = PyList_GET_SIZE(self->references);
210 while (--i != -1) {
211 PyObject *py_shader_test = PyList_GET_ITEM(self->references, i);
212 if (BPyGPUShader_Check(py_shader_test)) {
213 PyList_SET_ITEM(self->references, i, (PyObject *)py_shader);
214 Py_INCREF(py_shader);
215 Py_DECREF(py_shader_test);
216 /* Only ever reference one shader. */
217 break;
218 }
219 }
220 if (i != -1) {
221 PyList_Append(self->references, (PyObject *)py_shader);
222 }
223#endif
224
225 Py_RETURN_NONE;
226}
227
232static const char *pygpu_shader_check_compatibility(blender::gpu::Batch *batch)
233{
234 if (!batch->shader) {
235 return nullptr;
236 }
237
238 /* Currently only POLYLINE shaders are checked. */
239 if (!bpygpu_shader_is_polyline(batch->shader)) {
240 return nullptr;
241 }
242
243 /* Check batch compatibility with shader. */
244 for (auto *vert : blender::Span(batch->verts, ARRAY_SIZE(batch->verts))) {
245 if (!vert) {
246 continue;
247 }
248 GPUVertFormat &format = vert->format;
249 if ((format.stride % 4) != 0) {
250 return "For POLYLINE shaders, only 4-byte aligned formats are supported";
251 }
252
253 int pos_attr_id = -1;
254 int col_attr_id = -1;
255 for (uint a_idx = 0; a_idx < format.attr_len; a_idx++) {
256 const GPUVertAttr *a = &format.attrs[a_idx];
257 if ((a->offset % 4) != 0) {
258 return "For POLYLINE shaders, only 4-byte aligned attributes are supported";
259 }
261 if (pos_attr_id == -1 && name == "pos") {
262 if (!ELEM(a->type.comp_type(), GPU_COMP_F32)) {
263 return "For POLYLINE shaders, the 'pos' attribute needs to be 'F32'";
264 }
265 if (!ELEM(a->type.fetch_mode(), GPU_FETCH_FLOAT)) {
266 return "For POLYLINE shaders, the 'pos' attribute must use the 'FLOAT' fetch type";
267 }
268 pos_attr_id = a_idx;
269 }
270 else if (col_attr_id == -1 && name == "color") {
272 return "For POLYLINE shaders, the 'color' attribute needs to be 'F32' or 'U8'";
273 }
274 col_attr_id = a_idx;
275 }
276 if (pos_attr_id != -1 && col_attr_id != -1) {
277 break;
278 }
279 }
280 }
281 return nullptr;
282}
283
285 /* Wrap. */
286 pygpu_batch_draw_doc,
287 ".. method:: draw(shader=None)\n"
288 "\n"
289 " Run the drawing shader with the parameters assigned to the batch.\n"
290 "\n"
291 " :arg shader: Shader that performs the drawing operations.\n"
292 " If ``None`` is passed, the last shader set to this batch will run.\n"
293 " :type program: :class:`gpu.types.GPUShader`\n");
294static PyObject *pygpu_batch_draw(BPyGPUBatch *self, PyObject *args)
295{
296 static bool deprecation_warning_issued = false;
297
298 BPyGPUShader *py_shader = nullptr;
299
300 if (!PyArg_ParseTuple(args, "|O!:GPUBatch.draw", &BPyGPUShader_Type, &py_shader)) {
301 return nullptr;
302 }
303 if (py_shader == nullptr) {
304 if (!deprecation_warning_issued) {
305 /* Deprecation warning raised when calling gpu.types.GPUBatch.draw without a valid GPUShader.
306 */
307 PyErr_WarnEx(PyExc_DeprecationWarning,
308 "Calling GPUBatch.draw without specifying a shader is deprecated. "
309 "Please provide a valid GPUShader as the 'shader' parameter.",
310 1);
311 deprecation_warning_issued = true;
312 }
313
315 return nullptr;
316 }
317 }
318 else if (self->batch->shader != py_shader->shader) {
319 GPU_batch_set_shader(self->batch, py_shader->shader);
320 }
321
322 /* Emit a warning when trying to draw wide lines as it is too late to automatically switch to a
323 * polyline shader. */
324 if (py_shader && py_shader->is_builtin &&
326 {
327 blender::gpu::Shader *shader = py_shader->shader;
328 const float line_width = GPU_line_width_get();
329 const bool use_linesmooth = GPU_line_smooth_get();
330 if (line_width > 1.0f || use_linesmooth) {
332 PyErr_WarnEx(PyExc_DeprecationWarning,
333 "Calling GPUBatch.draw to draw wide or smooth lines with "
334 "GPU_SHADER_3D_FLAT_COLOR is deprecated. "
335 "Use GPU_SHADER_3D_POLYLINE_FLAT_COLOR instead.",
336 1);
337 }
339 PyErr_WarnEx(PyExc_DeprecationWarning,
340 "Calling GPUBatch.draw to draw wide or smooth lines with "
341 "GPU_SHADER_3D_SMOOTH_COLOR is deprecated. "
342 "Use GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR instead.",
343 1);
344 }
346 PyErr_WarnEx(PyExc_DeprecationWarning,
347 "Calling GPUBatch.draw to draw wide or smooth lines with "
348 "GPU_SHADER_3D_UNIFORM_COLOR is deprecated. "
349 "Use GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR instead.",
350 1);
351 }
352 }
353 }
354
355 /* Emit a warning when trying to draw points with a regular shader as it is too late to
356 * automatically switch to a point shader. */
357 if (py_shader && py_shader->is_builtin && self->batch->prim_type == GPU_PRIM_POINTS) {
358 blender::gpu::Shader *shader = py_shader->shader;
360 PyErr_WarnEx(PyExc_DeprecationWarning,
361 "Calling GPUBatch.draw to draw points with "
362 "GPU_SHADER_3D_FLAT_COLOR is deprecated. "
363 "Use GPU_SHADER_3D_POINT_FLAT_COLOR instead.",
364 1);
365 }
367 PyErr_WarnEx(PyExc_DeprecationWarning,
368 "Calling GPUBatch.draw to draw points with "
369 "GPU_SHADER_3D_SMOOTH_COLOR is deprecated. "
370 "Use GPU_SHADER_3D_POINT_FLAT_COLOR instead.",
371 1);
372 }
374 PyErr_WarnEx(PyExc_DeprecationWarning,
375 "Calling GPUBatch.draw to draw points with "
376 "GPU_SHADER_3D_UNIFORM_COLOR is deprecated. "
377 "Use GPU_SHADER_3D_POINT_SMOOTH_COLOR instead.",
378 1);
379 }
380 }
381
382 if (const char *error = pygpu_shader_check_compatibility(self->batch)) {
383 PyErr_SetString(PyExc_RuntimeError, error);
384 return nullptr;
385 }
386
387 GPU_batch_draw(self->batch);
388 Py_RETURN_NONE;
389}
390
392 /* Wrap. */
393 pygpu_batch_draw_instanced_doc,
394 ".. method:: draw_instanced(program, *, instance_start=0, instance_count=0)\n"
395 "\n"
396 " Draw multiple instances of the drawing program with the parameters assigned\n"
397 " to the batch. In the vertex shader, ``gl_InstanceID`` will contain the instance\n"
398 " number being drawn.\n"
399 "\n"
400 " :arg program: Program that performs the drawing operations.\n"
401 " :type program: :class:`gpu.types.GPUShader`\n"
402 " :arg instance_start: Number of the first instance to draw.\n"
403 " :type instance_start: int\n"
404 " :arg instance_count: Number of instances to draw. When not provided or set to 0\n"
405 " the number of instances will be determined by the number of rows in the first\n"
406 " vertex buffer.\n"
407 " :type instance_count: int\n");
408static PyObject *pygpu_batch_draw_instanced(BPyGPUBatch *self, PyObject *args, PyObject *kw)
409{
410 BPyGPUShader *py_program = nullptr;
411 int instance_start = 0;
412 int instance_count = 0;
413
414 static const char *_keywords[] = {"program", "instance_start", "instance_count", nullptr};
415 static _PyArg_Parser _parser = {
417 "O!" /* `program` */
418 "|$" /* Optional keyword only arguments. */
419 "i" /* `instance_start` */
420 "i" /* `instance_count` */
421 ":GPUBatch.draw_instanced",
422 _keywords,
423 nullptr,
424 };
425 if (!_PyArg_ParseTupleAndKeywordsFast(
426 args, kw, &_parser, &BPyGPUShader_Type, &py_program, &instance_start, &instance_count))
427 {
428 return nullptr;
429 }
430
431 GPU_batch_set_shader(self->batch, py_program->shader);
432 GPU_batch_draw_instance_range(self->batch, instance_start, instance_count);
433 Py_RETURN_NONE;
434}
435
437 /* Wrap. */
438 pygpu_batch_draw_range_doc,
439 ".. method:: draw_range(program, *, elem_start=0, elem_count=0)\n"
440 "\n"
441 " Run the drawing program with the parameters assigned to the batch. "
442 "Only draw the ``elem_count`` elements of the index buffer starting at ``elem_start``.\n"
443 "\n"
444 " :arg program: Program that performs the drawing operations.\n"
445 " :type program: :class:`gpu.types.GPUShader`\n"
446 " :arg elem_start: First index to draw. When not provided or set to 0 drawing\n"
447 " will start from the first element of the index buffer.\n"
448 " :type elem_start: int\n"
449 " :arg elem_count: Number of elements of the index buffer to draw. When not\n"
450 " provided or set to 0 all elements from ``elem_start`` to the end of the\n"
451 " index buffer will be drawn.\n"
452 " :type elem_count: int\n");
453static PyObject *pygpu_batch_draw_range(BPyGPUBatch *self, PyObject *args, PyObject *kw)
454{
455 BPyGPUShader *py_program = nullptr;
456 int elem_start = 0;
457 int elem_count = 0;
458
459 static const char *_keywords[] = {"program", "elem_start", "elem_count", nullptr};
460 static _PyArg_Parser _parser = {
462 "O!" /* `program` */
463 "|$" /* Optional keyword only arguments. */
464 "i" /* `elem_start` */
465 "i" /* `elem_count` */
466 ":GPUBatch.draw_range",
467 _keywords,
468 nullptr,
469 };
470 if (!_PyArg_ParseTupleAndKeywordsFast(
471 args, kw, &_parser, &BPyGPUShader_Type, &py_program, &elem_start, &elem_count))
472 {
473 return nullptr;
474 }
475
476 GPU_batch_set_shader(self->batch, py_program->shader);
477 GPU_batch_draw_range(self->batch, elem_start, elem_count);
478 Py_RETURN_NONE;
479}
480
482{
484 return nullptr;
485 }
486 GPU_shader_bind(self->batch->shader);
487 Py_RETURN_NONE;
488}
489
491{
493 return nullptr;
494 }
496 Py_RETURN_NONE;
497}
498
499#ifdef __GNUC__
500# ifdef __clang__
501# pragma clang diagnostic push
502# pragma clang diagnostic ignored "-Wcast-function-type"
503# else
504# pragma GCC diagnostic push
505# pragma GCC diagnostic ignored "-Wcast-function-type"
506# endif
507#endif
508
509static PyMethodDef pygpu_batch__tp_methods[] = {
510 {"vertbuf_add", (PyCFunction)pygpu_batch_vertbuf_add, METH_O, pygpu_batch_vertbuf_add_doc},
511 {"program_set", (PyCFunction)pygpu_batch_program_set, METH_O, pygpu_batch_program_set_doc},
512 {"draw", (PyCFunction)pygpu_batch_draw, METH_VARARGS, pygpu_batch_draw_doc},
513 {"draw_instanced",
514 (PyCFunction)pygpu_batch_draw_instanced,
515 METH_VARARGS | METH_KEYWORDS,
516 pygpu_batch_draw_instanced_doc},
517 {"draw_range",
518 (PyCFunction)pygpu_batch_draw_range,
519 METH_VARARGS | METH_KEYWORDS,
520 pygpu_batch_draw_range_doc},
521 {"_program_use_begin", (PyCFunction)pygpu_batch_program_use_begin, METH_NOARGS, ""},
522 {"_program_use_end", (PyCFunction)pygpu_batch_program_use_end, METH_NOARGS, ""},
523 {nullptr, nullptr, 0, nullptr},
524};
525
526#ifdef __GNUC__
527# ifdef __clang__
528# pragma clang diagnostic pop
529# else
530# pragma GCC diagnostic pop
531# endif
532#endif
533
534#ifdef USE_GPU_PY_REFERENCES
535
536static int pygpu_batch__tp_traverse(BPyGPUBatch *self, visitproc visit, void *arg)
537{
538 Py_VISIT(self->references);
539 return 0;
540}
541
543{
544 Py_CLEAR(self->references);
545 return 0;
546}
547
549{
550 return self->references != nullptr;
551}
552
553#endif
554
556{
557 GPU_batch_discard(self->batch);
558
559#ifdef USE_GPU_PY_REFERENCES
560 PyObject_GC_UnTrack(self);
561 if (self->references) {
563 Py_XDECREF(self->references);
564 }
565#endif
566
567 Py_TYPE(self)->tp_free(self);
568}
569
571 /* Wrap. */
572 pygpu_batch__tp_doc,
573 ".. class:: GPUBatch(type, buf, elem=None)\n"
574 "\n"
575 " Reusable container for drawable geometry.\n"
576 "\n"
577 " :arg type: The primitive type of geometry to be drawn.\n"
578 " Possible values are ``POINTS``, ``LINES``, ``TRIS``, ``LINE_STRIP``, ``LINE_LOOP``, "
579 "``TRI_STRIP``, ``TRI_FAN``, ``LINES_ADJ``, ``TRIS_ADJ`` and ``LINE_STRIP_ADJ``.\n"
580 " :type type: str\n"
581 " :arg buf: Vertex buffer containing all or some of the attributes required for drawing.\n"
582 " :type buf: :class:`gpu.types.GPUVertBuf`\n"
583 " :arg elem: An optional index buffer.\n"
584 " :type elem: :class:`gpu.types.GPUIndexBuf`\n");
585PyTypeObject BPyGPUBatch_Type = {
586 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
587 /*tp_name*/ "GPUBatch",
588 /*tp_basicsize*/ sizeof(BPyGPUBatch),
589 /*tp_itemsize*/ 0,
590 /*tp_dealloc*/ (destructor)pygpu_batch__tp_dealloc,
591 /*tp_vectorcall_offset*/ 0,
592 /*tp_getattr*/ nullptr,
593 /*tp_setattr*/ nullptr,
594 /*tp_as_async*/ nullptr,
595 /*tp_repr*/ nullptr,
596 /*tp_as_number*/ nullptr,
597 /*tp_as_sequence*/ nullptr,
598 /*tp_as_mapping*/ nullptr,
599 /*tp_hash*/ nullptr,
600 /*tp_call*/ nullptr,
601 /*tp_str*/ nullptr,
602 /*tp_getattro*/ nullptr,
603 /*tp_setattro*/ nullptr,
604 /*tp_as_buffer*/ nullptr,
605#ifdef USE_GPU_PY_REFERENCES
606 /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
607#else
608 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
609#endif
610 /*tp_doc*/ pygpu_batch__tp_doc,
611#ifdef USE_GPU_PY_REFERENCES
612 /*tp_traverse*/ (traverseproc)pygpu_batch__tp_traverse,
613#else
614 /*tp_traverse*/ nullptr,
615#endif
617 /*tp_clear*/ (inquiry)pygpu_batch__tp_clear,
618#else
619 /*tp_clear*/ nullptr,
620#endif
621 /*tp_richcompare*/ nullptr,
622 /*tp_weaklistoffset*/ 0,
623 /*tp_iter*/ nullptr,
624 /*tp_iternext*/ nullptr,
625 /*tp_methods*/ pygpu_batch__tp_methods,
626 /*tp_members*/ nullptr,
627 /*tp_getset*/ nullptr,
628 /*tp_base*/ nullptr,
629 /*tp_dict*/ nullptr,
630 /*tp_descr_get*/ nullptr,
631 /*tp_descr_set*/ nullptr,
632 /*tp_dictoffset*/ 0,
633 /*tp_init*/ nullptr,
634 /*tp_alloc*/ nullptr,
635 /*tp_new*/ pygpu_batch__tp_new,
636 /*tp_free*/ nullptr,
637#ifdef USE_GPU_PY_REFERENCES
638 /*tp_is_gc*/ (inquiry)pygpu_batch__tp_is_gc,
639#else
640 /*tp_is_gc*/ nullptr,
641#endif
642 /*tp_bases*/ nullptr,
643 /*tp_mro*/ nullptr,
644 /*tp_cache*/ nullptr,
645 /*tp_subclasses*/ nullptr,
646 /*tp_weaklist*/ nullptr,
647 /*tp_del*/ nullptr,
648 /*tp_version_tag*/ 0,
649 /*tp_finalize*/ nullptr,
650 /*tp_vectorcall*/ nullptr,
651};
652
654
655/* -------------------------------------------------------------------- */
658
659PyObject *BPyGPUBatch_CreatePyObject(blender::gpu::Batch *batch)
660{
662
663#ifdef USE_GPU_PY_REFERENCES
664 self = (BPyGPUBatch *)_PyObject_GC_New(&BPyGPUBatch_Type);
665 self->references = nullptr;
666#else
667 self = PyObject_New(BPyGPUBatch, &BPyGPUBatch_Type);
668#endif
669
670 self->batch = batch;
671
672 return (PyObject *)self;
673}
674
676
677#undef BPY_GPU_BATCH_CHECK_OBJ
#define BLI_assert(a)
Definition BLI_assert.h:46
unsigned int uint
#define ARRAY_SIZE(arr)
#define STRINGIFY(x)
#define ELEM(...)
static constexpr int GPU_BATCH_VBO_MAX_LEN
Definition GPU_batch.hh:33
void GPU_batch_discard(blender::gpu::Batch *batch)
#define GPU_batch_create(primitive_type, vertex_buf, index_buf)
Definition GPU_batch.hh:141
void GPU_batch_draw_instance_range(blender::gpu::Batch *batch, int instance_first, int instance_count)
int GPU_batch_vertbuf_add(blender::gpu::Batch *batch, blender::gpu::VertBuf *vertex_buf, bool own_vbo)
void GPU_batch_draw(blender::gpu::Batch *batch)
void GPU_batch_draw_range(blender::gpu::Batch *batch, int vertex_first, int vertex_count)
void GPU_batch_set_shader(blender::gpu::Batch *batch, blender::gpu::Shader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
GPUPrimType
@ GPU_PRIM_TRI_FAN
@ GPU_PRIM_LINE_LOOP
@ GPU_PRIM_NONE
@ GPU_PRIM_LINES
@ GPU_PRIM_POINTS
@ GPU_PRIM_LINE_STRIP
void GPU_shader_bind(blender::gpu::Shader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_unbind()
blender::gpu::Shader * GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
@ GPU_SHADER_3D_SMOOTH_COLOR
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_3D_FLAT_COLOR
bool GPU_line_smooth_get()
Definition gpu_state.cc:262
float GPU_line_width_get()
Definition gpu_state.cc:256
uint GPU_vertbuf_get_vertex_len(const blender::gpu::VertBuf *verts)
BLI_INLINE const char * GPU_vertformat_attr_name_get(const GPUVertFormat *format, const GPUVertAttr *attr, uint n_idx)
@ GPU_FETCH_FLOAT
@ GPU_COMP_F32
@ GPU_COMP_U8
PyObject * self
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
PyC_StringEnumItems bpygpu_primtype_items[]
Definition gpu_py.cc:26
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition gpu_py.hh:20
static PyObject * pygpu_batch_draw(BPyGPUBatch *self, PyObject *args)
static int pygpu_batch__tp_clear(BPyGPUBatch *self)
PyObject * BPyGPUBatch_CreatePyObject(blender::gpu::Batch *batch)
static PyObject * pygpu_batch_program_use_begin(BPyGPUBatch *self)
static int pygpu_batch__tp_traverse(BPyGPUBatch *self, visitproc visit, void *arg)
static PyObject * pygpu_batch_program_set(BPyGPUBatch *self, BPyGPUShader *py_shader)
static PyObject * pygpu_batch__tp_new(PyTypeObject *, PyObject *args, PyObject *kwds)
static PyObject * pygpu_batch_program_use_end(BPyGPUBatch *self)
static void pygpu_batch__tp_dealloc(BPyGPUBatch *self)
static bool pygpu_batch_is_program_or_error(BPyGPUBatch *self)
static PyObject * pygpu_batch_draw_instanced(BPyGPUBatch *self, PyObject *args, PyObject *kw)
static PyMethodDef pygpu_batch__tp_methods[]
static PyObject * pygpu_batch_draw_range(BPyGPUBatch *self, PyObject *args, PyObject *kw)
static int pygpu_batch__tp_is_gc(BPyGPUBatch *self)
static const char * pygpu_shader_check_compatibility(blender::gpu::Batch *batch)
PyTypeObject BPyGPUBatch_Type
PyDoc_STRVAR(pygpu_batch_vertbuf_add_doc, ".. method:: vertbuf_add(buf)\n" "\n" " Add another vertex buffer to the Batch.\n" " It is not possible to add more vertices to the batch using this method.\n" " Instead it can be used to add more attributes to the existing vertices.\n" " A good use case would be when you have a separate\n" " vertex buffer for vertex positions and vertex normals.\n" " Current a batch can have at most " STRINGIFY(GPU_BATCH_VBO_MAX_LEN) " vertex buffers.\n" "\n" " :arg buf: The vertex buffer that will be added to the batch.\n" " :type buf: :class:`gpu.types.GPUVertBuf`\n")
static PyObject * pygpu_batch_vertbuf_add(BPyGPUBatch *self, BPyGPUVertBuf *py_buf)
#define USE_GPU_PY_REFERENCES
PyTypeObject BPyGPUIndexBuf_Type
bool bpygpu_shader_is_polyline(blender::gpu::Shader *shader)
PyTypeObject BPyGPUShader_Type
#define BPyGPUShader_Check(v)
PyTypeObject BPyGPUVertBuf_Type
#define BPyGPUVertBuf_Check(v)
format
static void error(const char *str)
int PyC_ParseStringEnum(PyObject *o, void *p)
header-only compatibility defines.
Py_DECREF(oname)
#define PY_ARG_PARSER_HEAD_COMPAT()
const char * name
return ret
PyObject_VAR_HEAD blender::gpu::IndexBuf * elem
PyObject_VAR_HEAD blender::gpu::Shader * shader
PyObject_VAR_HEAD blender::gpu::VertBuf * buf
GPUVertFetchMode fetch_mode() const
GPUVertCompType comp_type() const
struct GPUVertAttr::Type type
i
Definition text_draw.cc:230