From 8fb2ff458ba579dba08bfdf57d043ad158b5db07 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 17 Jan 2022 14:32:03 +0100 Subject: 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 --- .../blender/gpu/intern/gpu_shader_create_info.cc | 173 +++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 source/blender/gpu/intern/gpu_shader_create_info.cc (limited to 'source/blender/gpu/intern/gpu_shader_create_info.cc') diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc new file mode 100644 index 00000000000..e4e5034026f --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_create_info.cc @@ -0,0 +1,173 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Descriptior type used to define shader structure, resources and interfaces. + */ + +#include "BLI_map.hh" +#include "BLI_set.hh" +#include "BLI_string_ref.hh" + +#include "GPU_shader.h" +#include "GPU_texture.h" + +#include "gpu_shader_create_info.hh" +#include "gpu_shader_create_info_private.hh" + +#undef GPU_SHADER_INTERFACE_INFO +#undef GPU_SHADER_CREATE_INFO + +namespace blender::gpu::shader { + +using CreateInfoDictionnary = Map; +using InterfaceDictionnary = Map; + +static CreateInfoDictionnary *g_create_infos = nullptr; +static InterfaceDictionnary *g_interfaces = nullptr; + +void ShaderCreateInfo::finalize() +{ + if (finalized_) { + return; + } + finalized_ = true; + + for (auto &info_name : additional_infos_) { + const ShaderCreateInfo &info = *reinterpret_cast( + gpu_shader_create_info_get(info_name.c_str())); + + /* Recursive. */ + const_cast(info).finalize(); + + interface_names_size_ += info.interface_names_size_; + + vertex_inputs_.extend(info.vertex_inputs_); + fragment_outputs_.extend(info.fragment_outputs_); + vertex_out_interfaces_.extend(info.vertex_out_interfaces_); + geometry_out_interfaces_.extend(info.geometry_out_interfaces_); + + push_constants_.extend(info.push_constants_); + defines_.extend(info.defines_); + + batch_resources_.extend(info.batch_resources_); + pass_resources_.extend(info.pass_resources_); + typedef_sources_.extend(info.typedef_sources_); + + if (info.local_group_size_[0] != 0) { + BLI_assert(local_group_size_[0] == 0); + for (int i = 0; i < 3; i++) { + local_group_size_[i] = info.local_group_size_[i]; + } + } + if (!info.vertex_source_.is_empty()) { + BLI_assert(vertex_source_.is_empty()); + vertex_source_ = info.vertex_source_; + } + if (!info.geometry_source_.is_empty()) { + BLI_assert(geometry_source_.is_empty()); + geometry_source_ = info.geometry_source_; + } + if (!info.fragment_source_.is_empty()) { + BLI_assert(fragment_source_.is_empty()); + fragment_source_ = info.fragment_source_; + } + if (!info.compute_source_.is_empty()) { + BLI_assert(compute_source_.is_empty()); + compute_source_ = info.compute_source_; + } + + do_static_compilation_ = do_static_compilation_ || info.do_static_compilation_; + } +} + +} // namespace blender::gpu::shader + +using namespace blender::gpu::shader; + +void gpu_shader_create_info_init() +{ + g_create_infos = new CreateInfoDictionnary(); + g_interfaces = new InterfaceDictionnary(); + +#define GPU_SHADER_INTERFACE_INFO(_interface, _inst_name) \ + auto *ptr_##_interface = new StageInterfaceInfo(#_interface, _inst_name); \ + auto &_interface = *ptr_##_interface; \ + g_interfaces->add_new(#_interface, ptr_##_interface); \ + _interface + +#define GPU_SHADER_CREATE_INFO(_info) \ + auto *ptr_##_info = new ShaderCreateInfo(#_info); \ + auto &_info = *ptr_##_info; \ + g_create_infos->add_new(#_info, ptr_##_info); \ + _info + +/* Declare, register and construct the infos. */ +#include "gpu_shader_create_info_list.hh" + +/* Baked shader data appended to create infos. */ +/* TODO(jbakker): should call a function with a callback. so we could switch implementations. We + * cannot compile bf_gpu twice.*/ +#ifdef GPU_RUNTIME +# include "gpu_shader_baked.hh" +#endif + + /* TEST */ + // gpu_shader_create_info_compile_all(); +} + +void gpu_shader_create_info_exit() +{ + for (auto *value : g_create_infos->values()) { + delete value; + } + delete g_create_infos; + + for (auto *value : g_interfaces->values()) { + delete value; + } + delete g_interfaces; +} + +bool gpu_shader_create_info_compile_all() +{ + for (ShaderCreateInfo *info : g_create_infos->values()) { + if (info->do_static_compilation_) { + // printf("Compiling %s: ... \n", info->name_.c_str()); + GPUShader *shader = GPU_shader_create_from_info( + reinterpret_cast(info)); + if (shader == nullptr) { + printf("Compilation %s Failed\n", info->name_.c_str()); + return false; + } + GPU_shader_free(shader); + // printf("Success\n"); + } + } + return true; +} + +/* Runtime create infos are not registered in the dictionnary and cannot be searched. */ +const GPUShaderCreateInfo *gpu_shader_create_info_get(const char *info_name) +{ + ShaderCreateInfo *info = g_create_infos->lookup(info_name); + return reinterpret_cast(info); +} -- cgit v1.2.3