Commit: 9bc678969aaef5e2343d9362648e9a633d1b6e5e Author: Germano Cavalcante Date: Tue Apr 12 18:28:27 2022 -0300 Branches: master https://developer.blender.org/rB9bc678969aaef5e2343d9362648e9a633d1b6e5e
pyGPU: Port 'StageInterfaceInfo' and 'ShaderCreateInfo' types In order to allow GLSL Cross Compilation across platforms, expose in Python the `GPUShaderCreateInfo` strategy as detailed in https://wiki.blender.org/wiki/EEVEE_%26_Viewport/GPU_Module/GLSL_Cross_Compilation The new features can be listed as follows: ``` >>> gpu.types.GPUShaderCreateInfo. define( fragment_out( fragment_source( push_constant( sampler( typedef_source( uniform_buf( vertex_in( vertex_out( vertex_source( >>> gpu.types.GPUStageInterfaceInfo. flat( name no_perspective( smooth( >>> gpu.shader.create_from_info( ``` Reviewed By: fclem, campbellbarton Differential Revision: https://developer.blender.org/D14497 =================================================================== M source/blender/gpu/GPU_shader.h M source/blender/gpu/intern/gpu_shader.cc M source/blender/gpu/intern/gpu_shader_create_info.cc M source/blender/gpu/intern/gpu_shader_create_info.hh M source/blender/python/generic/py_capi_utils.h M source/blender/python/gpu/CMakeLists.txt M source/blender/python/gpu/gpu_py_shader.c M source/blender/python/gpu/gpu_py_shader.h A source/blender/python/gpu/gpu_py_shader_create_info.cc M source/blender/python/gpu/gpu_py_types.c =================================================================== diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index c0c25022836..eed7685bf01 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -56,6 +56,7 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info); GPUShader *GPU_shader_create_from_info_name(const char *info_name); const GPUShaderCreateInfo *GPU_shader_create_info_get(const char *info_name); +bool GPU_shader_create_info_check_error(const GPUShaderCreateInfo *_info, char r_error[128]); struct GPU_ShaderCreateFromArray_Params { const char **vert, **geom, **frag, **defs; diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index b434cfbbb0e..227525bd5d3 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -249,6 +249,19 @@ const GPUShaderCreateInfo *GPU_shader_create_info_get(const char *info_name) return gpu_shader_create_info_get(info_name); } +bool GPU_shader_create_info_check_error(const GPUShaderCreateInfo *_info, char r_error[128]) +{ + using namespace blender::gpu::shader; + const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info); + std::string error = info.check_error(); + if (error.length() == 0) { + return true; + } + + BLI_strncpy(r_error, error.c_str(), 128); + return false; +} + GPUShader *GPU_shader_create_from_info_name(const char *info_name) { using namespace blender::gpu::shader; @@ -270,28 +283,10 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) GPU_debug_group_begin(GPU_DEBUG_SHADER_COMPILATION_GROUP); - /* At least a vertex shader and a fragment shader are required, or only a compute shader. */ - if (info.compute_source_.is_empty()) { - if (info.vertex_source_.is_empty()) { - printf("Missing vertex shader in %s.\n", info.name_.c_str()); - } - if (info.fragment_source_.is_empty()) { - printf("Missing fragment shader in %s.\n", info.name_.c_str()); - } - BLI_assert(!info.vertex_source_.is_empty() && !info.fragment_source_.is_empty()); - } - else { - if (!info.vertex_source_.is_empty()) { - printf("Compute shader has vertex_source_ shader attached in %s.\n", info.name_.c_str()); - } - if (!info.geometry_source_.is_empty()) { - printf("Compute shader has geometry_source_ shader attached in %s.\n", info.name_.c_str()); - } - if (!info.fragment_source_.is_empty()) { - printf("Compute shader has fragment_source_ shader attached in %s.\n", info.name_.c_str()); - } - BLI_assert(info.vertex_source_.is_empty() && info.geometry_source_.is_empty() && - info.fragment_source_.is_empty()); + std::string error = info.check_error(); + if (error.length()) { + printf(error.c_str()); + BLI_assert(true); } Shader *shader = GPUBackend::get()->shader_alloc(info.name_.c_str()); diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc index 0dd82d4ea44..6e82201b424 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.cc +++ b/source/blender/gpu/intern/gpu_shader_create_info.cc @@ -136,6 +136,34 @@ void ShaderCreateInfo::finalize() } } +std::string ShaderCreateInfo::check_error() const +{ + std::string error; + + /* At least a vertex shader and a fragment shader are required, or only a compute shader. */ + if (this->compute_source_.is_empty()) { + if (this->vertex_source_.is_empty()) { + error += "Missing vertex shader in " + this->name_ + ".\n"; + } + if (this->fragment_source_.is_empty()) { + error += "Missing fragment shader in " + this->name_ + ".\n"; + } + } + else { + if (!this->vertex_source_.is_empty()) { + error += "Compute shader has vertex_source_ shader attached in" + this->name_ + ".\n"; + } + if (!this->geometry_source_.is_empty()) { + error += "Compute shader has geometry_source_ shader attached in" + this->name_ + ".\n"; + } + if (!this->fragment_source_.is_empty()) { + error += "Compute shader has fragment_source_ shader attached in" + this->name_ + ".\n"; + } + } + + return error; +} + void ShaderCreateInfo::validate(const ShaderCreateInfo &other_info) { if (!auto_resource_location_) { diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh index 51008993353..dfd73219d1b 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.hh +++ b/source/blender/gpu/intern/gpu_shader_create_info.hh @@ -787,6 +787,8 @@ struct ShaderCreateInfo { /* WARNING: Recursive. */ void finalize(); + std::string check_error() const; + /** Error detection that some backend compilers do not complain about. */ void validate(const ShaderCreateInfo &other_info); diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 0f94b264159..ecb6db2b82c 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -8,6 +8,10 @@ #ifndef __PY_CAPI_UTILS_H__ #define __PY_CAPI_UTILS_H__ +#ifdef __cplusplus +extern "C" { +#endif + #include "BLI_sys_types.h" #include "BLI_utildefines_variadic.h" @@ -273,3 +277,7 @@ bool PyC_StructFmt_type_is_byte(char format); bool PyC_StructFmt_type_is_bool(char format); #endif /* __PY_CAPI_UTILS_H__ */ + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/python/gpu/CMakeLists.txt b/source/blender/python/gpu/CMakeLists.txt index 644bbd18173..e726cb7883d 100644 --- a/source/blender/python/gpu/CMakeLists.txt +++ b/source/blender/python/gpu/CMakeLists.txt @@ -29,6 +29,7 @@ set(SRC gpu_py_offscreen.c gpu_py_platform.c gpu_py_select.c + gpu_py_shader_create_info.cc gpu_py_shader.c gpu_py_state.c gpu_py_texture.c diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index c74b3e173d1..cdcf22df7a1 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -831,6 +831,38 @@ static PyObject *pygpu_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyOb return r_dict; } +PyDoc_STRVAR(pygpu_shader_create_from_info_doc, + ".. function:: create_from_info(shader_info)\n" + "\n" + " Create shader from a GPUShaderCreateInfo.\n" + "\n" + " :param shader_info: GPUShaderCreateInfo\n" + " :type shader_info: :class:`bpy.types.GPUShaderCreateInfo`\n" + " :return: Shader object corresponding to the given name.\n" + " :rtype: :class:`bpy.types.GPUShader`\n"); +static PyObject *pygpu_shader_create_from_info(BPyGPUShader *UNUSED(self), + BPyGPUShaderCreateInfo *o) +{ + if (!BPyGPUShaderCreateInfo_Check(o)) { + PyErr_Format(PyExc_TypeError, "Expected a GPUShaderCreateInfo, got %s", Py_TYPE(o)->tp_name); + return NULL; + } + + char error[128]; + if (!GPU_shader_create_info_check_error(o->info, error)) { + PyErr_SetString(PyExc_Exception, error); + return NULL; + } + + GPUShader *shader = GPU_shader_create_from_info(o->info); + if (!shader) { + PyErr_SetString(PyExc_Exception, "Shader Compile Error, see console for more details"); + return NULL; + } + + return BPyGPUShader_CreatePyObject(shader, false); +} + static struct PyMethodDef pygpu_shader_module__tp_methods[] = { {"unbind", (PyCFunction)pygpu_shader_unbind, METH_NOARGS, pygpu_shader_unbind_doc}, {"from_builtin", @@ -841,6 +873,10 @@ static struct PyMethodDef pygpu_shader_module__tp_methods[] = { (PyCFunction)pygpu_shader_code_from_builtin, METH_O, pygpu_shader_code_from_builtin_doc}, + {"create_from_info", + (PyCFunction)pygpu_shader_create_from_info, + METH_O, + pygpu_shader_create_from_info_doc}, {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/python/gpu/gpu_py_shader.h b/source/blender/python/gpu/gpu_py_shader.h index eb4810efeac..b5944c4b3a0 100644 --- a/source/blender/python/gpu/gpu_py_shader.h +++ b/source/blender/python/gpu/gpu_py_shader.h @@ -6,6 +6,12 @@ #pragma once +/* Make sure that there is always a reference count for PyObjects of type String as the strings are + * passed by reference in the #GPUStageInterfaceInfo and #GPUShaderCreateInfo APIs. */ +#define USE_GPU_PY_REFERENCES + +/* gpu_py_shader.c */ + extern PyTypeObject BPyGPUShader_Type; #define BPyGPUShader_Check(v) (Py_TYPE(v) == &BPyGPUShader_Type) @@ -18,3 +24,44 @@ typedef struct BPyGPUShader { PyObject *BPyGPUShader_CreatePyObject(struct GPUShader *shader, bool is_builtin); PyObject *bpygpu_shader_init(void); + +#ifdef __cplusplus +extern "C" { +#endif + +/* gpu_py_shader_create_info.cc */ + +extern PyTypeObject BPyGPUShaderCreateInfo_Type; +extern PyTypeObject BPyGPUStageInterfaceInfo_Type; + +#define BPyGPUShaderCreateInfo_Check(v) (Py_TYPE(v) == &BPyGPUShaderCreateInfo_Type) +#define BPyGPUStageInterfaceInfo_Check(v) (Py_TYPE(v) == &BPyGPUStageInterfaceInfo_Type) + +typedef struct BPyGPUStageInterfaceInfo { + PyObject_VAR_HEAD + struct GPUStageInterfaceInfo *interface; +#ifdef USE_GPU_PY_REFERENCES + /* Just to keep a user to prevent freeing buf's we're using. */ + PyObject *references; +#endif +} BPyGPUStageInterfaceInfo; + +typedef struct BPyGPUShaderCreateInfo { + PyObject_VAR_HEAD + struct GPUShaderCreateInfo *info; +#ifdef USE_GPU_PY_REFERENCES + /* Just to keep a user to prevent freeing buf's we're using. */ + PyObject *vertex_source; + PyObject *fragment_source; + PyObject *typedef_source; + PyObject *references; +#endif + size_t constants_total_size; +} BPyGPUShaderCreateInfo; + +PyObject *BPyGPUStageInterfaceInfo_CreatePyObject(struct GPUStageInterfaceInfo *interface); +PyObject *BPyGPUShaderCreateInfo_CreatePyObject(struct GPUShaderCreateInfo *info); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/python/gpu/gpu_py_shader_create_info.cc b/source/blender/python/gpu/gpu_py_shader_create_info.cc new file mode 100644 index 00000000000..caf71ad5980 --- /dev/null +++ b/source/blender/python/gpu @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
