Blender V4.3
gpu_py_shader.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 "BLI_utildefines.h"
15
16#include "GPU_shader.hh"
17#include "GPU_texture.hh"
18#include "GPU_uniform_buffer.hh"
19
23
25
26#include "gpu_py.hh"
27#include "gpu_py_texture.hh"
30
31#include "gpu_py_shader.hh" /* own include */
32
33/* -------------------------------------------------------------------- */
37#define PYDOC_BUILTIN_SHADER_DESCRIPTION \
38 "``FLAT_COLOR``\n" \
39 " :Attributes: vec3 pos, vec4 color\n" \
40 " :Uniforms: none\n" \
41 "``IMAGE``\n" \
42 " :Attributes: vec3 pos, vec2 texCoord\n" \
43 " :Uniforms: sampler2D image\n" \
44 "``IMAGE_COLOR``\n" \
45 " :Attributes: vec3 pos, vec2 texCoord\n" \
46 " :Uniforms: sampler2D image, vec4 color\n" \
47 "``SMOOTH_COLOR``\n" \
48 " :Attributes: vec3 pos, vec4 color\n" \
49 " :Uniforms: none\n" \
50 "``UNIFORM_COLOR``\n" \
51 " :Attributes: vec3 pos\n" \
52 " :Uniforms: vec4 color\n" \
53 "``POLYLINE_FLAT_COLOR``\n" \
54 " :Attributes: vec3 pos, vec4 color\n" \
55 " :Uniforms: vec2 viewportSize, float lineWidth\n" \
56 "``POLYLINE_SMOOTH_COLOR``\n" \
57 " :Attributes: vec3 pos, vec4 color\n" \
58 " :Uniforms: vec2 viewportSize, float lineWidth\n" \
59 "``POLYLINE_UNIFORM_COLOR``\n" \
60 " :Attributes: vec3 pos\n" \
61 " :Uniforms: vec2 viewportSize, float lineWidth\n"
62
64 {GPU_SHADER_3D_FLAT_COLOR, "FLAT_COLOR"},
65 {GPU_SHADER_3D_IMAGE, "IMAGE"},
66 {GPU_SHADER_3D_IMAGE_COLOR, "IMAGE_COLOR"},
67 {GPU_SHADER_3D_SMOOTH_COLOR, "SMOOTH_COLOR"},
68 {GPU_SHADER_3D_UNIFORM_COLOR, "UNIFORM_COLOR"},
69 {GPU_SHADER_3D_POLYLINE_FLAT_COLOR, "POLYLINE_FLAT_COLOR"},
70 {GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR, "POLYLINE_SMOOTH_COLOR"},
71 {GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR, "POLYLINE_UNIFORM_COLOR"},
72 {0, nullptr},
73};
74
76 {GPU_SHADER_CFG_DEFAULT, "DEFAULT"},
77 {GPU_SHADER_CFG_CLIPPED, "CLIPPED"},
78 {0, nullptr},
79};
80
82 const char *name,
83 const char *error_prefix)
84{
85 const int uniform = GPU_shader_get_uniform(shader, name);
86
87 if (uniform == -1) {
88 PyErr_Format(PyExc_ValueError, "%s: uniform %.32s not found", error_prefix, name);
89 }
90
91 return uniform;
92}
93
96/* -------------------------------------------------------------------- */
100static PyObject *pygpu_shader__tp_new(PyTypeObject * /*type*/, PyObject *args, PyObject *kwds)
101{
103
104 struct {
105 const char *vertexcode;
106 const char *fragcode;
107 const char *geocode;
108 const char *libcode;
109 const char *defines;
110 const char *name;
111 } params = {nullptr};
112
113 static const char *_keywords[] = {
114 "vertexcode", "fragcode", "geocode", "libcode", "defines", "name", nullptr};
115 static _PyArg_Parser _parser = {
117 "s" /* `vertexcode` */
118 "s" /* `fragcode` */
119 "|$" /* Optional keyword only arguments. */
120 "s" /* `geocode` */
121 "s" /* `libcode` */
122 "s" /* `defines` */
123 "s" /* `name` */
124 ":GPUShader.__new__",
125 _keywords,
126 nullptr,
127 };
128 if (!_PyArg_ParseTupleAndKeywordsFast(args,
129 kwds,
130 &_parser,
131 &params.vertexcode,
132 &params.fragcode,
133 &params.geocode,
134 &params.libcode,
135 &params.defines,
136 &params.name))
137 {
138 return nullptr;
139 }
140
142 params.fragcode,
143 params.geocode,
144 params.libcode,
145 params.defines,
146 params.name);
147
148 if (shader == nullptr) {
149 PyErr_SetString(PyExc_Exception, "Shader Compile Error, see console for more details");
150 return nullptr;
151 }
152
153 return BPyGPUShader_CreatePyObject(shader, false);
154}
155
157 /* Wrap. */
158 pygpu_shader_bind_doc,
159 ".. method:: bind()\n"
160 "\n"
161 " Bind the shader object. Required to be able to change uniforms of this shader.\n");
163{
164 GPU_shader_bind(self->shader);
165 Py_RETURN_NONE;
166}
167
169 /* Wrap. */
170 pygpu_shader_uniform_from_name_doc,
171 ".. method:: uniform_from_name(name)\n"
172 "\n"
173 " Get uniform location by name.\n"
174 "\n"
175 " :arg name: Name of the uniform variable whose location is to be queried.\n"
176 " :type name: str\n"
177 " :return: Location of the uniform variable.\n"
178 " :rtype: int\n");
179static PyObject *pygpu_shader_uniform_from_name(BPyGPUShader *self, PyObject *arg)
180{
181 const char *name = PyUnicode_AsUTF8(arg);
182 if (name == nullptr) {
183 return nullptr;
184 }
185
186 const int uniform = pygpu_shader_uniform_location_get(
187 self->shader, name, "GPUShader.get_uniform");
188
189 if (uniform == -1) {
190 return nullptr;
191 }
192
193 return PyLong_FromLong(uniform);
194}
195
197 /* Wrap. */
198 pygpu_shader_uniform_block_from_name_doc,
199 ".. method:: uniform_block_from_name(name)\n"
200 "\n"
201 " Get uniform block location by name.\n"
202 "\n"
203 " :arg name: Name of the uniform block variable whose location is to be queried.\n"
204 " :type name: str\n"
205 " :return: The location of the uniform block variable.\n"
206 " :rtype: int\n");
208{
209 const char *name = PyUnicode_AsUTF8(arg);
210 if (name == nullptr) {
211 return nullptr;
212 }
213
214 const int uniform = GPU_shader_get_uniform_block(self->shader, name);
215
216 if (uniform == -1) {
217 PyErr_Format(PyExc_ValueError, "GPUShader.get_uniform_block: uniform %.32s not found", name);
218 return nullptr;
219 }
220
221 return PyLong_FromLong(uniform);
222}
223
224static bool pygpu_shader_uniform_vector_impl(PyObject *args,
225 int elem_size,
226 int *r_location,
227 int *r_length,
228 int *r_count,
229 Py_buffer *r_pybuffer)
230{
231 PyObject *buffer;
232
233 *r_count = 1;
234 if (!PyArg_ParseTuple(
235 args, "iOi|i:GPUShader.uniform_vector_*", r_location, &buffer, r_length, r_count))
236 {
237 return false;
238 }
239
240 if (PyObject_GetBuffer(buffer, r_pybuffer, PyBUF_SIMPLE) == -1) {
241 /* PyObject_GetBuffer raise a PyExc_BufferError */
242 return false;
243 }
244
245 if (r_pybuffer->len < (*r_length * *r_count * elem_size)) {
246 PyErr_SetString(PyExc_OverflowError,
247 "GPUShader.uniform_vector_*: buffer size smaller than required.");
248 return false;
249 }
250
251 return true;
252}
253
255 /* Wrap. */
256 pygpu_shader_uniform_vector_float_doc,
257 ".. method:: uniform_vector_float(location, buffer, length, count)\n"
258 "\n"
259 " Set the buffer to fill the uniform.\n"
260 "\n"
261 " :arg location: Location of the uniform variable to be modified.\n"
262 " :type location: int\n"
263 " :arg buffer: The data that should be set. Can support the buffer protocol.\n"
264 " :type buffer: Sequence[float]\n"
265 " :arg length: Size of the uniform data type:\n"
266 "\n"
267 " - 1: float\n"
268 " - 2: vec2 or float[2]\n"
269 " - 3: vec3 or float[3]\n"
270 " - 4: vec4 or float[4]\n"
271 " - 9: mat3\n"
272 " - 16: mat4\n"
273 " :type length: int\n"
274 " :arg count: Specifies the number of elements, vector or matrices that are to "
275 "be modified.\n"
276 " :type count: int\n");
277static PyObject *pygpu_shader_uniform_vector_float(BPyGPUShader *self, PyObject *args)
278{
279 int location, length, count;
280
281 Py_buffer pybuffer;
282
284 args, sizeof(float), &location, &length, &count, &pybuffer))
285 {
286 return nullptr;
287 }
288
289 GPU_shader_bind(self->shader);
291 self->shader, location, length, count, static_cast<const float *>(pybuffer.buf));
292
293 PyBuffer_Release(&pybuffer);
294
295 Py_RETURN_NONE;
296}
297
299 /* Wrap. */
300 pygpu_shader_uniform_vector_int_doc,
301 ".. method:: uniform_vector_int(location, buffer, length, count)\n"
302 "\n"
303 " See GPUShader.uniform_vector_float(...) description.\n");
304static PyObject *pygpu_shader_uniform_vector_int(BPyGPUShader *self, PyObject *args)
305{
306 int location, length, count;
307
308 Py_buffer pybuffer;
309
310 if (!pygpu_shader_uniform_vector_impl(args, sizeof(int), &location, &length, &count, &pybuffer))
311 {
312 return nullptr;
313 }
314
315 GPU_shader_bind(self->shader);
317 self->shader, location, length, count, static_cast<const int *>(pybuffer.buf));
318
319 PyBuffer_Release(&pybuffer);
320
321 Py_RETURN_NONE;
322}
323
325 /* Wrap. */
326 pygpu_shader_uniform_bool_doc,
327 ".. method:: uniform_bool(name, value)\n"
328 "\n"
329 " Specify the value of a uniform variable for the current program object.\n"
330 "\n"
331 " :arg name: Name of the uniform variable whose value is to be changed.\n"
332 " :type name: str\n"
333 " :arg value: Value that will be used to update the specified uniform variable.\n"
334 " :type value: bool | Sequence[bool]\n");
335static PyObject *pygpu_shader_uniform_bool(BPyGPUShader *self, PyObject *args)
336{
337 const char *error_prefix = "GPUShader.uniform_bool";
338
339 struct {
340 const char *id;
341 PyObject *seq;
342 } params;
343
344 if (!PyArg_ParseTuple(args, "sO:GPUShader.uniform_bool", &params.id, &params.seq)) {
345 return nullptr;
346 }
347
348 int values[4];
349 int length;
350 int ret = -1;
351 if (PySequence_Check(params.seq)) {
352 PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
353 if (seq_fast == nullptr) {
354 PyErr_Format(PyExc_TypeError,
355 "%s: expected a sequence, got %s",
356 error_prefix,
357 Py_TYPE(params.seq)->tp_name);
358 }
359 else {
360 length = PySequence_Fast_GET_SIZE(seq_fast);
361 if (length == 0 || length > 4) {
362 PyErr_Format(PyExc_TypeError,
363 "%s: invalid sequence length. expected 1..4, got %d",
364 error_prefix,
365 length);
366 }
367 else {
369 values, sizeof(*values), seq_fast, length, &PyLong_Type, error_prefix);
370 }
371 Py_DECREF(seq_fast);
372 }
373 }
374 else if (((values[0] = int(PyLong_AsLong(params.seq))) != -1) && ELEM(values[0], 0, 1)) {
375 length = 1;
376 ret = 0;
377 }
378 else {
379 PyErr_Format(
380 PyExc_ValueError, "expected a bool or sequence, got %s", Py_TYPE(params.seq)->tp_name);
381 }
382
383 if (ret == -1) {
384 return nullptr;
385 }
386
387 const int location = pygpu_shader_uniform_location_get(self->shader, params.id, error_prefix);
388
389 if (location == -1) {
390 return nullptr;
391 }
392
393 GPU_shader_bind(self->shader);
394 GPU_shader_uniform_int_ex(self->shader, location, length, 1, values);
395
396 Py_RETURN_NONE;
397}
398
400 /* Wrap. */
401 pygpu_shader_uniform_float_doc,
402 ".. method:: uniform_float(name, value)\n"
403 "\n"
404 " Specify the value of a uniform variable for the current program object.\n"
405 "\n"
406 " :arg name: Name of the uniform variable whose value is to be changed.\n"
407 " :type name: str\n"
408 " :arg value: Value that will be used to update the specified uniform variable.\n"
409 " :type value: float | Sequence[float]\n");
410static PyObject *pygpu_shader_uniform_float(BPyGPUShader *self, PyObject *args)
411{
412 const char *error_prefix = "GPUShader.uniform_float";
413
414 struct {
415 const char *id;
416 PyObject *seq;
417 } params;
418
419 if (!PyArg_ParseTuple(args, "sO:GPUShader.uniform_float", &params.id, &params.seq)) {
420 return nullptr;
421 }
422
423 float values[16];
424 int length;
425
426 if (PyFloat_Check(params.seq)) {
427 values[0] = float(PyFloat_AsDouble(params.seq));
428 length = 1;
429 }
430 else if (PyLong_Check(params.seq)) {
431 values[0] = float(PyLong_AsDouble(params.seq));
432 length = 1;
433 }
434 else if (MatrixObject_Check(params.seq)) {
435 MatrixObject *mat = (MatrixObject *)params.seq;
436 if (BaseMath_ReadCallback(mat) == -1) {
437 return nullptr;
438 }
439 if ((mat->row_num != mat->col_num) || !ELEM(mat->row_num, 3, 4)) {
440 PyErr_SetString(PyExc_ValueError, "Expected 3x3 or 4x4 matrix");
441 return nullptr;
442 }
443 length = mat->row_num * mat->col_num;
444 memcpy(values, mat->matrix, sizeof(float) * length);
445 }
446 else {
447 length = mathutils_array_parse(values, 2, 16, params.seq, "");
448 if (length == -1) {
449 return nullptr;
450 }
451 }
452
453 if (!ELEM(length, 1, 2, 3, 4, 9, 16)) {
454 PyErr_SetString(PyExc_TypeError,
455 "Expected a single float or a sequence of floats of length 1..4, 9 or 16.");
456 return nullptr;
457 }
458
459 const int location = pygpu_shader_uniform_location_get(self->shader, params.id, error_prefix);
460
461 if (location == -1) {
462 return nullptr;
463 }
464
465 GPU_shader_bind(self->shader);
466 GPU_shader_uniform_float_ex(self->shader, location, length, 1, values);
467
468 Py_RETURN_NONE;
469}
470
472 /* Wrap. */
473 pygpu_shader_uniform_int_doc,
474 ".. method:: uniform_int(name, seq)\n"
475 "\n"
476 " Specify the value of a uniform variable for the current program object.\n"
477 "\n"
478 " :arg name: name of the uniform variable whose value is to be changed.\n"
479 " :type name: str\n"
480 " :arg seq: Value that will be used to update the specified uniform variable.\n"
481 " :type seq: Sequence[int]\n");
482static PyObject *pygpu_shader_uniform_int(BPyGPUShader *self, PyObject *args)
483{
484 const char *error_prefix = "GPUShader.uniform_int";
485
486 struct {
487 const char *id;
488 PyObject *seq;
489 } params;
490
491 if (!PyArg_ParseTuple(args, "sO:GPUShader.uniform_int", &params.id, &params.seq)) {
492 return nullptr;
493 }
494
495 int values[4];
496 int length;
497 int ret;
498
499 if (PyLong_Check(params.seq)) {
500 values[0] = PyC_Long_AsI32(params.seq);
501 length = 1;
502 ret = 0;
503 }
504 else {
505 PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
506 if (seq_fast == nullptr) {
507 PyErr_Format(PyExc_TypeError,
508 "%s: expected a sequence, got %s",
509 error_prefix,
510 Py_TYPE(params.seq)->tp_name);
511 ret = -1;
512 }
513 else {
514 length = PySequence_Fast_GET_SIZE(seq_fast);
515 if (length == 0 || length > 4) {
516 PyErr_Format(PyExc_TypeError,
517 "%s: invalid sequence length. expected 1..4, got %d",
518 error_prefix,
519 length);
520 ret = -1;
521 }
522 else {
524 values, sizeof(*values), seq_fast, length, &PyLong_Type, error_prefix);
525 }
526 Py_DECREF(seq_fast);
527 }
528 }
529 if (ret == -1) {
530 return nullptr;
531 }
532
533 const int location = pygpu_shader_uniform_location_get(self->shader, params.id, error_prefix);
534
535 if (location == -1) {
536 return nullptr;
537 }
538
539 GPU_shader_bind(self->shader);
540 GPU_shader_uniform_int_ex(self->shader, location, length, 1, values);
541
542 Py_RETURN_NONE;
543}
544
546 /* Wrap. */
547 pygpu_shader_uniform_sampler_doc,
548 ".. method:: uniform_sampler(name, texture)\n"
549 "\n"
550 " Specify the value of a texture uniform variable for the current GPUShader.\n"
551 "\n"
552 " :arg name: name of the uniform variable whose texture is to be specified.\n"
553 " :type name: str\n"
554 " :arg texture: Texture to attach.\n"
555 " :type texture: :class:`gpu.types.GPUTexture`\n");
556static PyObject *pygpu_shader_uniform_sampler(BPyGPUShader *self, PyObject *args)
557{
558 const char *name;
559 BPyGPUTexture *py_texture;
560 if (!PyArg_ParseTuple(
561 args, "sO!:GPUShader.uniform_sampler", &name, &BPyGPUTexture_Type, &py_texture))
562 {
563 return nullptr;
564 }
565
566 GPU_shader_bind(self->shader);
567 int slot = GPU_shader_get_sampler_binding(self->shader, name);
568 GPU_texture_bind(py_texture->tex, slot);
569 GPU_shader_uniform_1i(self->shader, name, slot);
570
571 Py_RETURN_NONE;
572}
573
575 /* Wrap. */
576 pygpu_shader_image_doc,
577 ".. method:: image(name, texture)\n"
578 "\n"
579 " Specify the value of an image variable for the current GPUShader.\n"
580 "\n"
581 " :arg name: Name of the image variable to which the texture is to be bound.\n"
582 " :type name: str\n"
583 " :arg texture: Texture to attach.\n"
584 " :type texture: :class:`gpu.types.GPUTexture`\n");
585static PyObject *pygpu_shader_image(BPyGPUShader *self, PyObject *args)
586{
587 const char *name;
588 BPyGPUTexture *py_texture;
589 if (!PyArg_ParseTuple(args, "sO!:GPUShader.image", &name, &BPyGPUTexture_Type, &py_texture)) {
590 return nullptr;
591 }
592
593 GPU_shader_bind(self->shader);
594 int image_unit = GPU_shader_get_sampler_binding(self->shader, name);
595 if (image_unit == -1) {
596 PyErr_Format(PyExc_ValueError, "Image '%s' not found in shader", name);
597 return nullptr;
598 }
599
600 GPU_texture_image_bind(py_texture->tex, image_unit);
601
602 Py_RETURN_NONE;
603}
604
606 /* Wrap. */
607 pygpu_shader_uniform_block_doc,
608 ".. method:: uniform_block(name, ubo)\n"
609 "\n"
610 " Specify the value of an uniform buffer object variable for the current GPUShader.\n"
611 "\n"
612 " :arg name: name of the uniform variable whose UBO is to be specified.\n"
613 " :type name: str\n"
614 " :arg ubo: Uniform Buffer to attach.\n"
615 " :type texture: :class:`gpu.types.GPUUniformBuf`\n");
616static PyObject *pygpu_shader_uniform_block(BPyGPUShader *self, PyObject *args)
617{
618 const char *name;
619 BPyGPUUniformBuf *py_ubo;
620 if (!PyArg_ParseTuple(
621 args, "sO!:GPUShader.uniform_block", &name, &BPyGPUUniformBuf_Type, &py_ubo))
622 {
623 return nullptr;
624 }
625
626 int binding = GPU_shader_get_ubo_binding(self->shader, name);
627 if (binding == -1) {
628 PyErr_SetString(
629 PyExc_BufferError,
630 "GPUShader.uniform_block: uniform block not found, make sure the name is correct");
631 return nullptr;
632 }
633
634 GPU_shader_bind(self->shader);
635 GPU_uniformbuf_bind(py_ubo->ubo, binding);
636
637 Py_RETURN_NONE;
638}
639
641 /* Wrap. */
642 pygpu_shader_attr_from_name_doc,
643 ".. method:: attr_from_name(name)\n"
644 "\n"
645 " Get attribute location by name.\n"
646 "\n"
647 " :arg name: The name of the attribute variable whose location is to be queried.\n"
648 " :type name: str\n"
649 " :return: The location of an attribute variable.\n"
650 " :rtype: int\n");
651static PyObject *pygpu_shader_attr_from_name(BPyGPUShader *self, PyObject *arg)
652{
653 const char *name = PyUnicode_AsUTF8(arg);
654 if (name == nullptr) {
655 return nullptr;
656 }
657
658 const int attr = GPU_shader_get_attribute(self->shader, name);
659
660 if (attr == -1) {
661 PyErr_Format(PyExc_ValueError, "GPUShader.attr_from_name: attribute %.32s not found", name);
662 return nullptr;
663 }
664
665 return PyLong_FromLong(attr);
666}
667
669 /* Wrap. */
670 pygpu_shader_format_calc_doc,
671 ".. method:: format_calc()\n"
672 "\n"
673 " Build a new format based on the attributes of the shader.\n"
674 "\n"
675 " :return: vertex attribute format for the shader\n"
676 " :rtype: :class:`gpu.types.GPUVertFormat`\n");
677static PyObject *pygpu_shader_format_calc(BPyGPUShader *self, PyObject * /*arg*/)
678{
680 GPU_vertformat_from_shader(&ret->fmt, self->shader);
681 return (PyObject *)ret;
682}
683
685 /* Wrap. */
686 pygpu_shader_attrs_info_get_doc,
687 ".. method:: attrs_info_get()\n"
688 "\n"
689 " Information about the attributes used in the Shader.\n"
690 "\n"
691 " :return: tuples containing information about the attributes in order (name, type)\n"
692 " :rtype: tuple[tuple[str, str | None], ...]\n");
693static PyObject *pygpu_shader_attrs_info_get(BPyGPUShader *self, PyObject * /*arg*/)
694{
695 uint attr_len = GPU_shader_get_attribute_len(self->shader);
696 int location_test = 0, attrs_added = 0;
697
698 PyObject *ret = PyTuple_New(attr_len);
699 while (attrs_added < attr_len) {
700 char name[256];
701 int type;
702 if (!GPU_shader_get_attribute_info(self->shader, location_test++, name, &type)) {
703 continue;
704 }
705 PyObject *py_type;
706 if (type != -1) {
707 py_type = PyUnicode_InternFromString(
709 }
710 else {
711 py_type = Py_None;
712 Py_INCREF(py_type);
713 }
714
715 PyObject *attr_info = PyTuple_New(2);
716 PyTuple_SET_ITEMS(attr_info, PyUnicode_FromString(name), py_type);
717 PyTuple_SetItem(ret, attrs_added, attr_info);
718 attrs_added++;
719 }
720 return ret;
721}
722
723#if (defined(__GNUC__) && !defined(__clang__))
724# pragma GCC diagnostic push
725# pragma GCC diagnostic ignored "-Wcast-function-type"
726#endif
727
728static PyMethodDef pygpu_shader__tp_methods[] = {
729 {"bind", (PyCFunction)pygpu_shader_bind, METH_NOARGS, pygpu_shader_bind_doc},
730 {"uniform_from_name",
732 METH_O,
733 pygpu_shader_uniform_from_name_doc},
734 {"uniform_block_from_name",
736 METH_O,
737 pygpu_shader_uniform_block_from_name_doc},
738 {"uniform_vector_float",
740 METH_VARARGS,
741 pygpu_shader_uniform_vector_float_doc},
742 {"uniform_vector_int",
744 METH_VARARGS,
745 pygpu_shader_uniform_vector_int_doc},
746 {"uniform_bool",
747 (PyCFunction)pygpu_shader_uniform_bool,
748 METH_VARARGS,
749 pygpu_shader_uniform_bool_doc},
750 {"uniform_float",
751 (PyCFunction)pygpu_shader_uniform_float,
752 METH_VARARGS,
753 pygpu_shader_uniform_float_doc},
754 {"uniform_int",
755 (PyCFunction)pygpu_shader_uniform_int,
756 METH_VARARGS,
757 pygpu_shader_uniform_int_doc},
758 {"uniform_sampler",
759 (PyCFunction)pygpu_shader_uniform_sampler,
760 METH_VARARGS,
761 pygpu_shader_uniform_sampler_doc},
762 {"image", (PyCFunction)pygpu_shader_image, METH_VARARGS, pygpu_shader_image_doc},
763 {"uniform_block",
764 (PyCFunction)pygpu_shader_uniform_block,
765 METH_VARARGS,
766 pygpu_shader_uniform_block_doc},
767 {"attr_from_name",
768 (PyCFunction)pygpu_shader_attr_from_name,
769 METH_O,
770 pygpu_shader_attr_from_name_doc},
771 {"format_calc",
772 (PyCFunction)pygpu_shader_format_calc,
773 METH_NOARGS,
774 pygpu_shader_format_calc_doc},
775 {"attrs_info_get",
776 (PyCFunction)pygpu_shader_attrs_info_get,
777 METH_NOARGS,
778 pygpu_shader_attrs_info_get_doc},
779 {nullptr, nullptr, 0, nullptr},
780};
781
782#if (defined(__GNUC__) && !defined(__clang__))
783# pragma GCC diagnostic pop
784#endif
785
787 /* Wrap. */
788 pygpu_shader_name_doc,
789 "The name of the shader object for debugging purposes (read-only).\n"
790 "\n"
791 ":type: str");
792static PyObject *pygpu_shader_name(BPyGPUShader *self, void * /*closure*/)
793{
794 return PyUnicode_FromString(GPU_shader_get_name(self->shader));
795}
796
798 /* Wrap. */
799 pygpu_shader_program_doc,
800 "The name of the program object for use by the OpenGL API (read-only).\n"
801 "\n"
802 ":type: int");
803static PyObject *pygpu_shader_program_get(BPyGPUShader *self, void * /*closure*/)
804{
805 return PyLong_FromLong(GPU_shader_get_program(self->shader));
806}
807
808static PyGetSetDef pygpu_shader__tp_getseters[] = {
809 {"program",
811 (setter) nullptr,
812 pygpu_shader_program_doc,
813 nullptr},
814 {"name", (getter)pygpu_shader_name, (setter) nullptr, pygpu_shader_name_doc, nullptr},
815 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
816};
817
819{
820 if (self->is_builtin == false) {
821 GPU_shader_free(self->shader);
822 }
823 Py_TYPE(self)->tp_free((PyObject *)self);
824}
825
827 /* Wrap. */
828 pygpu_shader__tp_doc,
829 ".. class:: GPUShader(vertexcode, fragcode, geocode=None, libcode=None, defines=None, "
830 "name='pyGPUShader')\n"
831 "\n"
832 " GPUShader combines multiple GLSL shaders into a program used for drawing.\n"
833 " It must contain at least a vertex and fragment shaders.\n"
834 "\n"
835 " The GLSL ``#version`` directive is automatically included at the top of shaders,\n"
836 " and set to 330. Some preprocessor directives are automatically added according to\n"
837 " the Operating System or availability: ``GPU_ATI``, ``GPU_NVIDIA`` and ``GPU_INTEL``.\n"
838 "\n"
839 " The following extensions are enabled by default if supported by the GPU:\n"
840 " ``GL_ARB_texture_gather``, ``GL_ARB_texture_cube_map_array``\n"
841 " and ``GL_ARB_shader_draw_parameters``.\n"
842 "\n"
843 " For drawing user interface elements and gizmos, use\n"
844 " ``fragOutput = blender_srgb_to_framebuffer_space(fragOutput)``\n"
845 " to transform the output sRGB colors to the frame-buffer color-space.\n"
846 "\n"
847 " :arg vertexcode: Vertex shader code.\n"
848 " :type vertexcode: str\n"
849 " :arg fragcode: Fragment shader code.\n"
850 " :type value: str\n"
851 " :arg geocode: Geometry shader code.\n"
852 " :type value: str\n"
853 " :arg libcode: Code with functions and presets to be shared between shaders.\n"
854 " :type value: str\n"
855 " :arg defines: Preprocessor directives.\n"
856 " :type value: str\n"
857 " :arg name: Name of shader code, for debugging purposes.\n"
858 " :type value: str\n");
859PyTypeObject BPyGPUShader_Type = {
860 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
861 /*tp_name*/ "GPUShader",
862 /*tp_basicsize*/ sizeof(BPyGPUShader),
863 /*tp_itemsize*/ 0,
864 /*tp_dealloc*/ (destructor)pygpu_shader__tp_dealloc,
865 /*tp_vectorcall_offset*/ 0,
866 /*tp_getattr*/ nullptr,
867 /*tp_setattr*/ nullptr,
868 /*tp_as_async*/ nullptr,
869 /*tp_repr*/ nullptr,
870 /*tp_as_number*/ nullptr,
871 /*tp_as_sequence*/ nullptr,
872 /*tp_as_mapping*/ nullptr,
873 /*tp_hash*/ nullptr,
874 /*tp_call*/ nullptr,
875 /*tp_str*/ nullptr,
876 /*tp_getattro*/ nullptr,
877 /*tp_setattro*/ nullptr,
878 /*tp_as_buffer*/ nullptr,
879 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
880 /*tp_doc*/ pygpu_shader__tp_doc,
881 /*tp_traverse*/ nullptr,
882 /*tp_clear*/ nullptr,
883 /*tp_richcompare*/ nullptr,
884 /*tp_weaklistoffset*/ 0,
885 /*tp_iter*/ nullptr,
886 /*tp_iternext*/ nullptr,
887 /*tp_methods*/ pygpu_shader__tp_methods,
888 /*tp_members*/ nullptr,
889 /*tp_getset*/ pygpu_shader__tp_getseters,
890 /*tp_base*/ nullptr,
891 /*tp_dict*/ nullptr,
892 /*tp_descr_get*/ nullptr,
893 /*tp_descr_set*/ nullptr,
894 /*tp_dictoffset*/ 0,
895 /*tp_init*/ nullptr,
896 /*tp_alloc*/ nullptr,
897 /*tp_new*/ pygpu_shader__tp_new,
898 /*tp_free*/ nullptr,
899 /*tp_is_gc*/ nullptr,
900 /*tp_bases*/ nullptr,
901 /*tp_mro*/ nullptr,
902 /*tp_cache*/ nullptr,
903 /*tp_subclasses*/ nullptr,
904 /*tp_weaklist*/ nullptr,
905 /*tp_del*/ nullptr,
906 /*tp_version_tag*/ 0,
907 /*tp_finalize*/ nullptr,
908 /*tp_vectorcall*/ nullptr,
909};
910
913/* -------------------------------------------------------------------- */
918 /* Wrap. */
919 pygpu_shader_unbind_doc,
920 ".. function:: unbind()\n"
921 "\n"
922 " Unbind the bound shader object.\n");
923static PyObject *pygpu_shader_unbind(BPyGPUShader * /*self*/)
924{
926 Py_RETURN_NONE;
927}
928
930 /* Wrap. */
931 pygpu_shader_from_builtin_doc,
932 ".. function:: from_builtin(shader_name, config='DEFAULT')\n"
933 "\n"
934 " Shaders that are embedded in the blender internal code (see :ref:`built-in-shaders`).\n"
935 " They all read the uniform ``mat4 ModelViewProjectionMatrix``,\n"
936 " which can be edited by the :mod:`gpu.matrix` module.\n"
937 "\n"
938 " You can also choose a shader configuration that uses clip_planes by setting the "
939 "``CLIPPED`` value to the config parameter. Note that in this case you also need to "
940 "manually set the value of ``mat4 ModelMatrix``.\n"
941 "\n"
942 " :arg shader_name: One of the builtin shader names.\n"
943 " :type shader_name: str\n"
944 " :arg config: One of these types of shader configuration:\n"
945 "\n"
946 " - ``DEFAULT``\n"
947 " - ``CLIPPED``\n"
948 " :type config: str\n"
949 " :return: Shader object corresponding to the given name.\n"
950 " :rtype: :class:`gpu.types.GPUShader`\n");
951static PyObject *pygpu_shader_from_builtin(PyObject * /*self*/, PyObject *args, PyObject *kwds)
952{
954
955 PyC_StringEnum pygpu_bultinshader = {pygpu_shader_builtin_items};
957
958 static const char *_keywords[] = {"shader_name", "config", nullptr};
959 static _PyArg_Parser _parser = {
961 "O&" /* `shader_name` */
962 "|$" /* Optional keyword only arguments. */
963 "O&" /* `config` */
964 ":from_builtin",
965 _keywords,
966 nullptr,
967 };
968 if (!_PyArg_ParseTupleAndKeywordsFast(args,
969 kwds,
970 &_parser,
972 &pygpu_bultinshader,
974 &pygpu_config))
975 {
976 return nullptr;
977 }
978
980 eGPUBuiltinShader(pygpu_bultinshader.value_found),
981 eGPUShaderConfig(pygpu_config.value_found));
982
983 return BPyGPUShader_CreatePyObject(shader, true);
984}
985
987 /* Wrap. */
988 pygpu_shader_create_from_info_doc,
989 ".. function:: create_from_info(shader_info)\n"
990 "\n"
991 " Create shader from a GPUShaderCreateInfo.\n"
992 "\n"
993 " :arg shader_info: GPUShaderCreateInfo\n"
994 " :type shader_info: :class:`bpy.types.GPUShaderCreateInfo`\n"
995 " :return: Shader object corresponding to the given name.\n"
996 " :rtype: :class:`gpu.types.GPUShader`\n");
998{
1000
1002 PyErr_Format(PyExc_TypeError, "Expected a GPUShaderCreateInfo, got %s", Py_TYPE(o)->tp_name);
1003 return nullptr;
1004 }
1005
1006 char error[128];
1008 PyErr_SetString(PyExc_Exception, error);
1009 return nullptr;
1010 }
1011
1013 if (!shader) {
1014 PyErr_SetString(PyExc_Exception, "Shader Compile Error, see console for more details");
1015 return nullptr;
1016 }
1017
1018 return BPyGPUShader_CreatePyObject(shader, false);
1019}
1020
1021#if (defined(__GNUC__) && !defined(__clang__))
1022# pragma GCC diagnostic push
1023# pragma GCC diagnostic ignored "-Wcast-function-type"
1024#endif
1025
1026static PyMethodDef pygpu_shader_module__tp_methods[] = {
1027 {"unbind", (PyCFunction)pygpu_shader_unbind, METH_NOARGS, pygpu_shader_unbind_doc},
1028 {"from_builtin",
1029 (PyCFunction)pygpu_shader_from_builtin,
1030 METH_VARARGS | METH_KEYWORDS,
1031 pygpu_shader_from_builtin_doc},
1032 {"create_from_info",
1033 (PyCFunction)pygpu_shader_create_from_info,
1034 METH_O,
1035 pygpu_shader_create_from_info_doc},
1036 {nullptr, nullptr, 0, nullptr},
1037};
1038
1039#if (defined(__GNUC__) && !defined(__clang__))
1040# pragma GCC diagnostic pop
1041#endif
1042
1044 /* Wrap. */
1045 pygpu_shader_module__tp_doc,
1046 "This module provides access to GPUShader internal functions.\n"
1047 "\n"
1048 ".. _built-in-shaders:\n"
1049 "\n"
1050 ".. rubric:: Built-in shaders\n"
1051 "\n"
1052 "All built-in shaders have the ``mat4 ModelViewProjectionMatrix`` uniform.\n"
1053 "\n"
1054 "Its value must be modified using the :class:`gpu.matrix` module.\n"
1056static PyModuleDef pygpu_shader_module_def = {
1057 /*m_base*/ PyModuleDef_HEAD_INIT,
1058 /*m_name*/ "gpu.shader",
1059 /*m_doc*/ pygpu_shader_module__tp_doc,
1060 /*m_size*/ 0,
1061 /*m_methods*/ pygpu_shader_module__tp_methods,
1062 /*m_slots*/ nullptr,
1063 /*m_traverse*/ nullptr,
1064 /*m_clear*/ nullptr,
1065 /*m_free*/ nullptr,
1066};
1067
1070/* -------------------------------------------------------------------- */
1074PyObject *BPyGPUShader_CreatePyObject(GPUShader *shader, bool is_builtin)
1075{
1077
1078 self = PyObject_New(BPyGPUShader, &BPyGPUShader_Type);
1079 self->shader = shader;
1080 self->is_builtin = is_builtin;
1081
1082 return (PyObject *)self;
1083}
1084
1086{
1087 PyObject *submodule;
1088
1089 submodule = PyModule_Create(&pygpu_shader_module_def);
1090
1091 return submodule;
1092}
1093
unsigned int uint
#define ELEM(...)
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
int GPU_shader_get_uniform(GPUShader *shader, const char *name)
bool GPU_shader_get_attribute_info(const GPUShader *shader, int attr_location, char r_name[256], int *r_type)
const char * GPU_shader_get_name(GPUShader *shader)
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
int GPU_shader_get_ubo_binding(GPUShader *shader, const char *name)
void GPU_shader_uniform_int_ex(GPUShader *shader, int location, int length, int array_size, const int *value)
GPUShader * GPU_shader_create_from_python(const char *vertcode, const char *fragcode, const char *geomcode, const char *libcode, const char *defines, const char *name)
unsigned int GPU_shader_get_attribute_len(const GPUShader *shader)
int GPU_shader_get_attribute(const GPUShader *shader, const char *name)
void GPU_shader_uniform_float_ex(GPUShader *shader, int location, int length, int array_size, const float *value)
int GPU_shader_get_program(GPUShader *shader)
void GPU_shader_bind(GPUShader *shader)
GPUShader * GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
void GPU_shader_free(GPUShader *shader)
bool GPU_shader_create_info_check_error(const GPUShaderCreateInfo *_info, char r_error[128])
void GPU_shader_unbind()
@ GPU_SHADER_CFG_DEFAULT
@ GPU_SHADER_CFG_CLIPPED
GPUShader * GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, eGPUShaderConfig sh_cfg)
eGPUBuiltinShader
@ GPU_SHADER_3D_SMOOTH_COLOR
@ GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR
@ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_3D_FLAT_COLOR
@ GPU_SHADER_3D_IMAGE
@ GPU_SHADER_3D_POLYLINE_FLAT_COLOR
@ GPU_SHADER_3D_IMAGE_COLOR
void GPU_texture_bind(GPUTexture *texture, int unit)
void GPU_texture_image_bind(GPUTexture *texture, int unit)
void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot)
void GPU_vertformat_from_shader(GPUVertFormat *format, const GPUShader *shader)
struct GPUShader GPUShader
PyObject * self
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
draw_view in_light_buf[] float
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition gpu_py.hh:18
#define PYDOC_BUILTIN_SHADER_DESCRIPTION
PyObject * BPyGPUShader_CreatePyObject(GPUShader *shader, bool is_builtin)
static const PyC_StringEnumItems pygpu_shader_builtin_items[]
static PyMethodDef pygpu_shader__tp_methods[]
static PyObject * pygpu_shader_unbind(BPyGPUShader *)
static PyObject * pygpu_shader_uniform_block(BPyGPUShader *self, PyObject *args)
static PyObject * pygpu_shader_uniform_vector_int(BPyGPUShader *self, PyObject *args)
static PyObject * pygpu_shader_program_get(BPyGPUShader *self, void *)
static PyObject * pygpu_shader_uniform_from_name(BPyGPUShader *self, PyObject *arg)
static PyObject * pygpu_shader_uniform_int(BPyGPUShader *self, PyObject *args)
static PyObject * pygpu_shader_create_from_info(BPyGPUShader *, BPyGPUShaderCreateInfo *o)
static PyObject * pygpu_shader_name(BPyGPUShader *self, void *)
PyTypeObject BPyGPUShader_Type
static PyObject * pygpu_shader_bind(BPyGPUShader *self)
static bool pygpu_shader_uniform_vector_impl(PyObject *args, int elem_size, int *r_location, int *r_length, int *r_count, Py_buffer *r_pybuffer)
PyObject * bpygpu_shader_init()
static PyObject * pygpu_shader_uniform_bool(BPyGPUShader *self, PyObject *args)
static PyObject * pygpu_shader_image(BPyGPUShader *self, PyObject *args)
static const PyC_StringEnumItems pygpu_shader_config_items[]
static PyObject * pygpu_shader__tp_new(PyTypeObject *, PyObject *args, PyObject *kwds)
static void pygpu_shader__tp_dealloc(BPyGPUShader *self)
static PyObject * pygpu_shader_from_builtin(PyObject *, PyObject *args, PyObject *kwds)
static PyObject * pygpu_shader_attr_from_name(BPyGPUShader *self, PyObject *arg)
static PyObject * pygpu_shader_format_calc(BPyGPUShader *self, PyObject *)
static PyObject * pygpu_shader_uniform_sampler(BPyGPUShader *self, PyObject *args)
static PyMethodDef pygpu_shader_module__tp_methods[]
static PyObject * pygpu_shader_uniform_float(BPyGPUShader *self, PyObject *args)
static PyObject * pygpu_shader_uniform_vector_float(BPyGPUShader *self, PyObject *args)
static PyObject * pygpu_shader_uniform_block_from_name(BPyGPUShader *self, PyObject *arg)
static PyObject * pygpu_shader_attrs_info_get(BPyGPUShader *self, PyObject *)
static PyModuleDef pygpu_shader_module_def
PyDoc_STRVAR(pygpu_shader_bind_doc, ".. method:: bind()\n" "\n" " Bind the shader object. Required to be able to change uniforms of this shader.\n")
static PyGetSetDef pygpu_shader__tp_getseters[]
static int pygpu_shader_uniform_location_get(GPUShader *shader, const char *name, const char *error_prefix)
const struct PyC_StringEnumItems pygpu_attrtype_items[]
struct BPyGPUShader BPyGPUShader
#define BPyGPUShaderCreateInfo_Check(v)
PyTypeObject BPyGPUTexture_Type
PyTypeObject BPyGPUUniformBuf_Type
PyObject * BPyGPUVertFormat_CreatePyObject(GPUVertFormat *fmt)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
int count
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition mathutils.cc:97
#define BaseMath_ReadCallback(_self)
Definition mathutils.hh:125
#define MatrixObject_Check(v)
static void error(const char *str)
int PyC_ParseStringEnum(PyObject *o, void *p)
const char * PyC_StringEnum_FindIDFromValue(const PyC_StringEnumItems *items, const int 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)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
header-only utilities
#define PyTuple_SET_ITEMS(op_arg,...)
return ret
PyObject_VAR_HEAD GPUShaderCreateInfo * info
PyObject_HEAD GPUTexture * tex
PyObject_HEAD GPUUniformBuf * ubo