Changeset View
Standalone View
source/blender/python/intern/gpu.c
| Show All 35 Lines | |||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_material_types.h" | #include "DNA_material_types.h" | ||||
| #include "DNA_ID.h" | #include "DNA_ID.h" | ||||
| #include "DNA_customdata_types.h" | #include "DNA_customdata_types.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_math_vector.h" | |||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "bpy_rna.h" | #include "bpy_rna.h" | ||||
| #include "../generic/py_capi_utils.h" | #include "../generic/py_capi_utils.h" | ||||
| #include "GPU_material.h" | #include "GPU_material.h" | ||||
| #include "gpu.h" | #include "gpu.h" | ||||
| #include "gpu_codegen.h" | |||||
| #define PY_MODULE_ADD_CONSTANT(module, name) PyModule_AddIntConstant(module, # name, name) | #include "BPY_extern.h" | ||||
| #include "mathutils/mathutils.h" | |||||
| #include "BKE_node.h" | |||||
| typedef struct GPULink { | |||||
| PyObject_VAR_HEAD | |||||
| GPULinkDesc desc; | |||||
| float uniform[16]; | |||||
| } GPULink; | |||||
| PyDoc_STRVAR(M_gpu_doc, | PyDoc_STRVAR(M_gpu_doc, | ||||
| "This module provides access to the GLSL shader and Offscreen rendering functionalities." | "This module provides access to the GLSL shader and Offscreen rendering functionalities." | ||||
| ); | ); | ||||
| PyDoc_STRVAR(pygpu_gpu_link_doc, | |||||
| "GPU_link(glsl_fnc, args)\n" | |||||
| "\n" | |||||
| " Return true if succeed.\n" | |||||
| "\n" | |||||
| " :param glsl_fnc: name of GLSL function from library\n" | |||||
| " :type glsl_fnc: `str`\n" | |||||
| " :param args: list of GPULinks\n" | |||||
| " :type args: `list`\n" | |||||
| " :return: result of invocation\n" | |||||
| " :rtype: :class:`boolean`\n" | |||||
| ); | |||||
| static PyObject *pygpu_gpu_link(PyObject *UNUSED(self), PyObject *args, PyObject *kwds); | |||||
| PyDoc_STRVAR(pygpu_gpu_link_output_doc, | |||||
| "GPU_link_output(link)\n" | |||||
| "\n" | |||||
| " Return true if successed\n" | |||||
| "\n" | |||||
| " :param link: output link\n" | |||||
| " :type link: :class: `GPULink`\n" | |||||
| " :return: result of invocation\n" | |||||
| " :rtype: :class:`boolean`\n" | |||||
| ); | |||||
| static PyObject *pygpu_gpu_link_output(PyObject *UNUSED(self), PyObject *args, PyObject *kwds); | |||||
| PyDoc_STRVAR(pygpu_gpu_get_shader_node_classes_doc, | |||||
| "get_shader_node_classes()\n" | |||||
| "\n" | |||||
| " Return tuple of all registered classes derrived from ShaderNodes.\n" | |||||
| "\n" | |||||
| " :return: tuple of all registered classes derrived from ShaderNodes\n" | |||||
| " :rtype: :class:`tuple`\n" | |||||
| ); | |||||
| static PyObject *pygpu_get_shader_node_classes(PyObject *UNUSED(self), PyObject *args, PyObject *kwds); | |||||
| PyDoc_STRVAR(pygpu_add_engine_compatibility_doc, | |||||
| "add_engine_compatibility()\n" | |||||
| "\n" | |||||
| " Return call result\n" | |||||
| "\n" | |||||
| " :param engine: render engine name\n" | |||||
| " :type engine: `str`\n" | |||||
| " :param node: node name\n" | |||||
| " :type node: `str`\n" | |||||
| " :param param: additional parameter\n" | |||||
| " :type param: tuple (gpufunc, library) or str,\n" | |||||
| " where gpufunc - function to replace corresponding shader node function\n" | |||||
| " library - glsl text with str type\n" | |||||
| " :return: call result\n" | |||||
| " :rtype: :class: int\n" | |||||
| ); | |||||
| static PyObject *pygpu_add_engine_compatibility(PyObject *UNUSED(self), PyObject *args, PyObject *kwds); | |||||
| PyDoc_STRVAR(pygpu_remove_engine_compatibility_doc, | |||||
| "remove_engine_compatibility()\n" | |||||
| "\n" | |||||
| " Return call result\n" | |||||
| "\n" | |||||
| " :param engine: render engine name.\n" | |||||
| " :type engine: str\n" | |||||
| " :return: call result\n" | |||||
| " :rtype: :class: int\n" | |||||
| ); | |||||
| static PyObject * pygpu_remove_engine_compatibility(PyObject *UNUSED(self), PyObject *args, PyObject *kwds); | |||||
| static struct PyMethodDef BPy_GPU_methods[] = { | |||||
| {"GPU_link", (PyCFunction)pygpu_gpu_link, METH_VARARGS | METH_KEYWORDS, pygpu_gpu_link_doc}, | |||||
| {"GPU_link_output", (PyCFunction)pygpu_gpu_link_output, METH_VARARGS | METH_KEYWORDS, pygpu_gpu_link_output_doc}, | |||||
| {"get_shader_node_classes", (PyCFunction)pygpu_get_shader_node_classes, METH_NOARGS, pygpu_gpu_get_shader_node_classes_doc}, | |||||
| {"add_engine_compatibility", (PyCFunction)pygpu_add_engine_compatibility, METH_VARARGS | METH_KEYWORDS, pygpu_add_engine_compatibility_doc}, | |||||
| {"remove_engine_compatibility", (PyCFunction)pygpu_remove_engine_compatibility, METH_VARARGS | METH_KEYWORDS, pygpu_remove_engine_compatibility_doc}, | |||||
| {NULL, NULL, 0, NULL} | |||||
| }; | |||||
| static struct PyModuleDef gpumodule = { | static struct PyModuleDef gpumodule = { | ||||
| PyModuleDef_HEAD_INIT, | PyModuleDef_HEAD_INIT, | ||||
| "gpu", /* name of module */ | "gpu", /* name of module */ | ||||
| M_gpu_doc, /* module documentation */ | M_gpu_doc, /* module documentation */ | ||||
| -1, /* size of per-interpreter state of the module, | -1, /* size of per-interpreter state of the module, | ||||
| * or -1 if the module keeps state in global variables. */ | * or -1 if the module keeps state in global variables. */ | ||||
| NULL, NULL, NULL, NULL, NULL | BPy_GPU_methods, /* methods */ | ||||
| NULL, NULL, NULL, NULL | |||||
| }; | }; | ||||
| static PyObject *PyInit_gpu(void) | static PyObject *PyInit_gpu(void) | ||||
| { | { | ||||
| PyObject *m; | PyObject *m; | ||||
| m = PyModule_Create(&gpumodule); | m = PyModule_Create(&gpumodule); | ||||
| if (m == NULL) | if (m == NULL) | ||||
| ▲ Show 20 Lines • Show All 235 Lines • ▼ Show 20 Lines | static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) | ||||
| GPU_free_shader_export(shader); | GPU_free_shader_export(shader); | ||||
| return result; | return result; | ||||
| } | } | ||||
| static PyMethodDef meth_export_shader[] = { | static PyMethodDef meth_export_shader[] = { | ||||
| {"export_shader", (PyCFunction)GPU_export_shader, METH_VARARGS | METH_KEYWORDS, GPU_export_shader_doc} | {"export_shader", (PyCFunction)GPU_export_shader, METH_VARARGS | METH_KEYWORDS, GPU_export_shader_doc} | ||||
| }; | }; | ||||
| PyDoc_STRVAR(gpulink_doc, | |||||
| ".. class:: GPULink()\n" | |||||
| "\n" | |||||
| " This object adds possibility to create graphs for shader generation in Blender.\n" | |||||
| "\n" | |||||
| ); | |||||
| static PyObject *gpulink_str(GPUNodeLink *UNUSED(self)) | |||||
| { | |||||
| const char * buf = "gpulink"; | |||||
| return PyUnicode_FromStringAndSize(buf, sizeof (buf)); | |||||
| } | |||||
campbellbarton: This should at least give some unique information. eg:
return PyUnicode_FromFormat… | |||||
| static PyObject *gpulink_new(PyTypeObject *type, PyObject *args, PyObject *kwds); | |||||
| PyTypeObject gpulink_Type = { | |||||
| PyVarObject_HEAD_INIT(NULL, 0) | |||||
| /* For printing, in format "<module>.<name>" */ | |||||
| "GPULink", /* char *tp_name; */ | |||||
| sizeof(GPULink), /* int tp_basicsize; */ | |||||
| 0, /* tp_itemsize; For allocation */ | |||||
| /* Methods to implement standard operations */ | |||||
| NULL, /* destructor tp_dealloc; */ | |||||
| NULL, /* printfunc tp_print; */ | |||||
| NULL, /* getattrfunc tp_getattr; */ | |||||
| NULL, /* setattrfunc tp_setattr; */ | |||||
| NULL, /* cmpfunc tp_compare; */ | |||||
| (reprfunc)gpulink_str, /* reprfunc tp_repr; */ | |||||
| /* Method suites for standard classes */ | |||||
| NULL, /* PyNumberMethods *tp_as_number; */ | |||||
| NULL, /* PySequenceMethods *tp_as_sequence; */ | |||||
| NULL, /* PyMappingMethods *tp_as_mapping; */ | |||||
| /* More standard operations (here for binary compatibility) */ | |||||
| NULL, /* hashfunc tp_hash; */ | |||||
| NULL, /* ternaryfunc tp_call; */ | |||||
| NULL, /* reprfunc tp_str; */ | |||||
| NULL, /* getattrofunc tp_getattro; */ | |||||
| NULL, /* setattrofunc tp_setattro; */ | |||||
| /* Functions to access object as input/output buffer */ | |||||
| NULL, /* PyBufferProcs *tp_as_buffer; */ | |||||
| /*** Flags to define presence of optional/expanded features ***/ | |||||
| Py_TPFLAGS_DEFAULT, /* tp_flags */ | |||||
| gpulink_doc, /* char *tp_doc; Documentation string */ | |||||
| /*** Assigned meaning in release 2.0 ***/ | |||||
| /* call function for all accessible objects */ | |||||
| NULL, /* tp_traverse */ | |||||
| /* delete references to contained objects */ | |||||
| NULL, /* tp_clear */ | |||||
| /*** Assigned meaning in release 2.1 ***/ | |||||
| /*** rich comparisons ***/ | |||||
| NULL, /* richcmpfunc tp_richcompare; */ | |||||
| /*** weak reference enabler ***/ | |||||
| 0, /* long tp_weaklistoffset; */ | |||||
| /*** Added in release 2.2 ***/ | |||||
| /* Iterators */ | |||||
| NULL, /* getiterfunc tp_iter; */ | |||||
| NULL, /* iternextfunc tp_iternext; */ | |||||
| /*** Attribute descriptor and subclassing stuff ***/ | |||||
| NULL, /* struct PyMethodDef *tp_methods; */ | |||||
| NULL, /* struct PyMemberDef *tp_members; */ | |||||
| NULL, /* struct PyGetSetDef *tp_getset; */ | |||||
| NULL, /* struct _typeobject *tp_base; */ | |||||
| NULL, /* PyObject *tp_dict; */ | |||||
| NULL, /* descrgetfunc tp_descr_get; */ | |||||
| NULL, /* descrsetfunc tp_descr_set; */ | |||||
| 0, /* long tp_dictoffset; */ | |||||
| NULL, /* initproc tp_init; */ | |||||
| NULL, /* allocfunc tp_alloc; */ | |||||
| gpulink_new, /* newfunc tp_new; */ | |||||
| /* Low-level free-memory routine */ | |||||
| NULL, /* freefunc tp_free; */ | |||||
| /* For PyObject_IS_GC */ | |||||
| NULL, /* inquiry tp_is_gc; */ | |||||
| NULL, /* PyObject *tp_bases; */ | |||||
| /* method resolution order */ | |||||
| NULL, /* PyObject *tp_mro; */ | |||||
| NULL, /* PyObject *tp_cache; */ | |||||
| NULL, /* PyObject *tp_subclasses; */ | |||||
| NULL, /* PyObject *tp_weaklist; */ | |||||
| NULL | |||||
| }; | |||||
| static PyObject *create_gpu_uniform(float *ptr, int len) { | |||||
| GPULink * ret = (GPULink *) _PyObject_GC_New(&(gpulink_Type)); | |||||
| ret->desc.link = GPU_uniform(ret->uniform); | |||||
| memcpy(ret->uniform, ptr, len * sizeof(float)); | |||||
| return (PyObject *)ret; | |||||
| } | |||||
| static PyObject *create_gpu_link(void *link, GPULinkType type) | |||||
| { | |||||
| GPULink * ret = (GPULink *) _PyObject_GC_New(&(gpulink_Type)); | |||||
| ret->desc.link = link; | |||||
| ret->desc.type = type; | |||||
| return (PyObject *)ret; | |||||
| } | |||||
| static PyObject *create_gpulink_from_1_param(PyObject* obj) | |||||
| { | |||||
| GPUNodeLink *link; | |||||
| /* if GPUNodeStack */ | |||||
| GPUNodeStack *gns = PyC_RNA_AsPointer(obj, "GPUNodeStack"); | |||||
| if (gns) { | |||||
| return create_gpu_link(&gns->link, LINK_REF); | |||||
| } | |||||
| else { | |||||
| /* if GPUBuiltin */ | |||||
| PyErr_Clear(); | |||||
| if (PyLong_Check(obj)) { | |||||
Done Inline ActionsA common pattern in CPy is to do: if (!(((id = _PyLong_AsInt(item)) == -1) && PyErr_Occurred())) {
/* id is ok! */
}
else {
PyErr_Clear();
... continue parsing ...
}This supports any types that support the number interface. campbellbarton: A common pattern in CPy is to do:
if (!(((id = _PyLong_AsInt(item)) == -1) &&… | |||||
| long id = PyLong_AsLong(obj); | |||||
| link = GPU_builtin(id); | |||||
| return create_gpu_link(link, LINK); | |||||
| } | |||||
| else { | |||||
| /* if Vector */ | |||||
| PyErr_Clear(); | |||||
Done Inline ActionsThere won't be any errors here. campbellbarton: There won't be any errors here. | |||||
| if (PyObject_TypeCheck(obj, &vector_Type)) { | |||||
Done Inline Actionsmathutils_array_parse is preferred over exact type checks. Allows tuples/lists too. campbellbarton: `mathutils_array_parse` is preferred over exact type checks.
Allows tuples/lists too. | |||||
| VectorObject * v = (VectorObject *)obj; | |||||
| return create_gpu_uniform(v->vec, v->size); | |||||
| } | |||||
| else { | |||||
| /* if Matrix */ | |||||
| PyErr_Clear(); | |||||
| if (PyObject_TypeCheck(obj, &matrix_Type)) { | |||||
Done Inline ActionsAgain, should use mathutils_array_parse, see matrix construction in mathutils_Matrix.c campbellbarton: Again, should use `mathutils_array_parse`, see matrix construction in `mathutils_Matrix.c` | |||||
| MatrixObject *matrix = (MatrixObject *)obj; | |||||
| return create_gpu_uniform(matrix->matrix, matrix->num_col * matrix->num_row); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| PyErr_SetString(PyExc_TypeError, | |||||
| "gpu.GPULink(): " | |||||
| "Parameter type is not supported"); | |||||
| return NULL; | |||||
| } | |||||
| static PyObject *create_gpulink_from_2_param(PyObject* obj1, PyObject* obj2) | |||||
| { | |||||
| GPUNodeLink *link; | |||||
| /* gpu attribute */ | |||||
| if (PyLong_Check(obj1)) { | |||||
| long id = PyLong_AsLong(obj1); | |||||
Done Inline ActionsAgain, overly spesific type checks, see _PyLong_AsInt suggestion above. campbellbarton: Again, overly spesific type checks, see `_PyLong_AsInt` suggestion above. | |||||
| PyObject *name_ob = PyUnicode_AsUTF8String(obj2); | |||||
| if (name_ob) { | |||||
Done Inline ActionsIf this fails it wont be clear for the caller why. campbellbarton: If this fails it wont be clear for the caller why. | |||||
| char *name = PyBytes_AsString(name_ob); | |||||
| link = GPU_attribute(id, name); | |||||
| return create_gpu_link(link, LINK); | |||||
| } | |||||
| } | |||||
| else { | |||||
| Image *ima = PyC_RNA_AsPointer(obj1, "Image"); | |||||
| if (PyBool_Check(obj2)) { | |||||
Done Inline ActionsAgain very spesific parsing, (will fail on 0/1), suggest using PyC_ParseBool. campbellbarton: Again very spesific parsing, (will fail on 0/1), suggest using `PyC_ParseBool`. | |||||
| bool isdata = obj2 == Py_True; | |||||
| link = GPU_image(ima, NULL, isdata); | |||||
| return create_gpu_link(link, LINK); | |||||
| } | |||||
| } | |||||
| PyErr_SetString(PyExc_TypeError, | |||||
| "gpu.GPULink(): " | |||||
| "Parameter type is not supported"); | |||||
| return NULL; | |||||
| } | |||||
| static PyObject *gpulink_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |||||
| { | |||||
| if (kwds && PyDict_Size(kwds)) { | |||||
| PyErr_SetString(PyExc_TypeError, | |||||
| "GPULink(): " | |||||
| "takes no keyword args"); | |||||
| return NULL; | |||||
| } | |||||
| GPULink *self; | |||||
| switch (PyTuple_GET_SIZE(args)) { | |||||
| case 0: | |||||
| self = (GPULink *)((type ? (type)->tp_alloc(type, 0) : _PyObject_GC_New(&(gpulink_Type)))); | |||||
| if (self) { | |||||
| self->desc.link = NULL; | |||||
| self->desc.type = LINK; | |||||
| } | |||||
| break; | |||||
| case 1: | |||||
| self = (GPULink *)create_gpulink_from_1_param(PyTuple_GET_ITEM(args, 0)); | |||||
| break; | |||||
| case 2: | |||||
| self = (GPULink *)create_gpulink_from_2_param(PyTuple_GET_ITEM(args, 0), PyTuple_GET_ITEM(args, 1)); | |||||
| break; | |||||
| default: | |||||
| PyErr_SetString(PyExc_TypeError, | |||||
| "gpu.GPULink(): " | |||||
| "Too many arguments"); | |||||
| return NULL; | |||||
| } | |||||
| return (PyObject *) self; | |||||
| } | |||||
| static PyObject *pygpu_get_shader_node_classes(PyObject *UNUSED(self), PyObject *UNUSED(args), PyObject *UNUSED(kwds)) | |||||
| { | |||||
| ListBase *lb = nodeGetShaderNodeTypes(); | |||||
| int len = BLI_listbase_count(lb); | |||||
| PyObject *ret; | |||||
| if (len) | |||||
| ret = PyTuple_New(len); | |||||
| else | |||||
| return PyTuple_New(0); | |||||
| int i = 0; | |||||
| if (len) | |||||
| for (LinkData * ld = lb->first; ld; ld = ld->next) { | |||||
| if (((bNodeType *)ld->data)->ext.data) { | |||||
| PyTuple_SetItem(ret, i, ((bNodeType *)ld->data)->ext.data); | |||||
| i++; | |||||
| } | |||||
| else { | |||||
| PyObject *types = PyImport_ImportModule("bpy.types"); | |||||
| PyObject *t = PyObject_GetAttrString(types, ((bNodeType *)ld->data)->idname); | |||||
| ((bNodeType *)ld->data)->ext.data = t; | |||||
| PyTuple_SetItem(ret, i, t); | |||||
| i++; | |||||
| } | |||||
| } | |||||
| Py_INCREF(ret); | |||||
Done Inline ActionsNo need, its created with a single user. campbellbarton: No need, its created with a single user. | |||||
| return ret; | |||||
| } | |||||
| static PyObject *pygpu_remove_engine_compatibility(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) | |||||
| { | |||||
| if (kwds && PyDict_Size(kwds)) { | |||||
| PyErr_SetString(PyExc_TypeError, | |||||
| "remove_engine_compatibility(): " | |||||
| "takes no keyword args"); | |||||
| return NULL; | |||||
| } | |||||
| char *engine_name = NULL; | |||||
| char *node_name = NULL; | |||||
| if (!PyArg_UnpackTuple(args, "ss:pygpu_remove_engine_compatibility", 2, 2, &engine_name, &node_name)) | |||||
| Py_RETURN_FALSE; | |||||
Done Inline ActionsMust return NULL to properly raise an error. campbellbarton: Must return NULL to properly raise an error. | |||||
| if (0 == node_shader_compatibility_cache_remove(engine_name, node_name)) | |||||
| Py_RETURN_TRUE; | |||||
| Py_RETURN_FALSE; | |||||
| } | |||||
| static PyObject *pygpu_add_engine_compatibility(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) | |||||
| { | |||||
| if (kwds && PyDict_Size(kwds)) { | |||||
| PyErr_SetString(PyExc_TypeError, | |||||
| "add_engine_compatibility(): " | |||||
| "takes no keyword args"); | |||||
| return NULL; | |||||
| } | |||||
| char *engine_name = NULL; | |||||
| char *node_name = NULL; | |||||
| char *library = NULL; | |||||
| char *reuse_engine = NULL; | |||||
| PyObject *gpufunc = NULL; | |||||
| int argc = PyTuple_GET_SIZE(args); | |||||
| if (!(argc == 2 || argc == 3)) { | |||||
| PyErr_Format(PyExc_RuntimeError, | |||||
| "gpu.add_engine_compatibility(...) wrong number of arguments"); | |||||
| Py_RETURN_FALSE; | |||||
Done Inline ActionsAgain, must return NULL... also for all other false returns in this function. campbellbarton: Again, must return NULL... also for all other false returns in this function. | |||||
| } | |||||
| PyObject *engine_name_ob = PyUnicode_AsUTF8String(PyTuple_GET_ITEM(args, 0)); | |||||
| if (engine_name_ob) | |||||
| engine_name = PyBytes_AsString(engine_name_ob); | |||||
| PyObject *node_name_ob = PyUnicode_AsUTF8String(PyTuple_GET_ITEM(args, 1)); | |||||
| if (node_name_ob) | |||||
| node_name = PyBytes_AsString(node_name_ob); | |||||
| if (argc == 3) { | |||||
| PyObject* arg3 = PyTuple_GET_ITEM(args, 2); | |||||
| if (PyTuple_Check(arg3)) { | |||||
| gpufunc = PyTuple_GET_ITEM(arg3, 0); | |||||
| PyObject *library_ob = PyTuple_GET_ITEM(arg3, 1); | |||||
| if (Py_None != library_ob) { | |||||
| if (!(library_ob = PyUnicode_AsUTF8String(library_ob))) { | |||||
| PyErr_Format(PyExc_RuntimeError, | |||||
| "gpu.add_engine_compatibility(...) wrong type of library arg"); | |||||
| Py_RETURN_FALSE; | |||||
| } | |||||
| library = PyBytes_AsString(library_ob); | |||||
| } | |||||
| if (!PyCallable_Check(gpufunc)) { | |||||
| PyErr_Format(PyExc_RuntimeError, | |||||
| "gpu.add_engine_compatibility(...) wrong type of gpufunc argument"); | |||||
| Py_RETURN_FALSE; | |||||
| } | |||||
| } | |||||
| else if (PyUnicode_AsUTF8String(arg3)) { | |||||
| reuse_engine = PyBytes_AsString(PyUnicode_AsUTF8String(arg3)); | |||||
| } | |||||
| else { | |||||
| PyErr_Format(PyExc_RuntimeError, | |||||
| "gpu.add_engine_compatibility(...) wrong type of 3rd argument"); | |||||
| Py_RETURN_FALSE; | |||||
| } | |||||
| } | |||||
| bNodeType *nt = nodeTypeFind(node_name); | |||||
| if (!nt) | |||||
| Py_RETURN_FALSE; | |||||
| if (gpufunc) | |||||
| Py_INCREF(gpufunc); | |||||
| node_shader_compatibility_cache_add(engine_name, node_name, gpufunc, library, reuse_engine); | |||||
| Py_RETURN_TRUE; | |||||
| } | |||||
| static PyObject *pygpu_gpu_link(PyObject *UNUSED(self), PyObject *args, PyObject *UNUSED(kwds)) | |||||
| { | |||||
| PyObject *fnc_name; | |||||
| PyObject *fnc_args; | |||||
| int ret = 0; | |||||
| if (!PyArg_UnpackTuple(args, "so:GPU_link", 2, 2, &fnc_name, &fnc_args)) | |||||
| Py_RETURN_FALSE; | |||||
Done Inline ActionsAgain, must return NULL. campbellbarton: Again, must return NULL. | |||||
| void *mat = BPY_context_gpumat_get(); | |||||
| PyObject* str_obj = PyUnicode_AsUTF8String(fnc_name); | |||||
| char * name = PyBytes_AsString(str_obj); | |||||
| int len = PySequence_Size(fnc_args); | |||||
| GPULinkDesc **link_args = PyMem_Malloc(sizeof (GPULinkDesc *) * len); | |||||
| for (int i = 0; i < len; i++) { | |||||
| PyObject *item = PySequence_GetItem(fnc_args, i); | |||||
| if (!PyObject_TypeCheck(item, &gpulink_Type)) | |||||
| { | |||||
| PyErr_Format(PyExc_RuntimeError, | |||||
| "gpu.GPU_link(...) bad %d item of arguments", i); | |||||
| goto exit; | |||||
| } | |||||
| link_args[i] = &((GPULink *)item)->desc; | |||||
| } | |||||
| ret = GPU_link_py(mat, name, link_args, len); | |||||
| exit: | |||||
| PyMem_Free(link_args); | |||||
| if (ret) | |||||
| Py_RETURN_TRUE; | |||||
| else | |||||
| Py_RETURN_FALSE; | |||||
| } | |||||
| static PyObject *pygpu_gpu_link_output(PyObject *UNUSED(self), PyObject *args, PyObject *UNUSED(kwds)) | |||||
| { | |||||
| PyObject* link; | |||||
| if (!PyArg_UnpackTuple(args, "o:GPU_link", 1, 1, &link)) | |||||
| Py_RETURN_FALSE; | |||||
Done Inline ActionsAgain, must return NULL. campbellbarton: Again, must return NULL. | |||||
| if (!PyObject_TypeCheck(link, &gpulink_Type)) { | |||||
| PyErr_Format(PyExc_RuntimeError, | |||||
| "gpu.GPU_link_output(...) bad argument"); | |||||
| return NULL; | |||||
| } | |||||
| void *mat = BPY_context_gpumat_get(); | |||||
| GPULinkDesc* desc = &((GPULink *)link)->desc; | |||||
| GPUNodeLink * l; | |||||
| if (desc->type == LINK_REF) | |||||
| l = *((GPUNodeLink **)desc->link); | |||||
| else | |||||
| l = desc->link; | |||||
| GPU_material_output_link(mat, l); | |||||
| Py_RETURN_TRUE; | |||||
Done Inline ActionsThis function should probably return None, not a boolean. campbellbarton: This function should probably return None, not a boolean. | |||||
| } | |||||
Done Inline ActionsMultiple places in this patch use: PyUnicode_AsUTF8String, then PyBytes_AsString. This isn't needed (causes intermediate variable to be created which needs to be dec-ref'd after). Instead just call _PyUnicode_AsString. campbellbarton: Multiple places in this patch use:
`PyUnicode_AsUTF8String`, then `PyBytes_AsString`.
This… | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /* Initialize Module */ | /* Initialize Module */ | ||||
| PyObject *GPU_initPython(void) | PyObject *GPU_initPython(void) | ||||
| { | { | ||||
| PyObject *module; | PyObject *module; | ||||
| PyObject *submodule; | PyObject *submodule; | ||||
| PyObject *sys_modules = PyThreadState_GET()->interp->modules; | PyObject *sys_modules = PyThreadState_GET()->interp->modules; | ||||
| module = PyInit_gpu(); | module = PyInit_gpu(); | ||||
| PyModule_AddObject(module, "export_shader", (PyObject *)PyCFunction_New(meth_export_shader, NULL)); | PyModule_AddObject(module, "export_shader", (PyObject *)PyCFunction_New(meth_export_shader, NULL)); | ||||
| /* gpu.offscreen */ | /* gpu.offscreen */ | ||||
| PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen())); | PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen())); | ||||
| PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); | PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); | ||||
| Py_INCREF(submodule); | Py_INCREF(submodule); | ||||
| /* gpu.GPULink */ | |||||
| PyType_Ready(&gpulink_Type); | |||||
| PyModule_AddObject(module, gpulink_Type.tp_name, (PyObject *)&gpulink_Type); | |||||
| /* gpu.builtins */ | |||||
| PyModule_AddObject(module, "builtins", (submodule = BPyInit_gpu_builtins())); | |||||
| PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); | |||||
| Py_INCREF(submodule); | |||||
| /* gpu.custom_data */ | |||||
| PyModule_AddObject(module, "custom_data", (submodule = BPyInit_gpu_custom_data())); | |||||
| PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); | |||||
| Py_INCREF(submodule); | |||||
| PyDict_SetItem(PyImport_GetModuleDict(), PyModule_GetNameObject(module), module); | PyDict_SetItem(PyImport_GetModuleDict(), PyModule_GetNameObject(module), module); | ||||
| return module; | return module; | ||||
| } | } | ||||
| void BPY_parse_shader_node_compatibility(void *node_type) | |||||
| { | |||||
| bNodeType *nt = (bNodeType *)node_type; | |||||
| PyObject *python_type = nt->ext.data; | |||||
| if(python_type) { | |||||
| PyObject *t = PyObject_GetAttrString(python_type, "bl_compatibility"); | |||||
| if (t) { | |||||
| if (!PySet_Check(t)) { | |||||
| PyErr_Format(PyExc_RuntimeError, "bad format of bl_compatibility in %s", nt->idname); | |||||
| return; | |||||
| } | |||||
| PyObject* seq = PyObject_GetIter(t); | |||||
| PyObject* item; | |||||
| while((item=PyIter_Next(seq))) { | |||||
| PyObject *sitem; | |||||
| sitem = PyUnicode_AsUTF8String(item); | |||||
| if(!sitem) { | |||||
| Py_DECREF(seq); | |||||
| Py_DECREF(item); | |||||
| PyErr_SetString(PyExc_TypeError, "all items of bl_compatibility must be strings"); | |||||
| return; | |||||
| } | |||||
| char * name = PyBytes_AsString(sitem); | |||||
Done Inline ActionsAgain, no need for intermediate PyUnicode_AsUTF8String conversion. campbellbarton: Again, no need for intermediate `PyUnicode_AsUTF8String` conversion. | |||||
| node_type_add_compatibility(nt, name); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| bool BPY_call_shader_node_gpu_func(GPUMaterial *mat, void *gpufunc, void *node, GPUNodeStack *gpuin, GPUNodeStack *gpuout) | |||||
| { | |||||
| extern FunctionRNA rna_Node_gpufunc_func; | |||||
| ParameterList list; | |||||
| FunctionRNA *func; | |||||
| PointerRNA ptr; | |||||
| func = &rna_Node_gpufunc_func; /* RNA_struct_find_function(&ptr, "gpufunc"); */ | |||||
| RNA_pointer_create(NULL, &RNA_Node, node, &ptr); | |||||
| GPUNodeStackArray array_ins; | |||||
| array_ins.array = gpuin; | |||||
| GPUNodeStackArray *i = &array_ins; | |||||
| GPUNodeStackArray array_outs; | |||||
| array_outs.array = gpuout; | |||||
| GPUNodeStackArray *o = &array_outs; | |||||
| RNA_parameter_list_create(&list, &ptr, func); | |||||
| RNA_parameter_set_lookup(&list, "ins", &i); | |||||
| RNA_parameter_set_lookup(&list, "outs", &o); | |||||
| BPY_context_gpumat_set(mat); | |||||
| BPY_class_call_ex(NULL, gpufunc, &ptr, func, &list); | |||||
| bool *ret; | |||||
| RNA_parameter_get_lookup(&list, "ret", (void **)&ret); | |||||
| bool r = *ret; | |||||
| BPY_context_gpumat_set(NULL); | |||||
| RNA_parameter_list_free(&list); | |||||
| return r; | |||||
| } | |||||
| void BPY_parse_shader_node_gpu_code(void *node_type) | |||||
| { | |||||
| bNodeType *nt = (bNodeType *)node_type; | |||||
| PyObject *python_type = nt->ext.data; | |||||
| if(python_type) { | |||||
| PyObject *t = PyObject_GetAttrString(python_type, "bl_gpu_code"); | |||||
| if (t) { | |||||
| if (!PyDict_Check(t)) { | |||||
| PyErr_Format(PyExc_RuntimeError, "bad format of bl_gpu_code in %s", nt->idname); | |||||
| return; | |||||
| } | |||||
| if (!nt->gpu_glsl_code) { | |||||
| nt->gpu_glsl_code = BLI_ghash_str_new("gpu_glsl_code gh"); | |||||
| } | |||||
| PyObject *key, *value; | |||||
| Py_ssize_t pos = 0; | |||||
| while (PyDict_Next(t, &pos, &key, &value)) { | |||||
| PyObject *skey = PyUnicode_AsUTF8String(key); | |||||
| PyObject *svalue = PyUnicode_AsUTF8String(value); | |||||
| if (!skey || !svalue) { | |||||
Done Inline ActionsAgain, no need for intermediate PyUnicode_AsUTF8String conversion. campbellbarton: Again, no need for intermediate `PyUnicode_AsUTF8String` conversion. | |||||
| PyErr_Format(PyExc_RuntimeError, "bad format of bl_gpu_code in %s", nt->idname); | |||||
| return; | |||||
| } | |||||
| char * ckey = PyBytes_AsString(skey); | |||||
| char * cvalue = PyBytes_AsString(svalue); | |||||
| BLI_ghash_insert(nt->gpu_glsl_code, BLI_strdup(ckey), BLI_strdup(cvalue)); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
This should at least give some unique information. eg:
return PyUnicode_FromFormat("<GPUNodeLink at %p>", self);