Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpu/intern/gpu_shader_create_info.hh')
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh595
1 files changed, 595 insertions, 0 deletions
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
new file mode 100644
index 00000000000..ced7f7039e7
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -0,0 +1,595 @@
+/*
+ * 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.
+ *
+ * Some rule of thumb:
+ * - Do not include anything else than this file in each info file.
+ */
+
+#pragma once
+
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+#include "GPU_texture.h"
+
+namespace blender::gpu::shader {
+
+#ifndef GPU_SHADER_CREATE_INFO
+/* Helps intelisense / auto-completion. */
+# define GPU_SHADER_INTERFACE_INFO(_interface, _inst_name) \
+ StageInterfaceInfo _interface(#_interface, _inst_name); \
+ _interface
+# define GPU_SHADER_CREATE_INFO(_info) \
+ ShaderCreateInfo _info(#_info); \
+ _info
+#endif
+
+enum class Type {
+ FLOAT = 0,
+ VEC2,
+ VEC3,
+ VEC4,
+ MAT3,
+ MAT4,
+ UINT,
+ UVEC2,
+ UVEC3,
+ UVEC4,
+ INT,
+ IVEC2,
+ IVEC3,
+ IVEC4,
+ BOOL,
+};
+
+enum class BuiltinBits {
+ /** Allow getting barycentic coordinates inside the fragment shader. NOTE: emulated on OpenGL. */
+ BARYCENTRIC_COORD = (1 << 0),
+ FRAG_COORD = (1 << 2),
+ FRONT_FACING = (1 << 4),
+ GLOBAL_INVOCATION_ID = (1 << 5),
+ INSTANCE_ID = (1 << 6),
+ LAYER = (1 << 7),
+ LOCAL_INVOCATION_ID = (1 << 8),
+ LOCAL_INVOCATION_INDEX = (1 << 9),
+ NUM_WORK_GROUP = (1 << 10),
+ POINT_COORD = (1 << 11),
+ POINT_SIZE = (1 << 12),
+ PRIMITIVE_ID = (1 << 13),
+ VERTEX_ID = (1 << 14),
+ WORK_GROUP_ID = (1 << 15),
+ WORK_GROUP_SIZE = (1 << 16),
+};
+ENUM_OPERATORS(BuiltinBits, BuiltinBits::WORK_GROUP_SIZE);
+
+/* Samplers & images. */
+enum class ImageType {
+ /** Color samplers/image. */
+ FLOAT_BUFFER = 0,
+ FLOAT_1D,
+ FLOAT_1D_ARRAY,
+ FLOAT_2D,
+ FLOAT_2D_ARRAY,
+ FLOAT_3D,
+ FLOAT_CUBE,
+ FLOAT_CUBE_ARRAY,
+ INT_BUFFER,
+ INT_1D,
+ INT_1D_ARRAY,
+ INT_2D,
+ INT_2D_ARRAY,
+ INT_3D,
+ INT_CUBE,
+ INT_CUBE_ARRAY,
+ UINT_BUFFER,
+ UINT_1D,
+ UINT_1D_ARRAY,
+ UINT_2D,
+ UINT_2D_ARRAY,
+ UINT_3D,
+ UINT_CUBE,
+ UINT_CUBE_ARRAY,
+ /** Depth samplers (not supported as image). */
+ SHADOW_2D,
+ SHADOW_2D_ARRAY,
+ SHADOW_CUBE,
+ SHADOW_CUBE_ARRAY,
+ DEPTH_2D,
+ DEPTH_2D_ARRAY,
+ DEPTH_CUBE,
+ DEPTH_CUBE_ARRAY,
+};
+
+/* Storage qualifiers. */
+enum class Qualifier {
+ RESTRICT = (1 << 0),
+ READ_ONLY = (1 << 1),
+ WRITE_ONLY = (1 << 2),
+ QUALIFIER_MAX = (WRITE_ONLY << 1) - 1,
+};
+ENUM_OPERATORS(Qualifier, Qualifier::QUALIFIER_MAX);
+
+enum class Frequency {
+ BATCH = 0,
+ PASS,
+};
+
+/* Dual Source Blending Index. */
+enum class DualBlend {
+ NONE = 0,
+ SRC_0,
+ SRC_1,
+};
+
+/* Interpolation qualifiers. */
+enum class Interpolation {
+ SMOOTH = 0,
+ FLAT,
+ NO_PERSPECTIVE,
+};
+
+/** Input layout for geometry shader. */
+enum class InputLayout {
+ POINTS = 0,
+ LINES,
+ LINES_ADJACENCY,
+ TRIANGLES,
+ TRIANGLES_ADJACENCY,
+};
+
+/** Output layout for geometry shader. */
+enum class OutputLayout {
+ POINTS = 0,
+ LINE_STRIP,
+ TRIANGLE_STRIP,
+};
+
+struct StageInterfaceInfo {
+ struct InOut {
+ Interpolation interp;
+ Type type;
+ StringRefNull name;
+ };
+
+ StringRefNull name;
+ /** Name of the instance of the block (used to access).
+ * Can be empty string (i.e: "") only if not using geometry shader. */
+ StringRefNull instance_name;
+ /** List of all members of the interface. */
+ Vector<InOut> inouts;
+
+ StageInterfaceInfo(const char *name_, const char *instance_name_)
+ : name(name_), instance_name(instance_name_){};
+ ~StageInterfaceInfo(){};
+
+ using Self = StageInterfaceInfo;
+
+ Self &smooth(Type type, StringRefNull _name)
+ {
+ inouts.append({Interpolation::SMOOTH, type, _name});
+ return *(Self *)this;
+ }
+
+ Self &flat(Type type, StringRefNull _name)
+ {
+ inouts.append({Interpolation::FLAT, type, _name});
+ return *(Self *)this;
+ }
+
+ Self &no_perspective(Type type, StringRefNull _name)
+ {
+ inouts.append({Interpolation::NO_PERSPECTIVE, type, _name});
+ return *(Self *)this;
+ }
+};
+
+/**
+ * @brief Describe inputs & outputs, stage interfaces, resources and sources of a shader.
+ * If all data is correctly provided, this is all that is needed to create and compile
+ * a GPUShader.
+ *
+ * IMPORTANT: All strings are references only. Make sure all the strings used by a
+ * ShaderCreateInfo are not freed until it is consumed or deleted.
+ */
+struct ShaderCreateInfo {
+ /** Shader name for debugging. */
+ StringRefNull name_;
+ /** True if the shader is static and can be precompiled at compile time. */
+ bool do_static_compilation_ = false;
+ /** If true, all additionaly linked create info will be merged into this one. */
+ bool finalized_ = false;
+ /**
+ * Maximum length of all the resource names including each null terminator.
+ * Only for names used by gpu::ShaderInterface.
+ */
+ size_t interface_names_size_ = 0;
+ /** Only for compute shaders. */
+ int local_group_size_[3] = {0, 0, 0};
+
+ struct VertIn {
+ int index;
+ Type type;
+ StringRefNull name;
+ };
+ Vector<VertIn> vertex_inputs_;
+
+ struct GeomIn {
+ InputLayout layout;
+ };
+ GeomIn geom_in_;
+
+ struct GeomOut {
+ OutputLayout layout;
+ int max_vertices;
+ };
+ GeomOut geom_out_;
+
+ struct FragOut {
+ int index;
+ Type type;
+ DualBlend blend;
+ StringRefNull name;
+ };
+ Vector<FragOut> fragment_outputs_;
+
+ struct Sampler {
+ ImageType type;
+ eGPUSamplerState sampler;
+ StringRefNull name;
+ };
+
+ struct Image {
+ eGPUTextureFormat format;
+ ImageType type;
+ Qualifier qualifiers;
+ StringRefNull name;
+ };
+
+ struct UniformBuf {
+ StringRefNull type_name;
+ StringRefNull name;
+ };
+
+ struct StorageBuf {
+ Qualifier qualifiers;
+ StringRefNull type_name;
+ StringRefNull name;
+ };
+
+ struct Resource {
+ enum BindType {
+ UNIFORM_BUFFER = 0,
+ STORAGE_BUFFER,
+ SAMPLER,
+ IMAGE,
+ };
+
+ BindType bind_type;
+ int slot;
+ union {
+ Sampler sampler;
+ Image image;
+ UniformBuf uniformbuf;
+ StorageBuf storagebuf;
+ };
+
+ Resource(BindType type, int _slot) : bind_type(type), slot(_slot){};
+ };
+ /**
+ * Resources are grouped by frequency of change.
+ * Pass resources are meants to be valid for the whole pass.
+ * Batch resources can be changed in a more granular manner (per object/material).
+ * Mis-usage will only produce suboptimal performance.
+ */
+ Vector<Resource> pass_resources_, batch_resources_;
+
+ Vector<StageInterfaceInfo *> vertex_out_interfaces_;
+ Vector<StageInterfaceInfo *> geometry_out_interfaces_;
+
+ struct PushConst {
+ int index;
+ Type type;
+ StringRefNull name;
+ int array_size;
+ };
+
+ Vector<PushConst> push_constants_;
+
+ /* Sources for resources type definitions. */
+ Vector<StringRefNull> typedef_sources_;
+
+ StringRefNull vertex_source_, geometry_source_, fragment_source_, compute_source_;
+
+ Vector<std::array<StringRefNull, 2>> defines_;
+ /**
+ * Name of other infos to recursively merge with this one.
+ * No data slot must overlap otherwise we throw an error.
+ */
+ Vector<StringRefNull> additional_infos_;
+
+ public:
+ ShaderCreateInfo(const char *name) : name_(name){};
+ ~ShaderCreateInfo(){};
+
+ using Self = ShaderCreateInfo;
+
+ /* -------------------------------------------------------------------- */
+ /** \name Shaders in/outs (fixed function pipeline config)
+ * \{ */
+
+ Self &vertex_in(int slot, Type type, StringRefNull name)
+ {
+ vertex_inputs_.append({slot, type, name});
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &vertex_out(StageInterfaceInfo &interface)
+ {
+ vertex_out_interfaces_.append(&interface);
+ return *(Self *)this;
+ }
+
+ Self &geometry_layout(InputLayout layout_in, OutputLayout layout_out, int max_vertices)
+ {
+ geom_in_.layout = layout_in;
+ geom_out_.layout = layout_out;
+ geom_out_.max_vertices = max_vertices;
+ return *(Self *)this;
+ }
+
+ /* Only needed if geometry shader is enabled. */
+ Self &geometry_out(StageInterfaceInfo &interface)
+ {
+ geometry_out_interfaces_.append(&interface);
+ return *(Self *)this;
+ }
+
+ Self &fragment_out(int slot, Type type, StringRefNull name, DualBlend blend = DualBlend::NONE)
+ {
+ fragment_outputs_.append({slot, type, blend, name});
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Resources bindings points
+ * \{ */
+
+ Self &uniform_buf(int slot,
+ StringRefNull type_name,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS)
+ {
+ Resource res(Resource::BindType::UNIFORM_BUFFER, slot);
+ res.uniformbuf.name = name;
+ res.uniformbuf.type_name = type_name;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &storage_buf(int slot,
+ Qualifier qualifiers,
+ StringRefNull type_name,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS)
+ {
+ Resource res(Resource::BindType::STORAGE_BUFFER, slot);
+ res.storagebuf.qualifiers = qualifiers;
+ res.storagebuf.type_name = type_name;
+ res.storagebuf.name = name;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &image(int slot,
+ eGPUTextureFormat format,
+ Qualifier qualifiers,
+ ImageType type,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS)
+ {
+ Resource res(Resource::BindType::IMAGE, slot);
+ res.image.format = format;
+ res.image.qualifiers = qualifiers;
+ res.image.type = type;
+ res.image.name = name;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &sampler(int slot,
+ ImageType type,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS,
+ eGPUSamplerState sampler = (eGPUSamplerState)-1)
+ {
+ Resource res(Resource::BindType::SAMPLER, slot);
+ res.sampler.type = type;
+ res.sampler.name = name;
+ res.sampler.sampler = sampler;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Shader Source
+ * \{ */
+
+ Self &vertex_source(StringRefNull filename)
+ {
+ vertex_source_ = filename;
+ return *(Self *)this;
+ }
+
+ Self &geometry_source(StringRefNull filename)
+ {
+ geometry_source_ = filename;
+ return *(Self *)this;
+ }
+
+ Self &fragment_source(StringRefNull filename)
+ {
+ fragment_source_ = filename;
+ return *(Self *)this;
+ }
+
+ Self &compute_source(StringRefNull filename)
+ {
+ compute_source_ = filename;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Push constants
+ *
+ * Data managed by GPUShader. Can be set through uniform functions. Must be less than 128bytes.
+ * One slot represents 4bytes. Each element needs to have enough empty space left after it.
+ * example:
+ * [0] = PUSH_CONSTANT(MAT4, "ModelMatrix"),
+ * ---- 16 slots occupied by ModelMatrix ----
+ * [16] = PUSH_CONSTANT(VEC4, "color"),
+ * ---- 4 slots occupied by color ----
+ * [20] = PUSH_CONSTANT(BOOL, "srgbToggle"),
+ * The maximum slot is 31.
+ * \{ */
+
+ Self &push_constant(int slot, Type type, StringRefNull name, int array_size = 0)
+ {
+ BLI_assert_msg(name.find("[") == -1,
+ "Array syntax is forbidden for push constants."
+ "Use the array_size parameter instead.");
+ push_constants_.append({slot, type, name, array_size});
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Compute shaders Local Group Size
+ * \{ */
+
+ Self &local_group_size(int x, int y = 1, int z = 1)
+ {
+ local_group_size_[0] = x;
+ local_group_size_[1] = y;
+ local_group_size_[2] = z;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Defines
+ * \{ */
+
+ Self &define(StringRefNull name, StringRefNull value = "")
+ {
+ defines_.append({name, value});
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Defines
+ * \{ */
+
+ Self &do_static_compilation(bool value)
+ {
+ do_static_compilation_ = value;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Additional Create Info
+ *
+ * Used to share parts of the infos that are common to many shaders.
+ * \{ */
+
+ Self &additional_info(StringRefNull info_name0,
+ StringRefNull info_name1 = "",
+ StringRefNull info_name2 = "",
+ StringRefNull info_name3 = "",
+ StringRefNull info_name4 = "")
+ {
+ additional_infos_.append(info_name0);
+ if (!info_name1.is_empty()) {
+ additional_infos_.append(info_name1);
+ }
+ if (!info_name2.is_empty()) {
+ additional_infos_.append(info_name2);
+ }
+ if (!info_name3.is_empty()) {
+ additional_infos_.append(info_name3);
+ }
+ if (!info_name4.is_empty()) {
+ additional_infos_.append(info_name4);
+ }
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Typedef Sources
+ *
+ * Some resource declarations might need some special structure defined.
+ * Adding a file using typedef_source will include it before the resource
+ * and interface definitions.
+ * \{ */
+
+ Self &typedef_source(StringRefNull filename)
+ {
+ typedef_sources_.append(filename);
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Recursive evaluation.
+ *
+ * Flatten all dependency so that this descriptor contains all the data from the additional
+ * descriptors. This avoids tedious traversal in shader source creation.
+ * \{ */
+
+ /* WARNING: Recursive. */
+ void finalize();
+
+ /** \} */
+};
+
+} // namespace blender::gpu::shader