Blender  V3.3
gpu_py_shader_create_info.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
10 #include <Python.h>
11 
12 #include "BLI_utildefines.h"
13 
14 #include "GPU_shader.h"
16 
17 #include "../generic/py_capi_utils.h"
18 
19 #include "gpu_py_shader.h" /* own include */
20 
21 //#define USE_PYGPU_SHADER_INFO_IMAGE_METHOD
22 
29 
30 #ifdef USE_PYGPU_SHADER_INFO_IMAGE_METHOD
32 
33 # define PYDOC_QUALIFIERS \
34  " - ``NO_RESTRICT``\n" \
35  " - ``READ``\n" \
36  " - ``WRITE``\n"
37 static const struct PyC_FlagSet pygpu_qualifiers[] = {
38  {(int)Qualifier::NO_RESTRICT, "NO_RESTRICT"},
39  {(int)Qualifier::READ, "READ"},
40  {(int)Qualifier::WRITE, "WRITE"},
41  {0, nullptr},
42 };
43 #endif
44 
45 #define PYDOC_TYPE_LIST \
46  " - ``FLOAT``\n" \
47  " - ``VEC2``\n" \
48  " - ``VEC3``\n" \
49  " - ``VEC4``\n" \
50  " - ``MAT3``\n" \
51  " - ``MAT4``\n" \
52  " - ``UINT``\n" \
53  " - ``UVEC2``\n" \
54  " - ``UVEC3``\n" \
55  " - ``UVEC4``\n" \
56  " - ``INT``\n" \
57  " - ``IVEC2``\n" \
58  " - ``IVEC3``\n" \
59  " - ``IVEC4``\n" \
60  " - ``BOOL``\n"
61 static const struct PyC_StringEnumItems pygpu_attrtype_items[] = {
62  {(int)Type::FLOAT, "FLOAT"},
63  {(int)Type::VEC2, "VEC2"},
64  {(int)Type::VEC3, "VEC3"},
65  {(int)Type::VEC4, "VEC4"},
66  {(int)Type::MAT3, "MAT3"},
67  {(int)Type::MAT4, "MAT4"},
68  {(int)Type::UINT, "UINT"},
69  {(int)Type::UVEC2, "UVEC2"},
70  {(int)Type::UVEC3, "UVEC3"},
71  {(int)Type::UVEC4, "UVEC4"},
72  {(int)Type::INT, "INT"},
73  {(int)Type::IVEC2, "IVEC2"},
74  {(int)Type::IVEC3, "IVEC3"},
75  {(int)Type::IVEC4, "IVEC4"},
76  {(int)Type::BOOL, "BOOL"},
77  {0, nullptr},
78 };
79 
80 #define PYDOC_IMAGE_TYPES \
81  " - ``FLOAT_BUFFER``\n" \
82  " - ``FLOAT_1D``\n" \
83  " - ``FLOAT_1D_ARRAY``\n" \
84  " - ``FLOAT_2D``\n" \
85  " - ``FLOAT_2D_ARRAY``\n" \
86  " - ``FLOAT_3D``\n" \
87  " - ``FLOAT_CUBE``\n" \
88  " - ``FLOAT_CUBE_ARRAY``\n" \
89  " - ``INT_BUFFER``\n" \
90  " - ``INT_1D``\n" \
91  " - ``INT_1D_ARRAY``\n" \
92  " - ``INT_2D``\n" \
93  " - ``INT_2D_ARRAY``\n" \
94  " - ``INT_3D``\n" \
95  " - ``INT_CUBE``\n" \
96  " - ``INT_CUBE_ARRAY``\n" \
97  " - ``UINT_BUFFER``\n" \
98  " - ``UINT_1D``\n" \
99  " - ``UINT_1D_ARRAY``\n" \
100  " - ``UINT_2D``\n" \
101  " - ``UINT_2D_ARRAY``\n" \
102  " - ``UINT_3D``\n" \
103  " - ``UINT_CUBE``\n" \
104  " - ``UINT_CUBE_ARRAY``\n" \
105  " - ``SHADOW_2D``\n" \
106  " - ``SHADOW_2D_ARRAY``\n" \
107  " - ``SHADOW_CUBE``\n" \
108  " - ``SHADOW_CUBE_ARRAY``\n" \
109  " - ``DEPTH_2D``\n" \
110  " - ``DEPTH_2D_ARRAY``\n" \
111  " - ``DEPTH_CUBE``\n" \
112  " - ``DEPTH_CUBE_ARRAY``\n"
113 static const struct PyC_StringEnumItems pygpu_imagetype_items[] = {
114  {(int)ImageType::FLOAT_BUFFER, "FLOAT_BUFFER"},
115  {(int)ImageType::FLOAT_1D, "FLOAT_1D"},
116  {(int)ImageType::FLOAT_1D_ARRAY, "FLOAT_1D_ARRAY"},
117  {(int)ImageType::FLOAT_2D, "FLOAT_2D"},
118  {(int)ImageType::FLOAT_2D_ARRAY, "FLOAT_2D_ARRAY"},
119  {(int)ImageType::FLOAT_3D, "FLOAT_3D"},
120  {(int)ImageType::FLOAT_CUBE, "FLOAT_CUBE"},
121  {(int)ImageType::FLOAT_CUBE_ARRAY, "FLOAT_CUBE_ARRAY"},
122  {(int)ImageType::INT_BUFFER, "INT_BUFFER"},
123  {(int)ImageType::INT_1D, "INT_1D"},
124  {(int)ImageType::INT_1D_ARRAY, "INT_1D_ARRAY"},
125  {(int)ImageType::INT_2D, "INT_2D"},
126  {(int)ImageType::INT_2D_ARRAY, "INT_2D_ARRAY"},
127  {(int)ImageType::INT_3D, "INT_3D"},
128  {(int)ImageType::INT_CUBE, "INT_CUBE"},
129  {(int)ImageType::INT_CUBE_ARRAY, "INT_CUBE_ARRAY"},
130  {(int)ImageType::UINT_BUFFER, "UINT_BUFFER"},
131  {(int)ImageType::UINT_1D, "UINT_1D"},
132  {(int)ImageType::UINT_1D_ARRAY, "UINT_1D_ARRAY"},
133  {(int)ImageType::UINT_2D, "UINT_2D"},
134  {(int)ImageType::UINT_2D_ARRAY, "UINT_2D_ARRAY"},
135  {(int)ImageType::UINT_3D, "UINT_3D"},
136  {(int)ImageType::UINT_CUBE, "UINT_CUBE"},
137  {(int)ImageType::UINT_CUBE_ARRAY, "UINT_CUBE_ARRAY"},
138  {(int)ImageType::SHADOW_2D, "SHADOW_2D"},
139  {(int)ImageType::SHADOW_2D_ARRAY, "SHADOW_2D_ARRAY"},
140  {(int)ImageType::SHADOW_CUBE, "SHADOW_CUBE"},
141  {(int)ImageType::SHADOW_CUBE_ARRAY, "SHADOW_CUBE_ARRAY"},
142  {(int)ImageType::DEPTH_2D, "DEPTH_2D"},
143  {(int)ImageType::DEPTH_2D_ARRAY, "DEPTH_2D_ARRAY"},
144  {(int)ImageType::DEPTH_CUBE, "DEPTH_CUBE"},
145  {(int)ImageType::DEPTH_CUBE_ARRAY, "DEPTH_CUBE_ARRAY"},
146  {0, nullptr},
147 };
148 
149 static const struct PyC_StringEnumItems pygpu_dualblend_items[] = {
150  {(int)DualBlend::NONE, "NONE"},
151  {(int)DualBlend::SRC_0, "SRC_0"},
152  {(int)DualBlend::SRC_1, "SRC_1"},
153  {0, nullptr},
154 };
155 
156 /* -------------------------------------------------------------------- */
161  PyObject *args,
162  const char *format,
163  Type *r_type,
164  const char **r_name)
165 {
166  struct PyC_StringEnum pygpu_type = {pygpu_attrtype_items};
167  PyObject *py_name;
168 
169  if (!PyArg_ParseTuple(args, format, PyC_ParseStringEnum, &pygpu_type, &py_name)) {
170  return false;
171  }
172 
173  const char *name = PyUnicode_AsUTF8(py_name);
174  if (name == nullptr) {
175  return false;
176  }
177 
178 #ifdef USE_GPU_PY_REFERENCES
179  PyList_Append(self->references, (PyObject *)py_name);
180 #endif
181 
182  *r_type = (Type)pygpu_type.value_found;
183  *r_name = name;
184  return true;
185 }
186 
187 PyDoc_STRVAR(pygpu_interface_info_smooth_doc,
188  ".. method:: smooth(type, name)\n"
189  "\n"
190  " Add an attribute with qualifier of type `smooth` to the interface block.\n"
191  "\n"
192  " :param type: One of these types:\n"
193  "\n" PYDOC_TYPE_LIST
194  "\n"
195  " :type type: str\n"
196  " :param name: name of the attribute.\n"
197  " :type name: str\n");
198 static PyObject *pygpu_interface_info_smooth(BPyGPUStageInterfaceInfo *self, PyObject *args)
199 {
200  Type type;
201  const char *name;
202  if (!pygpu_interface_info_get_args(self, args, "O&O:smooth", &type, &name)) {
203  return nullptr;
204  }
205 
206  StageInterfaceInfo *interface = reinterpret_cast<StageInterfaceInfo *>(self->interface);
207  interface->smooth(type, name);
208  Py_RETURN_NONE;
209 }
210 
211 PyDoc_STRVAR(pygpu_interface_info_flat_doc,
212  ".. method:: flat(type, name)\n"
213  "\n"
214  " Add an attribute with qualifier of type `flat` to the interface block.\n"
215  "\n"
216  " :param type: One of these types:\n"
217  "\n" PYDOC_TYPE_LIST
218  "\n"
219  " :type type: str\n"
220  " :param name: name of the attribute.\n"
221  " :type name: str\n");
222 static PyObject *pygpu_interface_info_flat(BPyGPUStageInterfaceInfo *self, PyObject *args)
223 {
224  Type type;
225  const char *name;
226  if (!pygpu_interface_info_get_args(self, args, "O&O:flat", &type, &name)) {
227  return nullptr;
228  }
229 
230  StageInterfaceInfo *interface = reinterpret_cast<StageInterfaceInfo *>(self->interface);
231  interface->flat(type, name);
232  Py_RETURN_NONE;
233 }
234 
236  pygpu_interface_info_no_perspective_doc,
237  ".. method:: no_perspective(type, name)\n"
238  "\n"
239  " Add an attribute with qualifier of type `no_perspective` to the interface block.\n"
240  "\n"
241  " :param type: One of these types:\n"
242  "\n" PYDOC_TYPE_LIST
243  "\n"
244  " :type type: str\n"
245  " :param name: name of the attribute.\n"
246  " :type name: str\n");
248  PyObject *args)
249 {
250  Type type;
251  const char *name;
252  if (!pygpu_interface_info_get_args(self, args, "O&O:no_perspective", &type, &name)) {
253  return nullptr;
254  }
255 
256  StageInterfaceInfo *interface = reinterpret_cast<StageInterfaceInfo *>(self->interface);
257  interface->no_perspective(type, name);
258  Py_RETURN_NONE;
259 }
260 
261 static struct PyMethodDef pygpu_interface_info__tp_methods[] = {
262  {"smooth",
263  (PyCFunction)pygpu_interface_info_smooth,
264  METH_VARARGS,
265  pygpu_interface_info_smooth_doc},
266  {"flat", (PyCFunction)pygpu_interface_info_flat, METH_VARARGS, pygpu_interface_info_flat_doc},
267  {"no_perspective",
269  METH_VARARGS,
270  pygpu_interface_info_no_perspective_doc},
271  {nullptr, nullptr, 0, nullptr},
272 };
273 
276 /* -------------------------------------------------------------------- */
280 PyDoc_STRVAR(pygpu_interface_info_name_doc,
281  "Name of the interface block.\n"
282  "\n"
283  ":type: str");
285  void *UNUSED(closure))
286 {
287  StageInterfaceInfo *interface = reinterpret_cast<StageInterfaceInfo *>(self->interface);
288  return PyUnicode_FromString(interface->name.c_str());
289 }
290 
291 static PyGetSetDef pygpu_interface_info__tp_getseters[] = {
292  {"name",
294  (setter) nullptr,
295  pygpu_interface_info_name_doc,
296  nullptr},
297  {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
298 };
299 
302 /* -------------------------------------------------------------------- */
306 static PyObject *pygpu_interface_info__tp_new(PyTypeObject *UNUSED(type),
307  PyObject *args,
308  PyObject *kwds)
309 {
310  if (kwds) {
311  PyErr_SetString(PyExc_TypeError, "no keywords are expected");
312  return nullptr;
313  }
314 
315  const char *name;
316  if (!PyArg_ParseTuple(args, "s:GPUStageInterfaceInfo.__new__*", &name)) {
317  return nullptr;
318  }
319 
320  StageInterfaceInfo *interface = new StageInterfaceInfo(name, "");
321  GPUStageInterfaceInfo *interface_info = reinterpret_cast<GPUStageInterfaceInfo *>(interface);
322 
323  auto *self = BPyGPUStageInterfaceInfo_CreatePyObject(interface_info);
324 
325 #ifdef USE_GPU_PY_REFERENCES
326  PyObject *py_name = PyTuple_GET_ITEM(args, 0);
327  PyList_Append(((BPyGPUStageInterfaceInfo *)self)->references, py_name);
328 #endif
329 
330  return self;
331 }
332 
333 #ifdef USE_GPU_PY_REFERENCES
334 
335 static int pygpu_interface_info__tp_traverse(PyObject *self, visitproc visit, void *arg)
336 {
337  BPyGPUStageInterfaceInfo *py_interface = reinterpret_cast<BPyGPUStageInterfaceInfo *>(self);
338  Py_VISIT(py_interface->references);
339  return 0;
340 }
341 
342 static int pygpu_interface_info__tp_clear(PyObject *self)
343 {
344  BPyGPUStageInterfaceInfo *py_interface = reinterpret_cast<BPyGPUStageInterfaceInfo *>(self);
345  Py_CLEAR(py_interface->references);
346  return 0;
347 }
348 
349 #endif
350 
351 static void pygpu_interface_info__tp_dealloc(PyObject *self)
352 {
353  BPyGPUStageInterfaceInfo *py_interface = reinterpret_cast<BPyGPUStageInterfaceInfo *>(self);
354  StageInterfaceInfo *interface = reinterpret_cast<StageInterfaceInfo *>(py_interface->interface);
355  delete interface;
356 
357 #ifdef USE_GPU_PY_REFERENCES
358  PyObject_GC_UnTrack(self);
359  if (py_interface->references) {
360  pygpu_interface_info__tp_clear(self);
361  Py_CLEAR(py_interface->references);
362  }
363 #endif
364 
365  Py_TYPE(self)->tp_free((PyObject *)self);
366 }
367 
368 PyDoc_STRVAR(pygpu_interface_info__tp_doc,
369  ".. class:: GPUStageInterfaceInfo(name)\n"
370  "\n"
371  " List of varyings between shader stages.\n\n"
372  "\n"
373  " :param name: Name of the interface block.\n"
374  " :type value: str\n");
375 constexpr PyTypeObject pygpu_interface_info_type()
376 {
377  PyTypeObject pytype = {PyVarObject_HEAD_INIT(nullptr, 0)};
378  pytype.tp_name = "GPUStageInterfaceInfo";
379  pytype.tp_basicsize = sizeof(BPyGPUStageInterfaceInfo);
380  pytype.tp_dealloc = pygpu_interface_info__tp_dealloc;
381  pytype.tp_doc = pygpu_interface_info__tp_doc;
382 #ifdef USE_GPU_PY_REFERENCES
383  pytype.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC;
384  pytype.tp_traverse = pygpu_interface_info__tp_traverse;
385  pytype.tp_clear = pygpu_interface_info__tp_clear;
386 #else
387  pytype.tp_flags = Py_TPFLAGS_DEFAULT,
388 #endif
389  pytype.tp_methods = pygpu_interface_info__tp_methods;
390  pytype.tp_getset = pygpu_interface_info__tp_getseters;
391  pytype.tp_new = pygpu_interface_info__tp_new;
392  return pytype;
393 }
394 
397 /* -------------------------------------------------------------------- */
401 PyDoc_STRVAR(pygpu_shader_info_vertex_in_doc,
402  ".. method:: vertex_in(slot, type, name)\n"
403  "\n"
404  " Add a vertex shader input attribute.\n"
405  "\n"
406  " :param slot: The attribute index.\n"
407  " :type slot: int\n"
408  " :param type: One of these types:\n"
409  "\n" PYDOC_TYPE_LIST
410  "\n"
411  " :type type: str\n"
412  " :param name: name of the attribute.\n"
413  " :type name: str\n");
414 static PyObject *pygpu_shader_info_vertex_in(BPyGPUShaderCreateInfo *self, PyObject *args)
415 {
416  int slot;
417  struct PyC_StringEnum pygpu_type = {pygpu_attrtype_items};
418  const char *param;
419 
420  if (!PyArg_ParseTuple(args, "iO&s:vertex_in", &slot, PyC_ParseStringEnum, &pygpu_type, &param)) {
421  return nullptr;
422  }
423 
424 #ifdef USE_GPU_PY_REFERENCES
425  PyObject *py_name = PyTuple_GET_ITEM(args, 2);
426  PyList_Append(self->references, py_name);
427 #endif
428 
429  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
430  info->vertex_in(slot, (Type)pygpu_type.value_found, param);
431  Py_RETURN_NONE;
432 }
433 
434 PyDoc_STRVAR(pygpu_shader_info_vertex_out_doc,
435  ".. method:: vertex_out(interface)\n"
436  "\n"
437  " Add a vertex shader output interface block.\n"
438  "\n"
439  " :param interface: Object describing the block.\n"
440  " :type interface: :class:`gpu.types.GPUStageInterfaceInfo`\n");
443 {
445  PyErr_Format(PyExc_TypeError, "Expected a GPUStageInterfaceInfo, got %s", Py_TYPE(o)->tp_name);
446  return nullptr;
447  }
448 
449 #ifdef USE_GPU_PY_REFERENCES
450  PyList_Append(self->references, (PyObject *)o);
451 #endif
452 
453  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
454  StageInterfaceInfo *interface = reinterpret_cast<StageInterfaceInfo *>(o->interface);
455  info->vertex_out(*interface);
456 
457  Py_RETURN_NONE;
458 }
459 
460 PyDoc_STRVAR(pygpu_shader_info_fragment_out_doc,
461  ".. method:: fragment_out(slot, type, name, blend='NONE')\n"
462  "\n"
463  " Specify a fragment output corresponding to a framebuffer target slot.\n"
464  "\n"
465  " :param slot: The attribute index.\n"
466  " :type slot: int\n"
467  " :param type: One of these types:\n"
468  "\n" PYDOC_TYPE_LIST
469  "\n"
470  " :type type: str\n"
471  " :param name: Name of the attribute.\n"
472  " :type name: str\n"
473  " :param blend: Dual Source Blending Index. It can be 'NONE', 'SRC_0' or 'SRC_1'.\n"
474  " :type blend: str\n");
476  PyObject *args,
477  PyObject *kwds)
478 {
479  int slot;
480  struct PyC_StringEnum pygpu_type = {pygpu_attrtype_items};
481  const char *name;
482  struct PyC_StringEnum blend_type = {pygpu_dualblend_items, (int)DualBlend::NONE};
483 
484  static const char *_keywords[] = {"slot", "type", "name", "blend", nullptr};
485  static _PyArg_Parser _parser = {
486  "i" /* `slot` */
487  "O&" /* `type` */
488  "s" /* `name` */
489  "|$" /* Optional keyword only arguments. */
490  "O&" /* `blend` */
491  ":fragment_out",
492  _keywords,
493  nullptr,
494  };
495  if (!_PyArg_ParseTupleAndKeywordsFast(args,
496  kwds,
497  &_parser,
498  &slot,
500  &pygpu_type,
501  &name,
503  &blend_type)) {
504  return nullptr;
505  }
506 
507 #ifdef USE_GPU_PY_REFERENCES
508  PyObject *py_name = PyTuple_GET_ITEM(args, 2);
509  PyList_Append(self->references, py_name);
510 #endif
511 
512  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
513  info->fragment_out(slot, (Type)pygpu_type.value_found, name, (DualBlend)blend_type.value_found);
514 
515  Py_RETURN_NONE;
516 }
517 
519  pygpu_shader_info_uniform_buf_doc,
520  ".. method:: uniform_buf(slot, type_name, name)\n"
521  "\n"
522  " Specify a uniform variable whose type can be one of those declared in `typedef_source`.\n"
523  "\n"
524  " :param slot: The uniform variable index.\n"
525  " :type slot: int\n"
526  " :param type_name: Name of the data type. It can be a struct type defined in the source "
527  "passed through the :meth:`gpu.types.GPUShaderCreateInfo.typedef_source`.\n"
528  " :type type_name: str\n"
529  " :param name: The uniform variable name.\n"
530  " :type name: str\n");
531 static PyObject *pygpu_shader_info_uniform_buf(BPyGPUShaderCreateInfo *self, PyObject *args)
532 {
533  int slot;
534  const char *type_name;
535  const char *name;
536 
537  if (!PyArg_ParseTuple(args, "iss:uniform_buf", &slot, &type_name, &name)) {
538  return nullptr;
539  }
540 
541 #ifdef USE_GPU_PY_REFERENCES
542  PyList_Append(self->references, PyTuple_GET_ITEM(args, 1)); /* type_name */
543  PyList_Append(self->references, PyTuple_GET_ITEM(args, 2)); /* name */
544 #endif
545 
546  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
547  info->uniform_buf(slot, type_name, name);
548 
549  Py_RETURN_NONE;
550 }
551 
552 #ifdef USE_PYGPU_SHADER_INFO_IMAGE_METHOD
554  pygpu_shader_info_image_doc,
555  ".. method:: image(slot, format, type, name, qualifiers={'NO_RESTRICT'})\n"
556  "\n"
557  " Specify an image resource used for arbitrary load and store operations.\n"
558  "\n"
559  " :param slot: The image resource index.\n"
560  " :type slot: int\n"
561  " :param format: The GPUTexture format that is passed to the shader. Possible values are:\n"
562  "" PYDOC_TEX_FORMAT_ITEMS
563  " :type format: str\n"
564  " :param type: The data type describing how the image is to be read in the shader. "
565  "Possible values are:\n"
566  "\n" PYDOC_IMAGE_TYPES
567  "\n"
568  " :type type: str\n"
569  " :param name: The image resource name.\n"
570  " :type name: str\n"
571  " :param qualifiers: Set containing values that describe how the image resource is to be "
572  "read or written. Possible values are:\n"
573  "" PYDOC_QUALIFIERS
574  ""
575  " :type qualifiers: set\n");
576 static PyObject *pygpu_shader_info_image(BPyGPUShaderCreateInfo *self,
577  PyObject *args,
578  PyObject *kwds)
579 {
580  int slot;
581  struct PyC_StringEnum pygpu_texformat = {pygpu_textureformat_items};
582  struct PyC_StringEnum pygpu_imagetype = {pygpu_imagetype_items};
583  const char *name;
584  PyObject *py_qualifiers = nullptr;
585  Qualifier qualifier = Qualifier::NO_RESTRICT;
586 
587  static const char *_keywords[] = {"slot", "format", "type", "name", "qualifiers", nullptr};
588  static _PyArg_Parser _parser = {
589  "i" /* `slot` */
590  "O&" /* `format` */
591  "O&" /* `type` */
592  "s" /* `name` */
593  "|$" /* Optional keyword only arguments. */
594  "O" /* `qualifiers` */
595  ":image",
596  _keywords,
597  nullptr,
598  };
599  if (!_PyArg_ParseTupleAndKeywordsFast(args,
600  kwds,
601  &_parser,
602  &slot,
604  &pygpu_texformat,
606  &pygpu_imagetype,
607  &name,
608  &py_qualifiers)) {
609  return nullptr;
610  }
611 
612  if (py_qualifiers &&
614  pygpu_qualifiers, py_qualifiers, (int *)&qualifier, "shader_info.image") == -1) {
615  return nullptr;
616  }
617 
618 # ifdef USE_GPU_PY_REFERENCES
619  PyList_Append(self->references, PyTuple_GET_ITEM(args, 3)); /* name */
620 # endif
621 
622  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
623  info->image(slot,
624  (eGPUTextureFormat)pygpu_texformat.value_found,
625  qualifier,
626  (ImageType)pygpu_imagetype.value_found,
627  name);
628 
629  Py_RETURN_NONE;
630 }
631 #endif
632 
634  pygpu_shader_info_sampler_doc,
635  ".. method:: sampler(slot, type, name)\n"
636  "\n"
637  " Specify an image texture sampler.\n"
638  "\n"
639  " :param slot: The image texture sampler index.\n"
640  " :type slot: int\n"
641  " :param type: The data type describing the format of each sampler unit. Possible values "
642  "are:\n"
643  "\n" PYDOC_IMAGE_TYPES
644  "\n"
645  " :type type: str\n"
646  " :param name: The image texture sampler name.\n"
647  " :type name: str\n");
648 static PyObject *pygpu_shader_info_sampler(BPyGPUShaderCreateInfo *self, PyObject *args)
649 {
650  int slot;
651  struct PyC_StringEnum pygpu_samplertype = {pygpu_imagetype_items};
652  const char *name;
653 
654  if (!PyArg_ParseTuple(
655  args, "iO&s:sampler", &slot, PyC_ParseStringEnum, &pygpu_samplertype, &name)) {
656  return nullptr;
657  }
658 
659 #ifdef USE_GPU_PY_REFERENCES
660  PyList_Append(self->references, PyTuple_GET_ITEM(args, 2)); /* name */
661 #endif
662 
663  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
664  info->sampler(slot, (ImageType)pygpu_samplertype.value_found, name);
665 
666  Py_RETURN_NONE;
667 }
668 
670 {
671  switch (type) {
672  case Type::BOOL:
673  case Type::FLOAT:
674  case Type::INT:
675  case Type::UINT:
676  return 4;
677  break;
678  case Type::VEC2:
679  case Type::UVEC2:
680  case Type::IVEC2:
681  return 8;
682  break;
683  case Type::VEC3:
684  case Type::UVEC3:
685  case Type::IVEC3:
686  return 12;
687  break;
688  case Type::VEC4:
689  case Type::UVEC4:
690  case Type::IVEC4:
691  return 16;
692  break;
693  case Type::MAT3:
694  return 36 + 3 * 4;
695  case Type::MAT4:
696  return 64;
697  break;
698  }
699  BLI_assert(false);
700  return -1;
701 }
702 
704 {
705  int size_prev = 0;
706  int size_last = 0;
707  for (const ShaderCreateInfo::PushConst &uniform : info->push_constants_) {
708  int pad = 0;
709  int size = constant_type_size(uniform.type);
710  if (size_last && size_last != size) {
711  /* Calc pad. */
712  int pack = (size == 8) ? 8 : 16;
713  if (size_last < size) {
714  pad = pack - (size_last % pack);
715  }
716  else {
717  pad = size_prev % pack;
718  }
719  }
720  else if (size == 12) {
721  /* It is still unclear how Vulkan handles padding for `vec3` constants. For now let's follow
722  * the rules of the `std140` layout. */
723  pad = 4;
724  }
725  size_prev += pad + size * std::max(1, uniform.array_size);
726  size_last = size;
727  }
728  return size_prev + (size_prev % 16);
729 }
730 
731 PyDoc_STRVAR(pygpu_shader_info_push_constant_doc,
732  ".. method:: push_constant(type, name, size=0)\n"
733  "\n"
734  " Specify a global access constant.\n"
735  "\n"
736  " :param type: One of these types:\n"
737  "\n" PYDOC_TYPE_LIST
738  "\n"
739  " :type type: str\n"
740  " :param name: Name of the constant.\n"
741  " :type name: str\n"
742  " :param size: If not zero, indicates that the constant is an array with the "
743  "specified size.\n"
744  " :type size: uint\n");
746  PyObject *args,
747  PyObject *kwds)
748 {
749  struct PyC_StringEnum pygpu_type = {pygpu_attrtype_items};
750  const char *name = nullptr;
751  int array_size = 0;
752 
753  static const char *_keywords[] = {"type", "name", "size", nullptr};
754  static _PyArg_Parser _parser = {
755  "O&" /* `type` */
756  "s" /* `name` */
757  "|" /* Optional arguments. */
758  "I" /* `size` */
759  ":push_constant",
760  _keywords,
761  nullptr,
762  };
763  if (!_PyArg_ParseTupleAndKeywordsFast(
764  args, kwds, &_parser, PyC_ParseStringEnum, &pygpu_type, &name, &array_size)) {
765  return nullptr;
766  }
767 
768 #ifdef USE_GPU_PY_REFERENCES
769  PyObject *py_name = PyTuple_GET_ITEM(args, 1);
770  PyList_Append(self->references, py_name);
771 #endif
772 
773  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
774  info->push_constant((Type)pygpu_type.value_found, name, array_size);
775 
776 #define VULKAN_LIMIT 128
777  int size = constants_calc_size(info);
778  if (size > VULKAN_LIMIT) {
779  printf("Push constants have a minimum supported size of "
781  " bytes, however the constants added so far already reach %d bytes. Consider using UBO.\n", size);
782  }
783 #undef VULKAN_LIMIT
784 
785  Py_RETURN_NONE;
786 }
787 
789  pygpu_shader_info_vertex_source_doc,
790  ".. method:: vertex_source(source)\n"
791  "\n"
792  " Vertex shader source code written in GLSL.\n"
793  "\n"
794  " Example:\n"
795  "\n"
796  " .. code-block:: python\n"
797  "\n"
798  " \"void main {gl_Position = vec4(pos, 1.0);}\"\n"
799  "\n"
800  " :param source: The vertex shader source code.\n"
801  " :type source: str\n"
802  "\n"
803  " .. seealso:: `GLSL Cross Compilation "
804  "<https://wiki.blender.org/wiki/EEVEE_%26_Viewport/GPU_Module/GLSL_Cross_Compilation>`__\n");
805 static PyObject *pygpu_shader_info_vertex_source(BPyGPUShaderCreateInfo *self, PyObject *o)
806 {
807  const char *vertex_source = PyUnicode_AsUTF8(o);
808  if (vertex_source == nullptr) {
809  PyErr_Format(PyExc_ValueError, "expected a string, got %s", Py_TYPE(o)->tp_name);
810  return nullptr;
811  }
812 
813 #ifdef USE_GPU_PY_REFERENCES
814  if (self->vertex_source) {
815  Py_DECREF(self->vertex_source);
816  }
817 
818  self->vertex_source = o;
819  Py_INCREF(o);
820 #endif
821 
822  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
823  info->vertex_source("common_colormanagement_lib.glsl");
825 
826  Py_RETURN_NONE;
827 }
828 
830  pygpu_shader_info_fragment_source_doc,
831  ".. method:: fragment_source(source)\n"
832  "\n"
833  " Fragment shader source code written in GLSL.\n"
834  "\n"
835  " Example:\n"
836  "\n"
837  " .. code-block:: python\n"
838  "\n"
839  " \"void main {fragColor = vec4(0.0, 0.0, 0.0, 1.0);}\"\n"
840  "\n"
841  " :param source: The fragment shader source code.\n"
842  " :type source: str\n"
843  "\n"
844  " .. seealso:: `GLSL Cross Compilation "
845  "<https://wiki.blender.org/wiki/EEVEE_%26_Viewport/GPU_Module/GLSL_Cross_Compilation>`__\n");
846 static PyObject *pygpu_shader_info_fragment_source(BPyGPUShaderCreateInfo *self, PyObject *o)
847 {
848  const char *fragment_source = PyUnicode_AsUTF8(o);
849  if (fragment_source == nullptr) {
850  PyErr_Format(PyExc_ValueError, "expected a string, got %s", Py_TYPE(o)->tp_name);
851  return nullptr;
852  }
853 
854 #ifdef USE_GPU_PY_REFERENCES
855  if (self->fragment_source) {
856  Py_DECREF(self->fragment_source);
857  }
858 
859  self->fragment_source = o;
860  Py_INCREF(o);
861 #endif
862 
863  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
864  info->fragment_source("common_colormanagement_lib.glsl");
866 
867  Py_RETURN_NONE;
868 }
869 
870 PyDoc_STRVAR(pygpu_shader_info_typedef_source_doc,
871  ".. method:: typedef_source(source)\n"
872  "\n"
873  " Source code included before resource declaration. "
874  "Useful for defining structs used by Uniform Buffers.\n"
875  "\n"
876  " Example:\n"
877  "\n"
878  ".. code-block:: python\n"
879  "\n"
880  " \"struct MyType {int foo; float bar;};\"\n"
881  "\n"
882  " :param source: The source code defining types.\n"
883  " :type source: str\n");
884 static PyObject *pygpu_shader_info_typedef_source(BPyGPUShaderCreateInfo *self, PyObject *o)
885 {
886  const char *typedef_source = PyUnicode_AsUTF8(o);
887  if (typedef_source == nullptr) {
888  PyErr_Format(PyExc_ValueError, "expected a string, got %s", Py_TYPE(o)->tp_name);
889  return nullptr;
890  }
891 
892 #ifdef USE_GPU_PY_REFERENCES
893  if (self->typedef_source) {
894  Py_DECREF(self->typedef_source);
895  }
896 
897  self->typedef_source = o;
898  Py_INCREF(o);
899 #endif
900 
901  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
902 #if 0
903  if (info->typedef_sources_.is_empty()) {
904  info->typedef_source("GPU_shader_shared_utils.h");
905  }
906 #endif
908 
909  Py_RETURN_NONE;
910 }
911 
912 PyDoc_STRVAR(pygpu_shader_info_define_doc,
913  ".. method:: define(name, value)\n"
914  "\n"
915  " Add a preprocessing define directive. In GLSL it would be something like:\n"
916  "\n"
917  ".. code-block:: glsl\n"
918  "\n"
919  " #define name value\n"
920  "\n"
921  " :param name: Token name.\n"
922  " :type name: str\n"
923  " :param value: Text that replaces token occurrences.\n"
924  " :type value: str\n");
925 static PyObject *pygpu_shader_info_define(BPyGPUShaderCreateInfo *self, PyObject *args)
926 {
927  const char *name;
928  const char *value = nullptr;
929 
930  if (!PyArg_ParseTuple(args, "s|s:define", &name, &value)) {
931  return nullptr;
932  }
933 
934 #ifdef USE_GPU_PY_REFERENCES
935  PyList_Append(self->references, PyTuple_GET_ITEM(args, 0)); /* name */
936  if (value) {
937  PyList_Append(self->references, PyTuple_GET_ITEM(args, 1)); /* value */
938  }
939 #endif
940 
941  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
942  if (value) {
943  info->define(name, value);
944  }
945  else {
946  info->define(name);
947  }
948 
949  Py_RETURN_NONE;
950 }
951 
952 static struct PyMethodDef pygpu_shader_info__tp_methods[] = {
953  {"vertex_in",
954  (PyCFunction)pygpu_shader_info_vertex_in,
955  METH_VARARGS,
956  pygpu_shader_info_vertex_in_doc},
957  {"vertex_out",
958  (PyCFunction)pygpu_shader_info_vertex_out,
959  METH_O,
960  pygpu_shader_info_vertex_out_doc},
961  {"fragment_out",
962  (PyCFunction)(void *)pygpu_shader_info_fragment_out,
963  METH_VARARGS | METH_KEYWORDS,
964  pygpu_shader_info_fragment_out_doc},
965  {"uniform_buf",
966  (PyCFunction)(void *)pygpu_shader_info_uniform_buf,
967  METH_VARARGS,
968  pygpu_shader_info_uniform_buf_doc},
969 #ifdef USE_PYGPU_SHADER_INFO_IMAGE_METHOD
970  {"image",
971  (PyCFunction)(void *)pygpu_shader_info_image,
972  METH_VARARGS | METH_KEYWORDS,
973  pygpu_shader_info_image_doc},
974 #endif
975  {"sampler",
976  (PyCFunction)pygpu_shader_info_sampler,
977  METH_VARARGS,
978  pygpu_shader_info_sampler_doc},
979  {"push_constant",
980  (PyCFunction)(void *)pygpu_shader_info_push_constant,
981  METH_VARARGS | METH_KEYWORDS,
982  pygpu_shader_info_push_constant_doc},
983  {"vertex_source",
984  (PyCFunction)pygpu_shader_info_vertex_source,
985  METH_O,
986  pygpu_shader_info_vertex_source_doc},
987  {"fragment_source",
989  METH_O,
990  pygpu_shader_info_fragment_source_doc},
991  {"typedef_source",
993  METH_O,
994  pygpu_shader_info_typedef_source_doc},
995  {"define", (PyCFunction)pygpu_shader_info_define, METH_VARARGS, pygpu_shader_info_define_doc},
996  {nullptr, nullptr, 0, nullptr},
997 };
998 
1001 /* -------------------------------------------------------------------- */
1005 static PyObject *pygpu_shader_info__tp_new(PyTypeObject *UNUSED(type),
1006  PyObject *args,
1007  PyObject *kwds)
1008 {
1009  if (PyTuple_Size(args) || kwds) {
1010  PyErr_SetString(PyExc_TypeError, "no args or keywords are expected");
1011  return nullptr;
1012  }
1013 
1014  ShaderCreateInfo *info = new ShaderCreateInfo("pyGPU_Shader");
1015  GPUShaderCreateInfo *shader_info = reinterpret_cast<GPUShaderCreateInfo *>(info);
1016 
1017  return BPyGPUShaderCreateInfo_CreatePyObject(shader_info);
1018 }
1019 
1020 #ifdef USE_GPU_PY_REFERENCES
1021 
1022 static int pygpu_shader_info__tp_traverse(PyObject *self, visitproc visit, void *arg)
1023 {
1024  BPyGPUShaderCreateInfo *py_info = reinterpret_cast<BPyGPUShaderCreateInfo *>(self);
1025  Py_VISIT(py_info->vertex_source);
1026  Py_VISIT(py_info->fragment_source);
1027  Py_VISIT(py_info->references);
1028  return 0;
1029 }
1030 
1031 static int pygpu_shader_info__tp_clear(PyObject *self)
1032 {
1033  BPyGPUShaderCreateInfo *py_info = reinterpret_cast<BPyGPUShaderCreateInfo *>(self);
1034  Py_CLEAR(py_info->vertex_source);
1035  Py_CLEAR(py_info->fragment_source);
1036  Py_CLEAR(py_info->references);
1037  return 0;
1038 }
1039 
1040 #endif
1041 
1042 static void pygpu_shader_info__tp_dealloc(PyObject *self)
1043 {
1044  BPyGPUShaderCreateInfo *py_info = reinterpret_cast<BPyGPUShaderCreateInfo *>(self);
1045  ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(py_info->info);
1046  delete info;
1047 
1048 #ifdef USE_GPU_PY_REFERENCES
1049  PyObject_GC_UnTrack(self);
1050  if (py_info->references || py_info->vertex_source || py_info->fragment_source) {
1051  pygpu_shader_info__tp_clear(self);
1052  Py_XDECREF(py_info->vertex_source);
1053  Py_XDECREF(py_info->fragment_source);
1054  Py_XDECREF(py_info->references);
1055  }
1056 #endif
1057 
1058  Py_TYPE(self)->tp_free((PyObject *)self);
1059 }
1060 
1061 PyDoc_STRVAR(pygpu_shader_info__tp_doc,
1062  ".. class:: GPUShaderCreateInfo()\n"
1063  "\n"
1064  " Stores and describes types and variables that are used in shader sources.\n");
1065 constexpr PyTypeObject pygpu_shader_info_type()
1066 {
1067  PyTypeObject pytype = {PyVarObject_HEAD_INIT(nullptr, 0)};
1068  pytype.tp_name = "GPUShaderCreateInfo";
1069  pytype.tp_basicsize = sizeof(BPyGPUShaderCreateInfo);
1070  pytype.tp_dealloc = pygpu_shader_info__tp_dealloc;
1071  pytype.tp_doc = pygpu_shader_info__tp_doc;
1072 #ifdef USE_GPU_PY_REFERENCES
1073  pytype.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC;
1074  pytype.tp_traverse = pygpu_shader_info__tp_traverse;
1075  pytype.tp_clear = pygpu_shader_info__tp_clear;
1076 #else
1077  pytype.tp_flags = Py_TPFLAGS_DEFAULT,
1078 #endif
1079  pytype.tp_methods = pygpu_shader_info__tp_methods;
1080  pytype.tp_new = pygpu_shader_info__tp_new;
1081  return pytype;
1082 }
1083 
1086 /* -------------------------------------------------------------------- */
1092 
1093 PyObject *BPyGPUStageInterfaceInfo_CreatePyObject(GPUStageInterfaceInfo *interface)
1094 {
1096 
1097 #ifdef USE_GPU_PY_REFERENCES
1098  self = (BPyGPUStageInterfaceInfo *)_PyObject_GC_New(&BPyGPUStageInterfaceInfo_Type);
1099  self->references = PyList_New(0);
1100 #else
1102 #endif
1103 
1104  self->interface = interface;
1105 
1106  return (PyObject *)self;
1107 }
1108 
1110 {
1111  BPyGPUShaderCreateInfo *self;
1112 
1113 #ifdef USE_GPU_PY_REFERENCES
1114  self = (BPyGPUShaderCreateInfo *)_PyObject_GC_New(&BPyGPUShaderCreateInfo_Type);
1115  self->vertex_source = nullptr;
1116  self->fragment_source = nullptr;
1117  self->typedef_source = nullptr;
1118  self->references = PyList_New(0);
1119 #else
1120  self = PyObject_New(BPyGPUShaderCreateInfo, &BPyGPUShaderCreateInfo_Type);
1121 #endif
1122 
1123  self->info = info;
1124  self->constants_total_size = 0;
1125 
1126  return (PyObject *)self;
1127 }
1128 
#define BLI_assert(a)
Definition: BLI_assert.h:46
KDTree *BLI_kdtree_nd_() new(unsigned int maxsize)
Definition: kdtree_impl.h:85
#define STRINGIFY(x)
#define UNUSED(x)
typedef UINT(API *GHOST_WIN32_GetDpiForWindow)(HWND)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
struct GPUShaderCreateInfo GPUShaderCreateInfo
Definition: GPU_shader.h:18
eGPUTextureFormat
Definition: GPU_texture.h:83
int pad[32 - sizeof(int)]
vertex_source("basic_depth_pointcloud_vert.glsl") .additional_info("draw_pointcloud")
PyObject * self
Definition: bpy_driver.c:165
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
out_color fragment_source("eevee_film_frag.glsl") .additional_info("draw_fullscreen"
typedef_source("eevee_defines.hh") .typedef_source("eevee_shader_shared.hh")
struct BPyGPUShaderCreateInfo BPyGPUShaderCreateInfo
struct BPyGPUStageInterfaceInfo BPyGPUStageInterfaceInfo
#define BPyGPUStageInterfaceInfo_Check(v)
Definition: gpu_py_shader.h:38
#define PYDOC_TYPE_LIST
static PyObject * pygpu_shader_info_define(BPyGPUShaderCreateInfo *self, PyObject *args)
constexpr PyTypeObject pygpu_interface_info_type()
static PyObject * pygpu_shader_info__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
static int constant_type_size(Type type)
PyTypeObject BPyGPUStageInterfaceInfo_Type
static const struct PyC_StringEnumItems pygpu_attrtype_items[]
static PyObject * pygpu_interface_info__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
#define VULKAN_LIMIT
static PyObject * pygpu_shader_info_uniform_buf(BPyGPUShaderCreateInfo *self, PyObject *args)
static int constants_calc_size(ShaderCreateInfo *info)
static PyObject * pygpu_shader_info_vertex_source(BPyGPUShaderCreateInfo *self, PyObject *o)
static PyObject * pygpu_shader_info_fragment_out(BPyGPUShaderCreateInfo *self, PyObject *args, PyObject *kwds)
static void pygpu_shader_info__tp_dealloc(PyObject *self)
static PyGetSetDef pygpu_interface_info__tp_getseters[]
static const struct PyC_StringEnumItems pygpu_dualblend_items[]
constexpr PyTypeObject pygpu_shader_info_type()
static PyObject * pygpu_shader_info_typedef_source(BPyGPUShaderCreateInfo *self, PyObject *o)
PyObject * BPyGPUStageInterfaceInfo_CreatePyObject(GPUStageInterfaceInfo *interface)
static struct PyMethodDef pygpu_shader_info__tp_methods[]
static PyObject * pygpu_interface_info_name_get(BPyGPUStageInterfaceInfo *self, void *UNUSED(closure))
PyDoc_STRVAR(pygpu_interface_info_smooth_doc, ".. method:: smooth(type, name)\n" "\n" " Add an attribute with qualifier of type `smooth` to the interface block.\n" "\n" " :param type: One of these types:\n" "\n" PYDOC_TYPE_LIST "\n" " :type type: str\n" " :param name: name of the attribute.\n" " :type name: str\n")
static PyObject * pygpu_interface_info_no_perspective(BPyGPUStageInterfaceInfo *self, PyObject *args)
PyObject * BPyGPUShaderCreateInfo_CreatePyObject(GPUShaderCreateInfo *info)
static PyObject * pygpu_shader_info_vertex_in(BPyGPUShaderCreateInfo *self, PyObject *args)
static PyObject * pygpu_shader_info_vertex_out(BPyGPUShaderCreateInfo *self, BPyGPUStageInterfaceInfo *o)
#define PYDOC_IMAGE_TYPES
PyTypeObject BPyGPUShaderCreateInfo_Type
static PyObject * pygpu_interface_info_smooth(BPyGPUStageInterfaceInfo *self, PyObject *args)
static struct PyMethodDef pygpu_interface_info__tp_methods[]
static void pygpu_interface_info__tp_dealloc(PyObject *self)
static PyObject * pygpu_shader_info_sampler(BPyGPUShaderCreateInfo *self, PyObject *args)
static const struct PyC_StringEnumItems pygpu_imagetype_items[]
static PyObject * pygpu_interface_info_flat(BPyGPUStageInterfaceInfo *self, PyObject *args)
static PyObject * pygpu_shader_info_fragment_source(BPyGPUShaderCreateInfo *self, PyObject *o)
static bool pygpu_interface_info_get_args(BPyGPUStageInterfaceInfo *self, PyObject *args, const char *format, Type *r_type, const char **r_name)
static PyObject * pygpu_shader_info_push_constant(BPyGPUShaderCreateInfo *self, PyObject *args, PyObject *kwds)
static const struct PyC_StringEnumItems pygpu_textureformat_items[]
format
Definition: logImageCore.h:38
int PyC_ParseStringEnum(PyObject *o, void *p)
int PyC_FlagSet_ToBitfield(const PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix)
@ FLOAT
PyObject_VAR_HEAD struct GPUShaderCreateInfo * info
Definition: gpu_py_shader.h:51
PyObject * fragment_source
Definition: gpu_py_shader.h:55
PyObject_VAR_HEAD struct GPUStageInterfaceInfo * interface
Definition: gpu_py_shader.h:42
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...
Self & typedef_source(StringRefNull filename)
Self & uniform_buf(int slot, StringRefNull type_name, StringRefNull name, Frequency freq=Frequency::PASS)
Self & sampler(int slot, ImageType type, StringRefNull name, Frequency freq=Frequency::PASS, eGPUSamplerState sampler=(eGPUSamplerState) -1)
Self & fragment_source(StringRefNull filename)
Self & vertex_in(int slot, Type type, StringRefNull name)
Self & vertex_out(StageInterfaceInfo &interface)
Self & push_constant(Type type, StringRefNull name, int array_size=0)
Self & define(StringRefNull name, StringRefNull value="")
Self & vertex_source(StringRefNull filename)
Self & image(int slot, eGPUTextureFormat format, Qualifier qualifiers, ImageType type, StringRefNull name, Frequency freq=Frequency::PASS)
Self & fragment_out(int slot, Type type, StringRefNull name, DualBlend blend=DualBlend::NONE)
Self & no_perspective(Type type, StringRefNull _name)
Self & smooth(Type type, StringRefNull _name)
Self & flat(Type type, StringRefNull _name)
float max