diff options
author | Jeroen Bakker <jbakker> | 2022-01-17 16:32:03 +0300 |
---|---|---|
committer | Jeroen Bakker <jeroen@blender.org> | 2022-01-17 16:32:28 +0300 |
commit | 8fb2ff458ba579dba08bfdf57d043ad158b5db07 (patch) | |
tree | e6324c08c69de3e8ed34c1f85d0b2982fa1d38ed /source/blender/gpu/intern/gpu_shader.cc | |
parent | 08822801acf648d23791fa308ec8c1c26f86963e (diff) |
GPUShaderCreateInfo for interface abstraction
This is a first part of the Shader Create Info system could be.
A shader create info provides a way to define shader structure, resources
and interfaces. This makes for a quick way to provide backend agnostic
binding informations while also making shader variations easy to declare.
- Clear source input (only one file). Cleans up the GPU api since we can create a
shader from one descriptor
- Resources and interfaces are generated by the backend (much simpler than parsing).
- Bindings are explicit from position in the array.
- GPUShaderInterface becomes a trivial translation of enums and string copy.
- No external dependency to third party lib.
- Cleaner code, less fragmentation of resources in several libs.
- Easy to modify / extend at runtime.
- no parser involve, very easy to code.
- Does not hold any data, can be static and kept on disc.
- Could hold precompiled bytecode for static shaders.
This also includes a new global dependency system.
GLSL shaders can include other sources by using #pragma BLENDER_REQUIRE(...).
This patch already migrated several builtin shaders. Other shaders should be migrated
one at a time, and could be done inside master.
There is a new compile directive `WITH_GPU_SHADER_BUILDER` this is an optional
directive for linting shaders to increase turn around time.
What is remaining:
- pyGPU API {T94975}
- Migration of other shaders. This could be a community effort.
Reviewed By: jbakker
Maniphest Tasks: T94975
Differential Revision: https://developer.blender.org/D13360
Diffstat (limited to 'source/blender/gpu/intern/gpu_shader.cc')
-rw-r--r-- | source/blender/gpu/intern/gpu_shader.cc | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 3f5a639d2a0..3b41e804fd4 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -31,10 +31,32 @@ #include "gpu_backend.hh" #include "gpu_context_private.hh" +#include "gpu_shader_create_info.hh" +#include "gpu_shader_create_info_private.hh" +#include "gpu_shader_dependency_private.h" #include "gpu_shader_private.hh" +#include <string> + extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[]; +namespace blender::gpu { + +std::string Shader::defines_declare(const shader::ShaderCreateInfo &info) const +{ + std::string defines; + for (const auto &def : info.defines_) { + defines += "#define "; + defines += def[0]; + defines += " "; + defines += def[1]; + defines += "\n"; + } + return defines; +} + +} // namespace blender::gpu + using namespace blender; using namespace blender::gpu; @@ -59,6 +81,8 @@ static void standard_defines(Vector<const char *> &sources) BLI_assert(sources.size() == 0); /* Version needs to be first. Exact values will be added by implementation. */ sources.append("version"); + /* Define to identify code usage in shading language. */ + sources.append("#define GPU_SHADER\n"); /* some useful defines to detect GPU type */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { sources.append("#define GPU_ATI\n"); @@ -225,6 +249,174 @@ GPUShader *GPU_shader_create_compute(const char *computecode, shname); } +GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) +{ + using namespace blender::gpu::shader; + const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info); + + const_cast<ShaderCreateInfo &>(info).finalize(); + + /* 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()); + } + + Shader *shader = GPUBackend::get()->shader_alloc(info.name_.c_str()); + + std::string defines = shader->defines_declare(info); + std::string resources = shader->resources_declare(info); + char *shader_shared_utils = nullptr; + + defines += "#define USE_GPU_SHADER_CREATE_INFO\n"; + + Vector<char *> typedefs; + for (auto filename : info.typedef_sources_) { + typedefs.append(gpu_shader_dependency_get_source(filename.c_str())); + } + if (!typedefs.is_empty()) { + shader_shared_utils = gpu_shader_dependency_get_source("gpu_shader_shared_utils.h"); + } + + if (!info.vertex_source_.is_empty()) { + uint32_t builtins = 0; + std::string interface = shader->vertex_interface_declare(info); + char *code = gpu_shader_dependency_get_resolved_source(info.vertex_source_.c_str(), &builtins); + + Vector<const char *> sources; + standard_defines(sources); + sources.append("#define GPU_VERTEX_SHADER\n"); + if (!info.geometry_source_.is_empty()) { + sources.append("#define USE_GEOMETRY_SHADER\n"); + } + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(interface.c_str()); + sources.append(code); + + shader->vertex_shader_from_glsl(sources); + + free(code); + } + + if (!info.fragment_source_.is_empty()) { + uint32_t builtins = 0; + std::string interface = shader->fragment_interface_declare(info); + char *code = gpu_shader_dependency_get_resolved_source(info.fragment_source_.c_str(), + &builtins); + + Vector<const char *> sources; + standard_defines(sources); + sources.append("#define GPU_FRAGMENT_SHADER\n"); + if (!info.geometry_source_.is_empty()) { + sources.append("#define USE_GEOMETRY_SHADER\n"); + } + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(interface.c_str()); + sources.append(code); + + shader->fragment_shader_from_glsl(sources); + + free(code); + } + + if (!info.geometry_source_.is_empty()) { + uint32_t builtins = 0; + std::string interface = shader->geometry_interface_declare(info); + std::string layout = shader->geometry_layout_declare(info); + char *code = gpu_shader_dependency_get_resolved_source(info.geometry_source_.c_str(), + &builtins); + + Vector<const char *> sources; + standard_defines(sources); + sources.append("#define GPU_GEOMETRY_SHADER\n"); + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(layout.c_str()); + sources.append(interface.c_str()); + sources.append(code); + + shader->geometry_shader_from_glsl(sources); + + free(code); + } + + if (!info.compute_source_.is_empty()) { + uint32_t builtins = 0; + char *code = gpu_shader_dependency_get_resolved_source(info.compute_source_.c_str(), + &builtins); + + Vector<const char *> sources; + standard_defines(sources); + sources.append("#define GPU_COMPUTE_SHADER\n"); + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(code); + + shader->compute_shader_from_glsl(sources); + + free(code); + } + + for (auto *types : typedefs) { + free(types); + } + + if (shader_shared_utils) { + free(shader_shared_utils); + } + + if (!shader->finalize(&info)) { + delete shader; + return nullptr; + } + + return wrap(shader); +} + GPUShader *GPU_shader_create_from_python(const char *vertcode, const char *fragcode, const char *geomcode, |