2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * ***** END GPL LICENSE BLOCK *****
21 /** \file blender/python/gpu/gpu_py_shader.c
24 * - Use ``bpygpu_`` for local API.
25 * - Use ``BPyGPU`` for public API.
30 #include "BLI_utildefines.h"
32 #include "GPU_shader.h"
33 #include "GPU_shader_interface.h"
35 #include "../generic/py_capi_utils.h"
36 #include "../generic/python_utildefines.h"
37 #include "../mathutils/mathutils.h"
39 #include "gpu_py_api.h"
40 #include "gpu_py_shader.h" /* own include */
41 #include "gpu_py_vertex_format.h"
44 /* -------------------------------------------------------------------- */
46 /** \name Enum Conversion.
49 static int bpygpu_ParseBultinShaderEnum(PyObject *o, void *p)
51 Py_ssize_t mode_id_len;
52 const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len);
53 if (mode_id == NULL) {
54 PyErr_Format(PyExc_ValueError,
55 "expected a string, got %s",
59 #define MATCH_ID(id) \
60 if (mode_id_len == (Py_ssize_t)strlen(STRINGIFY(id))) { \
61 if (STREQ(mode_id, STRINGIFY(id))) { \
62 mode = GPU_SHADER_##id; \
67 GPUBuiltinShader mode;
68 MATCH_ID(2D_UNIFORM_COLOR);
69 MATCH_ID(2D_FLAT_COLOR);
70 MATCH_ID(2D_SMOOTH_COLOR);
72 MATCH_ID(3D_UNIFORM_COLOR);
73 MATCH_ID(3D_FLAT_COLOR);
74 MATCH_ID(3D_SMOOTH_COLOR);
77 PyErr_Format(PyExc_ValueError,
78 "unknown type literal: '%s'",
83 (*(GPUBuiltinShader *)p) = mode;
87 static int bpygpu_uniform_location_get(GPUShader *shader, const char *name, const char *error_prefix)
89 int uniform = GPU_shader_get_uniform(shader, name);
92 PyErr_Format(PyExc_ValueError, "%s: uniform %.32s %.32s not found", error_prefix, name);
101 /* -------------------------------------------------------------------- */
103 /** \name Shader Type
106 static PyObject *bpygpu_shader_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
108 BPYGPU_IS_INIT_OR_ERROR_OBJ;
111 const char *vertexcode;
112 const char *fragcode;
118 static const char *_keywords[] = {
119 "vertexcode", "fragcode", "geocode",
120 "libcode", "defines", NULL};
122 static _PyArg_Parser _parser = {"ss|$sss:GPUShader.__new__", _keywords, 0};
123 if (!_PyArg_ParseTupleAndKeywordsFast(
124 args, kwds, &_parser,
125 ¶ms.vertexcode, ¶ms.fragcode, ¶ms.geocode,
126 ¶ms.libcode, ¶ms.defines))
131 GPUShader *shader = GPU_shader_create(
139 if (shader == NULL) {
140 PyErr_SetString(PyExc_Exception,
141 "Shader Compile Error, see console for more details");
145 return BPyGPUShader_CreatePyObject(shader, false);
148 PyDoc_STRVAR(bpygpu_shader_bind_doc,
149 ".. method:: bind()\n"
151 " Bind the shader object. Required to be able to change uniforms of this shader.\n"
153 static PyObject *bpygpu_shader_bind(BPyGPUShader *self)
155 GPU_shader_bind(self->shader);
159 PyDoc_STRVAR(bpygpu_shader_uniform_from_name_doc,
160 ".. method:: uniform_from_name(name)\n"
162 " Get uniform location by name.\n"
164 " :param name: Name of the uniform variable whose location is to be queried.\n"
165 " :type name: `str`\n"
166 " :return: Location of the uniform variable.\n"
169 static PyObject *bpygpu_shader_uniform_from_name(
170 BPyGPUShader *self, PyObject *arg)
172 const char *name = PyUnicode_AsUTF8(arg);
177 int uniform = bpygpu_uniform_location_get(
178 self->shader, name, "GPUShader.get_uniform");
184 return PyLong_FromLong(uniform);
187 PyDoc_STRVAR(bpygpu_shader_uniform_block_from_name_doc,
188 ".. method:: uniform_block_from_name(name)\n"
190 " Get uniform block location by name.\n"
192 " :param name: Name of the uniform block variable whose location is to be queried.\n"
193 " :type name: `str`\n"
194 " :return: The location of the uniform block variable.\n"
197 static PyObject *bpygpu_shader_uniform_block_from_name(
198 BPyGPUShader *self, PyObject *arg)
200 const char *name = PyUnicode_AsUTF8(arg);
205 int uniform = GPU_shader_get_uniform_block(self->shader, name);
208 PyErr_Format(PyExc_ValueError,
209 "GPUShader.get_uniform_block: uniform %.32s not found", name);
213 return PyLong_FromLong(uniform);
216 static bool bpygpu_shader_uniform_vector_imp(
217 PyObject *args, int elem_size,
218 int *r_location, int *r_length, int *r_count, Py_buffer *r_pybuffer)
223 if (!PyArg_ParseTuple(
224 args, "iOi|i:GPUShader.uniform_vector_*",
225 r_location, &buffer, r_length, r_count))
230 if (PyObject_GetBuffer(buffer, r_pybuffer, PyBUF_SIMPLE) == -1) {
231 /* PyObject_GetBuffer raise a PyExc_BufferError */
235 if (r_pybuffer->len != (*r_length * *r_count * elem_size)) {
238 "GPUShader.uniform_vector_*: buffer size does not match.");
245 PyDoc_STRVAR(bpygpu_shader_uniform_vector_float_doc,
246 ".. method:: uniform_vector_float(location, buffer, length, count)\n"
248 " Set the buffer to fill the uniform.\n"
250 " :param location: Location of the uniform variable to be modified.\n"
251 " :type location: int\n"
252 " :param buffer: The data that should be set. Can support the buffer protocol.\n"
253 " :type buffer: sequence of floats\n"
254 " :param length: Size of the uniform data type:\n"
257 " - 2: vec2 or float[2]\n"
258 " - 3: vec3 or float[3]\n"
259 " - 4: vec4 or float[4]\n"
263 " :type length: int\n"
264 " :param count: Specifies the number of elements, vector or matrices that are to be modified.\n"
265 " :type count: int\n"
267 static PyObject *bpygpu_shader_uniform_vector_float(
268 BPyGPUShader *self, PyObject *args)
270 int location, length, count;
274 if (!bpygpu_shader_uniform_vector_imp(
276 &location, &length, &count, &pybuffer))
281 GPU_shader_uniform_vector(
282 self->shader, location, length,
283 count, pybuffer.buf);
285 PyBuffer_Release(&pybuffer);
290 PyDoc_STRVAR(bpygpu_shader_uniform_vector_int_doc,
291 ".. method:: uniform_vector_int(location, buffer, length, count)\n"
293 " See GPUShader.uniform_vector_float(...) description.\n"
295 static PyObject *bpygpu_shader_uniform_vector_int(
296 BPyGPUShader *self, PyObject *args)
298 int location, length, count;
302 if (!bpygpu_shader_uniform_vector_imp(
304 &location, &length, &count, &pybuffer))
309 GPU_shader_uniform_vector_int(
310 self->shader, location, length,
311 count, pybuffer.buf);
313 PyBuffer_Release(&pybuffer);
318 PyDoc_STRVAR(bpygpu_shader_uniform_bool_doc,
319 ".. method:: uniform_bool(name, seq)\n"
321 " Specify the value of a uniform variable for the current program object.\n"
323 " :param name: Name of the uniform variable whose value is to be changed.\n"
325 " :param seq: Value that will be used to update the specified uniform variable.\n"
326 " :type seq: sequence of bools\n"
328 static PyObject *bpygpu_shader_uniform_bool(
329 BPyGPUShader *self, PyObject *args)
331 const char *error_prefix = "GPUShader.uniform_bool";
338 if (!PyArg_ParseTuple(
339 args, "sO:GPUShader.uniform_bool",
340 ¶ms.id, ¶ms.seq))
349 PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
350 if (seq_fast == NULL) {
351 PyErr_Format(PyExc_TypeError,
352 "%s: expected a sequence, got %s",
353 error_prefix, Py_TYPE(params.seq)->tp_name);
357 length = PySequence_Fast_GET_SIZE(seq_fast);
358 if (length == 0 || length > 4) {
359 PyErr_Format(PyExc_TypeError,
360 "%s: invalid sequence length. expected 1..4, got %d",
361 error_prefix, length);
365 ret = PyC_AsArray_FAST(
366 values, seq_fast, length, &PyLong_Type,
367 false, error_prefix);
376 const int location = bpygpu_uniform_location_get(
377 self->shader, params.id, error_prefix);
379 if (location == -1) {
383 GPU_shader_uniform_vector_int(self->shader, location, length, 1, values);
388 PyDoc_STRVAR(bpygpu_shader_uniform_float_doc,
389 ".. method:: uniform_float(name, value)\n"
391 " Specify the value of a uniform variable for the current program object.\n"
393 " :param name: Name of the uniform variable whose value is to be changed.\n"
395 " :param value: Value that will be used to update the specified uniform variable.\n"
396 " :type value: single number or sequence of numbers\n"
398 static PyObject *bpygpu_shader_uniform_float(
399 BPyGPUShader *self, PyObject *args)
401 const char *error_prefix = "GPUShader.uniform_float";
408 if (!PyArg_ParseTuple(
409 args, "sO:GPUShader.uniform_float",
410 ¶ms.id, ¶ms.seq))
418 if (PyFloat_Check(params.seq)) {
419 values[0] = (float)PyFloat_AsDouble(params.seq);
422 else if (PyLong_Check(params.seq)) {
423 values[0] = (float)PyLong_AsDouble(params.seq);
426 else if (MatrixObject_Check(params.seq)) {
427 MatrixObject *mat = (MatrixObject *)params.seq;
428 if (BaseMath_ReadCallback(mat) == -1) {
431 if ((mat->num_row != mat->num_col) || !ELEM(mat->num_row, 3, 4)) {
432 PyErr_SetString(PyExc_ValueError,
433 "Expected 3x3 or 4x4 matrix");
436 length = mat->num_row * mat->num_col;
437 memcpy(values, mat->matrix, sizeof(float) * length);
440 length = mathutils_array_parse(values, 2, 16, params.seq, "");
446 if (!ELEM(length, 1, 2, 3, 4, 9, 16)) {
447 PyErr_SetString(PyExc_TypeError,
448 "Expected a single float or a sequence of floats of length 1..4, 9 or 16.");
452 const int location = bpygpu_uniform_location_get(
453 self->shader, params.id, error_prefix);
455 if (location == -1) {
459 GPU_shader_uniform_vector(self->shader, location, length, 1, values);
464 PyDoc_STRVAR(bpygpu_shader_uniform_int_doc,
465 ".. method:: uniform_int(name, seq)\n"
467 " Specify the value of a uniform variable for the current program object.\n"
469 " :param name: name of the uniform variable whose value is to be changed.\n"
471 " :param seq: Value that will be used to update the specified uniform variable.\n"
472 " :type seq: sequence of numbers\n"
474 static PyObject *bpygpu_shader_uniform_int(
475 BPyGPUShader *self, PyObject *args)
477 const char *error_prefix = "GPUShader.uniform_int";
484 if (!PyArg_ParseTuple(
485 args, "sO:GPUShader.uniform_int",
486 ¶ms.id, ¶ms.seq))
495 if (PyLong_Check(params.seq)) {
496 values[0] = PyC_Long_AsI32(params.seq);
501 PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
502 if (seq_fast == NULL) {
503 PyErr_Format(PyExc_TypeError,
504 "%s: expected a sequence, got %s",
505 error_prefix, Py_TYPE(params.seq)->tp_name);
509 length = PySequence_Fast_GET_SIZE(seq_fast);
510 if (length == 0 || length > 4) {
511 PyErr_Format(PyExc_TypeError,
512 "%s: invalid sequence length. expected 1..4, got %d",
513 error_prefix, length);
517 ret = PyC_AsArray_FAST(
518 values, seq_fast, length, &PyLong_Type,
519 false, error_prefix);
528 const int location = bpygpu_uniform_location_get(
529 self->shader, params.id, error_prefix);
531 if (location == -1) {
535 GPU_shader_uniform_vector_int(self->shader, location, length, 1, values);
540 PyDoc_STRVAR(bpygpu_shader_attr_from_name_doc,
541 ".. method:: attr_from_name(name)\n"
543 " Get attribute location by name.\n"
545 " :param name: The name of the attribute variable whose location is to be queried.\n"
547 " :return: The location of an attribute variable.\n"
550 static PyObject *bpygpu_shader_attr_from_name(
551 BPyGPUShader *self, PyObject *arg)
553 const char *name = PyUnicode_AsUTF8(arg);
558 int attr = GPU_shader_get_attribute(self->shader, name);
561 PyErr_Format(PyExc_ValueError,
562 "GPUShader.attr_from_name: attribute %.32s not found", name);
566 return PyLong_FromLong(attr);
569 PyDoc_STRVAR(bpygpu_shader_calc_format_doc,
570 ".. method:: calc_format()\n"
572 " Build a new format based on the attributes of the shader.\n"
574 " :return: vertex attribute format for the shader\n"
575 " :rtype: GPUVertFormat\n"
577 static PyObject *bpygpu_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg))
579 BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL);
580 GPU_vertformat_from_interface(&ret->fmt, GPU_shader_get_interface(self->shader));
581 return (PyObject *)ret;
584 static struct PyMethodDef bpygpu_shader_methods[] = {
585 {"bind", (PyCFunction)bpygpu_shader_bind,
586 METH_NOARGS, bpygpu_shader_bind_doc},
587 {"uniform_from_name",
588 (PyCFunction)bpygpu_shader_uniform_from_name,
589 METH_O, bpygpu_shader_uniform_from_name_doc},
590 {"uniform_block_from_name",
591 (PyCFunction)bpygpu_shader_uniform_block_from_name,
592 METH_O, bpygpu_shader_uniform_block_from_name_doc},
593 {"uniform_vector_float",
594 (PyCFunction)bpygpu_shader_uniform_vector_float,
595 METH_VARARGS, bpygpu_shader_uniform_vector_float_doc},
596 {"uniform_vector_int",
597 (PyCFunction)bpygpu_shader_uniform_vector_int,
598 METH_VARARGS, bpygpu_shader_uniform_vector_int_doc},
600 (PyCFunction)bpygpu_shader_uniform_bool,
601 METH_VARARGS, bpygpu_shader_uniform_bool_doc},
603 (PyCFunction)bpygpu_shader_uniform_float,
604 METH_VARARGS, bpygpu_shader_uniform_float_doc},
606 (PyCFunction)bpygpu_shader_uniform_int,
607 METH_VARARGS, bpygpu_shader_uniform_int_doc},
609 (PyCFunction)bpygpu_shader_attr_from_name,
610 METH_O, bpygpu_shader_attr_from_name_doc},
612 (PyCFunction)bpygpu_shader_calc_format,
613 METH_NOARGS, bpygpu_shader_calc_format_doc},
614 {NULL, NULL, 0, NULL}
617 PyDoc_STRVAR(bpygpu_shader_program_doc,
618 "The name of the program object for use by the OpenGL API (read-only).\n\n:type: int"
620 static PyObject *bpygpu_shader_program_get(BPyGPUShader *self, void *UNUSED(closure))
622 return PyLong_FromLong(GPU_shader_get_program(self->shader));
625 static PyGetSetDef bpygpu_shader_getseters[] = {
627 (getter)bpygpu_shader_program_get, (setter)NULL,
628 bpygpu_shader_program_doc, NULL},
629 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
633 static void bpygpu_shader_dealloc(BPyGPUShader *self)
635 if (self->is_builtin == false) {
636 GPU_shader_free(self->shader);
638 Py_TYPE(self)->tp_free((PyObject *)self);
642 PyDoc_STRVAR(bpygpu_shader_doc,
643 ".. class:: GPUShader(vertexcode, fragcode, geocode=None, libcode=None, defines=None)\n"
645 " GPUShader combines multiple GLSL shaders into a program used for drawing.\n"
646 " It must contain a vertex and fragment shaders, with an optional geometry shader.\n"
648 " The GLSL #version directive is automatically included at the top of shaders, and set to 330.\n"
649 " Some preprocessor directives are automatically added according to the Operating System or availability:\n"
650 " ``GPU_ATI``, ``GPU_NVIDIA`` and ``GPU_INTEL``.\n"
652 " The following extensions are enabled by default if supported by the GPU:\n"
653 " ``GL_ARB_texture_gather`` and ``GL_ARB_texture_query_lod``.\n"
655 " To debug shaders, use the --debug-gpu-shaders command line option"
656 " to see full GLSL shader compilation and linking errors.\n"
658 " :param vertexcode: Vertex shader code.\n"
659 " :type vertexcode: str\n"
660 " :param fragcode: Fragment shader code.\n"
661 " :type value: str\n"
662 " :param geocode: Geometry shader code.\n"
663 " :type value: str\n"
664 " :param libcode: Code with functions and presets to be shared between shaders.\n"
665 " :type value: str\n"
666 " :param defines: Preprocessor directives.\n"
667 " :type value: str\n"
669 PyTypeObject BPyGPUShader_Type = {
670 PyVarObject_HEAD_INIT(NULL, 0)
671 .tp_name = "GPUShader",
672 .tp_basicsize = sizeof(BPyGPUShader),
673 .tp_dealloc = (destructor)bpygpu_shader_dealloc,
674 .tp_flags = Py_TPFLAGS_DEFAULT,
675 .tp_doc = bpygpu_shader_doc,
676 .tp_methods = bpygpu_shader_methods,
677 .tp_getset = bpygpu_shader_getseters,
678 .tp_new = bpygpu_shader_new,
684 /* -------------------------------------------------------------------- */
686 /** \name gpu.shader Module API
689 PyDoc_STRVAR(bpygpu_shader_unbind_doc,
690 ".. function:: unbind()\n"
692 " Unbind the bound shader object.\n"
694 static PyObject *bpygpu_shader_unbind(BPyGPUShader *UNUSED(self))
700 PyDoc_STRVAR(bpygpu_shader_from_builtin_doc,
701 ".. function:: from_builtin(shader_name)\n"
703 " Shaders that are embedded in the blender internal code.\n"
704 " They all read the uniform 'mat4 ModelViewProjectionMatrix', which can be edited by the 'gpu.matrix' module.\n"
705 " For more details, you can check the shader code with the function 'gpu.shader.code_from_builtin';\n"
707 " :param shader_name: One of these builtin shader names: {\n"
708 " '2D_UNIFORM_COLOR',\n"
709 " '2D_FLAT_COLOR',\n"
710 " '2D_SMOOTH_COLOR',\n"
712 " '3D_UNIFORM_COLOR',\n"
713 " '3D_FLAT_COLOR',\n"
714 " '3D_SMOOTH_COLOR'}\n"
715 " :type shader_name: str\n"
716 " :return: Shader object corresponding to the given name.\n"
717 " :rtype: :class:`bpy.types.GPUShader`\n"
719 static PyObject *bpygpu_shader_from_builtin(PyObject *UNUSED(self), PyObject *arg)
721 BPYGPU_IS_INIT_OR_ERROR_OBJ;
723 GPUBuiltinShader shader_id;
725 if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) {
729 GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
731 return BPyGPUShader_CreatePyObject(shader, true);
734 PyDoc_STRVAR(bpygpu_shader_code_from_builtin_doc,
735 ".. function:: code_from_builtin(shader_name)\n"
737 " Exposes the internal shader code for query.\n"
739 " :param shader_name: One of these builtin shader names: {\n"
740 " '2D_UNIFORM_COLOR',\n"
741 " '2D_FLAT_COLOR',\n"
742 " '2D_SMOOTH_COLOR',\n"
744 " '3D_UNIFORM_COLOR',\n"
745 " '3D_FLAT_COLOR',\n"
746 " '3D_SMOOTH_COLOR'}\n"
747 " :type shader_name: str\n"
748 " :return: Vertex, fragment and geometry shader codes.\n"
751 static PyObject *bpygpu_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyObject *arg)
753 GPUBuiltinShader shader_id;
760 PyObject *item, *r_dict;
762 if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) {
766 GPU_shader_get_builtin_shader_code(
767 shader_id, &vert, &frag, &geom, &defines);
769 r_dict = PyDict_New();
771 PyDict_SetItemString(r_dict, "vertex_shader", item = PyUnicode_FromString(vert));
774 PyDict_SetItemString(r_dict, "fragment_shader", item = PyUnicode_FromString(frag));
778 PyDict_SetItemString(r_dict, "geometry_shader", item = PyUnicode_FromString(geom));
782 PyDict_SetItemString(r_dict, "defines", item = PyUnicode_FromString(defines));
788 static struct PyMethodDef bpygpu_shader_module_methods[] = {
790 (PyCFunction)bpygpu_shader_unbind,
791 METH_NOARGS, bpygpu_shader_unbind_doc},
793 (PyCFunction)bpygpu_shader_from_builtin,
794 METH_O, bpygpu_shader_from_builtin_doc},
795 {"code_from_builtin",
796 (PyCFunction)bpygpu_shader_code_from_builtin,
797 METH_O, bpygpu_shader_code_from_builtin_doc},
798 {NULL, NULL, 0, NULL}
801 PyDoc_STRVAR(bpygpu_shader_module_doc,
802 "This module provides access to GPUShader internal functions."
804 static PyModuleDef BPyGPU_shader_module_def = {
805 PyModuleDef_HEAD_INIT,
806 .m_name = "gpu.shader",
807 .m_doc = bpygpu_shader_module_doc,
808 .m_methods = bpygpu_shader_module_methods,
814 /* -------------------------------------------------------------------- */
819 PyObject *BPyGPUShader_CreatePyObject(GPUShader *shader, bool is_builtin)
823 self = PyObject_New(BPyGPUShader, &BPyGPUShader_Type);
824 self->shader = shader;
825 self->is_builtin = is_builtin;
827 return (PyObject *)self;
830 PyObject *BPyInit_gpu_shader(void)
834 submodule = PyModule_Create(&BPyGPU_shader_module_def);