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
This commit is contained in:
parent
359b6baf32
commit
9bc678969a
Notes:
blender-bot
2023-02-14 05:12:59 +01:00
Referenced by commit 927cb5bfac
, Cleanup: separate format-units for Python argument parsing
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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_) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -59,6 +59,12 @@ PyObject *bpygpu_types_init(void)
|
|||
if (PyType_Ready(&BPyGPUUniformBuf_Type) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (PyType_Ready(&BPyGPUShaderCreateInfo_Type) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (PyType_Ready(&BPyGPUStageInterfaceInfo_Type) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyModule_AddType(submodule, &BPyGPU_BufferType);
|
||||
PyModule_AddType(submodule, &BPyGPUVertFormat_Type);
|
||||
|
@ -70,6 +76,8 @@ PyObject *bpygpu_types_init(void)
|
|||
PyModule_AddType(submodule, &BPyGPUTexture_Type);
|
||||
PyModule_AddType(submodule, &BPyGPUFrameBuffer_Type);
|
||||
PyModule_AddType(submodule, &BPyGPUUniformBuf_Type);
|
||||
PyModule_AddType(submodule, &BPyGPUShaderCreateInfo_Type);
|
||||
PyModule_AddType(submodule, &BPyGPUStageInterfaceInfo_Type);
|
||||
|
||||
return submodule;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue