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:
authorClément Foucault <foucault.clem@gmail.com>2022-04-14 19:47:58 +0300
committerClément Foucault <foucault.clem@gmail.com>2022-04-14 19:47:58 +0300
commit80859a6cb2726a39fb22cb49f06e0355dc9390a7 (patch)
treefd3f8ead5a247a79ea11e4aacc720843bbc5e2c2 /source/blender/gpu
parent66dc4d4efb88ecf2d18bfa08ab9c43b024ebd2fb (diff)
GPU: Make nodetree GLSL Codegen render engine agnostic
This commit removes all EEVEE specific code from the `gpu_shader_material*.glsl` files. It defines a clear interface to evaluate the closure nodes leaving more flexibility to the render engine. Some of the long standing workaround are fixed: - bump mapping support is no longer duplicating a lot of node and is instead compiled into a function call. - bump rewiring to Normal socket is no longer needed as we now use a global `g_data.N` for that. Closure sampling with upstread weight eval is now supported if the engine needs it. This also makes all the material GLSL sources use `GPUSource` for better debugging experience. The `GPUFunction` parsing now happens in `GPUSource` creation. The whole `GPUCodegen` now uses the `ShaderCreateInfo` and is object type agnostic. Is has also been rewritten in C++. This patch changes a view behavior for EEVEE: - Mix shader node factor imput is now clamped. - Tangent Vector displacement behavior is now matching cycles. - The chosen BSDF used for SSR might change. - Hair shading may have very small changes on very large hairs when using hair polygon stripes. - ShaderToRGB node will remove any SSR and SSS form a shader. - SSS radius input now is no longer a scaling factor but defines an average radius. The SSS kernel "shape" (radii) are still defined by the socket default values. Appart from the listed changes no other regressions are expected.
Diffstat (limited to 'source/blender/gpu')
-rw-r--r--source/blender/gpu/CMakeLists.txt4
-rw-r--r--source/blender/gpu/GPU_material.h126
-rw-r--r--source/blender/gpu/GPU_uniform_buffer.h4
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c1123
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc825
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h28
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c2
-rw-r--r--source/blender/gpu/intern/gpu_material.c339
-rw-r--r--source/blender/gpu/intern/gpu_material_library.c904
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h27
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c117
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h54
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc5
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder_stubs.cc5
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh9
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc325
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl173
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl18
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl26
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_background.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl38
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl31
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl101
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl15
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl7
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl53
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl64
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl39
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl46
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl26
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl14
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl69
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl14
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl12
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl36
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl18
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl23
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl248
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl37
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl27
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl30
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl84
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl20
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl23
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl17
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl32
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl19
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl24
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl22
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl15
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl23
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl24
80 files changed, 2353 insertions, 3184 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 3e12426acdc..98d15a1024c 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -46,7 +46,7 @@ set(SRC
intern/gpu_batch_utils.c
intern/gpu_buffers.c
intern/gpu_capabilities.cc
- intern/gpu_codegen.c
+ intern/gpu_codegen.cc
intern/gpu_compute.cc
intern/gpu_context.cc
intern/gpu_debug.cc
@@ -57,7 +57,6 @@ set(SRC
intern/gpu_index_buffer.cc
intern/gpu_init_exit.c
intern/gpu_material.c
- intern/gpu_material_library.c
intern/gpu_matrix.cc
intern/gpu_node_graph.c
intern/gpu_platform.cc
@@ -312,6 +311,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_glass.glsl
shaders/material/gpu_shader_material_glossy.glsl
shaders/material/gpu_shader_material_hair_info.glsl
+ shaders/material/gpu_shader_material_hair.glsl
shaders/material/gpu_shader_material_hash.glsl
shaders/material/gpu_shader_material_holdout.glsl
shaders/material/gpu_shader_material_hue_sat_val.glsl
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 9b63d0feb1e..f38b9681ad7 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -13,6 +13,7 @@
#include "BLI_sys_types.h" /* for bool */
+#include "GPU_shader.h" /* for GPUShaderCreateInfo */
#include "GPU_texture.h" /* for eGPUSamplerState */
#ifdef __cplusplus
@@ -58,8 +59,6 @@ typedef enum eGPUType {
GPU_TEX2D = 1002,
GPU_TEX2D_ARRAY = 1003,
GPU_TEX3D = 1004,
- GPU_SHADOW2D = 1005,
- GPU_TEXCUBE = 1006,
/* GLSL Struct types */
GPU_CLOSURE = 1007,
@@ -68,35 +67,30 @@ typedef enum eGPUType {
GPU_ATTR = 3001,
} eGPUType;
-typedef enum eGPUBuiltin {
- GPU_VIEW_MATRIX = (1 << 0),
- GPU_OBJECT_MATRIX = (1 << 1),
- GPU_INVERSE_VIEW_MATRIX = (1 << 2),
- GPU_INVERSE_OBJECT_MATRIX = (1 << 3),
- GPU_VIEW_POSITION = (1 << 4),
- GPU_VIEW_NORMAL = (1 << 5),
- GPU_OBJECT_COLOR = (1 << 6),
- GPU_AUTO_BUMPSCALE = (1 << 7),
- GPU_CAMERA_TEXCO_FACTORS = (1 << 8),
- GPU_PARTICLE_SCALAR_PROPS = (1 << 9),
- GPU_PARTICLE_LOCATION = (1 << 10),
- GPU_PARTICLE_VELOCITY = (1 << 11),
- GPU_PARTICLE_ANG_VELOCITY = (1 << 12),
- GPU_LOC_TO_VIEW_MATRIX = (1 << 13),
- GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
- GPU_OBJECT_INFO = (1 << 15),
- GPU_BARYCENTRIC_TEXCO = (1 << 16),
- GPU_BARYCENTRIC_DIST = (1 << 17),
- GPU_WORLD_NORMAL = (1 << 18),
-} eGPUBuiltin;
-
-typedef enum eGPUMatFlag {
+typedef enum eGPUMaterialFlag {
GPU_MATFLAG_DIFFUSE = (1 << 0),
- GPU_MATFLAG_GLOSSY = (1 << 1),
- GPU_MATFLAG_REFRACT = (1 << 2),
- GPU_MATFLAG_SSS = (1 << 3),
- GPU_MATFLAG_BARYCENTRIC = (1 << 4),
-} eGPUMatFlag;
+ GPU_MATFLAG_SUBSURFACE = (1 << 1),
+ GPU_MATFLAG_GLOSSY = (1 << 2),
+ GPU_MATFLAG_REFRACT = (1 << 3),
+ GPU_MATFLAG_EMISSION = (1 << 4),
+ GPU_MATFLAG_TRANSPARENT = (1 << 5),
+ GPU_MATFLAG_HOLDOUT = (1 << 6),
+ GPU_MATFLAG_SHADER_TO_RGBA = (1 << 7),
+ GPU_MATFLAG_AO = (1 << 8),
+
+ GPU_MATFLAG_OBJECT_INFO = (1 << 10),
+ GPU_MATFLAG_AOV = (1 << 11),
+
+ GPU_MATFLAG_BARYCENTRIC = (1 << 20),
+
+ /* Tells the render engine the material was just compiled or updated. */
+ GPU_MATFLAG_UPDATED = (1 << 29),
+
+ /* HACK(fclem) Tells the environment texture node to not bail out if empty. */
+ GPU_MATFLAG_LOOKDEV_HACK = (1 << 30),
+} eGPUMaterialFlag;
+
+ENUM_OPERATORS(eGPUMaterialFlag, GPU_MATFLAG_LOOKDEV_HACK);
typedef struct GPUNodeStack {
eGPUType type;
@@ -110,6 +104,7 @@ typedef struct GPUNodeStack {
typedef enum eGPUMaterialStatus {
GPU_MAT_FAILED = 0,
+ GPU_MAT_CREATED,
GPU_MAT_QUEUED,
GPU_MAT_SUCCESS,
} eGPUMaterialStatus;
@@ -119,12 +114,19 @@ typedef enum eGPUVolumeDefaultValue {
GPU_VOLUME_DEFAULT_1,
} eGPUVolumeDefaultValue;
-typedef void (*GPUMaterialEvalCallbackFn)(GPUMaterial *mat,
- int options,
- const char **vert_code,
- const char **geom_code,
- const char **frag_lib,
- const char **defines);
+typedef struct GPUCodegenOutput {
+ char *attr_load;
+ /* Nodetree functions calls. */
+ char *displacement;
+ char *surface;
+ char *volume;
+ char *thickness;
+ char *material_functions;
+
+ GPUShaderCreateInfo *create_info;
+} GPUCodegenOutput;
+
+typedef void (*GPUCodegenCallbackFn)(void *thunk, GPUMaterial *mat, GPUCodegenOutput *codegen);
GPUNodeLink *GPU_constant(const float *num);
GPUNodeLink *GPU_uniform(const float *num);
@@ -143,7 +145,12 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro
GPUNodeLink *GPU_volume_grid(GPUMaterial *mat,
const char *name,
eGPUVolumeDefaultValue default_value);
-GPUNodeLink *GPU_builtin(eGPUBuiltin builtin);
+/**
+ * Create an implementation defined differential calculation of a float function.
+ * The given function should return a float.
+ * The result will be a vec2 containing dFdx and dFdy result of that function.
+ */
+GPUNodeLink *GPU_differentiate_float_function(const char *function_name);
bool GPU_link(GPUMaterial *mat, const char *name, ...);
bool GPU_stack_link(GPUMaterial *mat,
@@ -157,10 +164,26 @@ GPUNodeLink *GPU_uniformbuf_link_out(struct GPUMaterial *mat,
struct GPUNodeStack *stack,
int index);
-void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
+void GPU_material_output_surface(GPUMaterial *material, GPUNodeLink *link);
+void GPU_material_output_volume(GPUMaterial *material, GPUNodeLink *link);
+void GPU_material_output_displacement(GPUMaterial *material, GPUNodeLink *link);
+void GPU_material_output_thickness(GPUMaterial *material, GPUNodeLink *link);
+
void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash);
-void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]);
+/**
+ * Wrap a part of the material graph into a function. You need then need to call the function by
+ * using something like #GPU_differentiate_float_function.
+ * \note This replace the link by a constant to break the link with the main graph.
+ * \param return_type: sub function return type. Output is cast to this type.
+ * \param link: link to use as the sub function output.
+ * \return the name of the generated function.
+ */
+char *GPU_material_split_sub_function(GPUMaterial *material,
+ eGPUType return_type,
+ GPUNodeLink **link);
+
+bool GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]);
struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material,
int sample_len,
struct GPUTexture **tex_profile);
@@ -180,15 +203,13 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene,
struct Material *ma,
struct bNodeTree *ntree,
struct ListBase *gpumaterials,
- const void *engine_type,
- int options,
- bool is_volume_shader,
- const char *vert_code,
- const char *geom_code,
- const char *frag_lib,
- const char *defines,
const char *name,
- GPUMaterialEvalCallbackFn callback);
+ uint64_t shader_uuid,
+ bool is_volume_shader,
+ bool is_lookdev,
+ GPUCodegenCallbackFn callback,
+ void *thunk);
+
void GPU_material_compile(GPUMaterial *mat);
void GPU_material_free(struct ListBase *gpumaterial);
@@ -205,6 +226,7 @@ struct Material *GPU_material_get_material(GPUMaterial *material);
* Return true if the material compilation has not yet begin or begin.
*/
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat);
+void GPU_material_status_set(GPUMaterial *mat, eGPUMaterialStatus status);
struct GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material);
/**
@@ -215,13 +237,15 @@ struct GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material);
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs);
struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void);
+bool GPU_material_is_volume_shader(GPUMaterial *mat);
bool GPU_material_has_surface_output(GPUMaterial *mat);
bool GPU_material_has_volume_output(GPUMaterial *mat);
-bool GPU_material_is_volume_shader(GPUMaterial *mat);
-
-void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag);
-bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag);
+void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag);
+bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag);
+eGPUMaterialFlag GPU_material_flag(const GPUMaterial *mat);
+bool GPU_material_recalc_flag_get(GPUMaterial *mat);
+uint64_t GPU_material_uuid_get(GPUMaterial *mat);
void GPU_pass_cache_init(void);
void GPU_pass_cache_garbage_collect(void);
diff --git a/source/blender/gpu/GPU_uniform_buffer.h b/source/blender/gpu/GPU_uniform_buffer.h
index c47be05a646..f78719d1963 100644
--- a/source/blender/gpu/GPU_uniform_buffer.h
+++ b/source/blender/gpu/GPU_uniform_buffer.h
@@ -42,8 +42,8 @@ void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot);
void GPU_uniformbuf_unbind(GPUUniformBuf *ubo);
void GPU_uniformbuf_unbind_all(void);
-#define GPU_UBO_BLOCK_NAME "nodeTree"
-#define GPU_ATTRIBUTE_UBO_BLOCK_NAME "uniformAttrs"
+#define GPU_UBO_BLOCK_NAME "node_tree"
+#define GPU_ATTRIBUTE_UBO_BLOCK_NAME "unf_attrs"
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
deleted file mode 100644
index e462308d3ee..00000000000
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ /dev/null
@@ -1,1123 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later
- * Copyright 2005 Blender Foundation. All rights reserved. */
-
-/** \file
- * \ingroup gpu
- *
- * Convert material node-trees to GLSL.
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_customdata_types.h"
-#include "DNA_image_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
-#include "BLI_ghash.h"
-#include "BLI_hash_mm2a.h"
-#include "BLI_link_utils.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "PIL_time.h"
-
-#include "BKE_material.h"
-
-#include "GPU_capabilities.h"
-#include "GPU_material.h"
-#include "GPU_shader.h"
-#include "GPU_uniform_buffer.h"
-#include "GPU_vertex_format.h"
-
-#include "BLI_sys_types.h" /* for intptr_t support */
-
-#include "gpu_codegen.h"
-#include "gpu_material_library.h"
-#include "gpu_node_graph.h"
-
-#include <stdarg.h>
-#include <string.h>
-
-extern char datatoc_gpu_shader_codegen_lib_glsl[];
-extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
-
-/* -------------------- GPUPass Cache ------------------ */
-/**
- * Internal shader cache: This prevent the shader recompilation / stall when
- * using undo/redo AND also allows for GPUPass reuse if the Shader code is the
- * same for 2 different Materials. Unused GPUPasses are free by Garbage collection.
- */
-
-/* Only use one linked-list that contains the GPUPasses grouped by hash. */
-static GPUPass *pass_cache = NULL;
-static SpinLock pass_cache_spin;
-
-static uint32_t gpu_pass_hash(const char *frag_gen, const char *defs, ListBase *attributes)
-{
- BLI_HashMurmur2A hm2a;
- BLI_hash_mm2a_init(&hm2a, 0);
- BLI_hash_mm2a_add(&hm2a, (uchar *)frag_gen, strlen(frag_gen));
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attributes) {
- BLI_hash_mm2a_add(&hm2a, (uchar *)attr->name, strlen(attr->name));
- }
- if (defs) {
- BLI_hash_mm2a_add(&hm2a, (uchar *)defs, strlen(defs));
- }
-
- return BLI_hash_mm2a_end(&hm2a);
-}
-
-/* Search by hash only. Return first pass with the same hash.
- * There is hash collision if (pass->next && pass->next->hash == hash) */
-static GPUPass *gpu_pass_cache_lookup(uint32_t hash)
-{
- BLI_spin_lock(&pass_cache_spin);
- /* Could be optimized with a Lookup table. */
- for (GPUPass *pass = pass_cache; pass; pass = pass->next) {
- if (pass->hash == hash) {
- BLI_spin_unlock(&pass_cache_spin);
- return pass;
- }
- }
- BLI_spin_unlock(&pass_cache_spin);
- return NULL;
-}
-
-/* Check all possible passes with the same hash. */
-static GPUPass *gpu_pass_cache_resolve_collision(GPUPass *pass,
- const char *vert,
- const char *geom,
- const char *frag,
- const char *defs,
- uint32_t hash)
-{
- BLI_spin_lock(&pass_cache_spin);
- /* Collision, need to `strcmp` the whole shader. */
- for (; pass && (pass->hash == hash); pass = pass->next) {
- if ((defs != NULL) && (!STREQ(pass->defines, defs))) { /* Pass */
- }
- else if ((geom != NULL) && (!STREQ(pass->geometrycode, geom))) { /* Pass */
- }
- else if ((!STREQ(pass->fragmentcode, frag) == 0) && (STREQ(pass->vertexcode, vert))) {
- BLI_spin_unlock(&pass_cache_spin);
- return pass;
- }
- }
- BLI_spin_unlock(&pass_cache_spin);
- return NULL;
-}
-
-/* GLSL code generation */
-
-static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *tmp, int id)
-{
- char name[1024];
-
- BLI_snprintf(name, sizeof(name), "%s%d", tmp, id);
-
- if (from == to) {
- BLI_dynstr_append(ds, name);
- }
- else if (to == GPU_FLOAT) {
- if (from == GPU_VEC4) {
- BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.2126, 0.7152, 0.0722))", name);
- }
- else if (from == GPU_VEC3) {
- BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name);
- }
- else if (from == GPU_VEC2) {
- BLI_dynstr_appendf(ds, "%s.r", name);
- }
- }
- else if (to == GPU_VEC2) {
- if (from == GPU_VEC4) {
- BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, %s.a)", name, name, name, name);
- }
- else if (from == GPU_VEC3) {
- BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, 1.0)", name, name, name);
- }
- else if (from == GPU_FLOAT) {
- BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name);
- }
- }
- else if (to == GPU_VEC3) {
- if (from == GPU_VEC4) {
- BLI_dynstr_appendf(ds, "%s.rgb", name);
- }
- else if (from == GPU_VEC2) {
- BLI_dynstr_appendf(ds, "vec3(%s.r, %s.r, %s.r)", name, name, name);
- }
- else if (from == GPU_FLOAT) {
- BLI_dynstr_appendf(ds, "vec3(%s, %s, %s)", name, name, name);
- }
- }
- else if (to == GPU_VEC4) {
- if (from == GPU_VEC3) {
- BLI_dynstr_appendf(ds, "vec4(%s, 1.0)", name);
- }
- else if (from == GPU_VEC2) {
- BLI_dynstr_appendf(ds, "vec4(%s.r, %s.r, %s.r, %s.g)", name, name, name, name);
- }
- else if (from == GPU_FLOAT) {
- BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name);
- }
- }
- else if (to == GPU_CLOSURE) {
- if (from == GPU_VEC4) {
- BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name);
- }
- else if (from == GPU_VEC3) {
- BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name);
- }
- else if (from == GPU_VEC2) {
- BLI_dynstr_appendf(ds, "closure_emission(%s.rrr)", name);
- }
- else if (from == GPU_FLOAT) {
- BLI_dynstr_appendf(ds, "closure_emission(vec3(%s, %s, %s))", name, name, name);
- }
- }
- else {
- BLI_dynstr_append(ds, name);
- }
-}
-
-static void codegen_print_datatype(DynStr *ds, const eGPUType type, float *data)
-{
- int i;
-
- BLI_dynstr_appendf(ds, "%s(", gpu_data_type_to_string(type));
-
- for (i = 0; i < type; i++) {
- BLI_dynstr_appendf(ds, "%.12f", data[i]);
- if (i == type - 1) {
- BLI_dynstr_append(ds, ")");
- }
- else {
- BLI_dynstr_append(ds, ", ");
- }
- }
-}
-
-static const char *gpu_builtin_name(eGPUBuiltin builtin)
-{
- if (builtin == GPU_VIEW_MATRIX) {
- return "unfviewmat";
- }
- if (builtin == GPU_OBJECT_MATRIX) {
- return "unfobmat";
- }
- if (builtin == GPU_INVERSE_VIEW_MATRIX) {
- return "unfinvviewmat";
- }
- if (builtin == GPU_INVERSE_OBJECT_MATRIX) {
- return "unfinvobmat";
- }
- if (builtin == GPU_LOC_TO_VIEW_MATRIX) {
- return "unflocaltoviewmat";
- }
- if (builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX) {
- return "unfinvlocaltoviewmat";
- }
- if (builtin == GPU_VIEW_POSITION) {
- return "varposition";
- }
- if (builtin == GPU_WORLD_NORMAL) {
- return "varwnormal";
- }
- if (builtin == GPU_VIEW_NORMAL) {
- return "varnormal";
- }
- if (builtin == GPU_OBJECT_COLOR) {
- return "unfobjectcolor";
- }
- if (builtin == GPU_AUTO_BUMPSCALE) {
- return "unfobautobumpscale";
- }
- if (builtin == GPU_CAMERA_TEXCO_FACTORS) {
- return "unfcameratexfactors";
- }
- if (builtin == GPU_PARTICLE_SCALAR_PROPS) {
- return "unfparticlescalarprops";
- }
- if (builtin == GPU_PARTICLE_LOCATION) {
- return "unfparticleco";
- }
- if (builtin == GPU_PARTICLE_VELOCITY) {
- return "unfparticlevel";
- }
- if (builtin == GPU_PARTICLE_ANG_VELOCITY) {
- return "unfparticleangvel";
- }
- if (builtin == GPU_OBJECT_INFO) {
- return "unfobjectinfo";
- }
- if (builtin == GPU_BARYCENTRIC_TEXCO) {
- return "unfbarycentrictex";
- }
- if (builtin == GPU_BARYCENTRIC_DIST) {
- return "unfbarycentricdist";
- }
- return "";
-}
-
-static void codegen_set_unique_ids(GPUNodeGraph *graph)
-{
- int id = 1;
-
- LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
- /* set id for unique names of uniform variables */
- input->id = id++;
- }
-
- LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
- /* set id for unique names of tmp variables storing output */
- output->id = id++;
- }
- }
-}
-
-/**
- * It will create an UBO for GPUMaterial if there is any GPU_DYNAMIC_UBO.
- */
-static int codegen_process_uniforms_functions(GPUMaterial *material,
- DynStr *ds,
- GPUNodeGraph *graph)
-{
- const char *name;
- int builtins = 0;
- ListBase ubo_inputs = {NULL, NULL};
-
- /* Textures */
- LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph->textures) {
- if (tex->colorband) {
- BLI_dynstr_appendf(ds, "uniform sampler1DArray %s;\n", tex->sampler_name);
- }
- else if (tex->tiled_mapping_name[0]) {
- BLI_dynstr_appendf(ds, "uniform sampler2DArray %s;\n", tex->sampler_name);
- BLI_dynstr_appendf(ds, "uniform sampler1DArray %s;\n", tex->tiled_mapping_name);
- }
- else {
- BLI_dynstr_appendf(ds, "uniform sampler2D %s;\n", tex->sampler_name);
- }
- }
-
- /* Volume Grids */
- LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) {
- BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", grid->sampler_name);
- BLI_dynstr_appendf(ds, "uniform mat4 %s = mat4(0.0);\n", grid->transform_name);
- }
-
- /* Print other uniforms */
-
- LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
- if (input->source == GPU_SOURCE_BUILTIN) {
- /* only define each builtin uniform/varying once */
- if (!(builtins & input->builtin)) {
- builtins |= input->builtin;
- name = gpu_builtin_name(input->builtin);
-
- if (BLI_str_startswith(name, "unf")) {
- BLI_dynstr_appendf(ds, "uniform %s %s;\n", gpu_data_type_to_string(input->type), name);
- }
- else {
- BLI_dynstr_appendf(ds, "in %s %s;\n", gpu_data_type_to_string(input->type), name);
- }
- }
- }
- else if (input->source == GPU_SOURCE_STRUCT) {
- /* Add other struct here if needed. */
- BLI_dynstr_appendf(ds, "Closure strct%d = CLOSURE_DEFAULT;\n", input->id);
- }
- else if (input->source == GPU_SOURCE_UNIFORM) {
- if (!input->link) {
- /* We handle the UBOuniforms separately. */
- BLI_addtail(&ubo_inputs, BLI_genericNodeN(input));
- }
- }
- else if (input->source == GPU_SOURCE_CONSTANT) {
- BLI_dynstr_appendf(
- ds, "const %s cons%d = ", gpu_data_type_to_string(input->type), input->id);
- codegen_print_datatype(ds, input->type, input->vec);
- BLI_dynstr_append(ds, ";\n");
- }
- }
- }
-
- /* Handle the UBO block separately. */
- if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) {
- GPU_material_uniform_buffer_create(material, &ubo_inputs);
-
- /* Inputs are sorted */
- BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME);
-
- LISTBASE_FOREACH (LinkData *, link, &ubo_inputs) {
- GPUInput *input = (GPUInput *)(link->data);
- BLI_dynstr_appendf(ds, " %s unf%d;\n", gpu_data_type_to_string(input->type), input->id);
- }
- BLI_dynstr_append(ds, "};\n");
- BLI_freelistN(&ubo_inputs);
- }
-
- /* Generate the uniform attribute UBO if necessary. */
- if (!BLI_listbase_is_empty(&graph->uniform_attrs.list)) {
- BLI_dynstr_append(ds, "\nstruct UniformAttributes {\n");
- LISTBASE_FOREACH (GPUUniformAttr *, attr, &graph->uniform_attrs.list) {
- BLI_dynstr_appendf(ds, " vec4 attr%d;\n", attr->id);
- }
- BLI_dynstr_append(ds, "};\n");
- BLI_dynstr_appendf(ds, "layout (std140) uniform %s {\n", GPU_ATTRIBUTE_UBO_BLOCK_NAME);
- BLI_dynstr_append(ds, " UniformAttributes uniform_attrs[DRW_RESOURCE_CHUNK_LEN];\n");
- BLI_dynstr_append(ds, "};\n");
- BLI_dynstr_append(ds, "#define GET_UNIFORM_ATTR(name) (uniform_attrs[resource_id].name)\n");
- }
-
- BLI_dynstr_append(ds, "\n");
-
- return builtins;
-}
-
-static void codegen_declare_tmps(DynStr *ds, GPUNodeGraph *graph)
-{
- LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- /* declare temporary variables for node output storage */
- LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
- if (output->type == GPU_CLOSURE) {
- BLI_dynstr_appendf(ds, " Closure tmp%d;\n", output->id);
- }
- else {
- BLI_dynstr_appendf(ds, " %s tmp%d;\n", gpu_data_type_to_string(output->type), output->id);
- }
- }
- }
- BLI_dynstr_append(ds, "\n");
-}
-
-static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph)
-{
- LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- BLI_dynstr_appendf(ds, " %s(", node->name);
-
- LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
- if (input->source == GPU_SOURCE_TEX) {
- BLI_dynstr_append(ds, input->texture->sampler_name);
- }
- else if (input->source == GPU_SOURCE_TEX_TILED_MAPPING) {
- BLI_dynstr_append(ds, input->texture->tiled_mapping_name);
- }
- else if (input->source == GPU_SOURCE_VOLUME_GRID) {
- BLI_dynstr_append(ds, input->volume_grid->sampler_name);
- }
- else if (input->source == GPU_SOURCE_VOLUME_GRID_TRANSFORM) {
- BLI_dynstr_append(ds, input->volume_grid->transform_name);
- }
- else if (input->source == GPU_SOURCE_OUTPUT) {
- codegen_convert_datatype(
- ds, input->link->output->type, input->type, "tmp", input->link->output->id);
- }
- else if (input->source == GPU_SOURCE_BUILTIN) {
- /* TODO(fclem): get rid of that. */
- if (input->builtin == GPU_INVERSE_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "viewinv");
- }
- else if (input->builtin == GPU_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "viewmat");
- }
- else if (input->builtin == GPU_CAMERA_TEXCO_FACTORS) {
- BLI_dynstr_append(ds, "camtexfac");
- }
- else if (input->builtin == GPU_LOC_TO_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "localtoviewmat");
- }
- else if (input->builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "invlocaltoviewmat");
- }
- else if (input->builtin == GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds, "barycentricDist");
- }
- else if (input->builtin == GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "barytexco");
- }
- else if (input->builtin == GPU_OBJECT_MATRIX) {
- BLI_dynstr_append(ds, "objmat");
- }
- else if (input->builtin == GPU_OBJECT_INFO) {
- BLI_dynstr_append(ds, "ObjectInfo");
- }
- else if (input->builtin == GPU_OBJECT_COLOR) {
- BLI_dynstr_append(ds, "ObjectColor");
- }
- else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) {
- BLI_dynstr_append(ds, "objinv");
- }
- else if (input->builtin == GPU_VIEW_POSITION) {
- BLI_dynstr_append(ds, "viewposition");
- }
- else if (input->builtin == GPU_VIEW_NORMAL) {
- BLI_dynstr_append(ds, "facingnormal");
- }
- else if (input->builtin == GPU_WORLD_NORMAL) {
- BLI_dynstr_append(ds, "facingwnormal");
- }
- else {
- BLI_dynstr_append(ds, gpu_builtin_name(input->builtin));
- }
- }
- else if (input->source == GPU_SOURCE_STRUCT) {
- BLI_dynstr_appendf(ds, "strct%d", input->id);
- }
- else if (input->source == GPU_SOURCE_UNIFORM) {
- BLI_dynstr_appendf(ds, "unf%d", input->id);
- }
- else if (input->source == GPU_SOURCE_CONSTANT) {
- BLI_dynstr_appendf(ds, "cons%d", input->id);
- }
- else if (input->source == GPU_SOURCE_ATTR) {
- codegen_convert_datatype(ds, input->attr->gputype, input->type, "var", input->attr->id);
- }
- else if (input->source == GPU_SOURCE_UNIFORM_ATTR) {
- BLI_dynstr_appendf(ds, "GET_UNIFORM_ATTR(attr%d)", input->uniform_attr->id);
- }
-
- BLI_dynstr_append(ds, ", ");
- }
-
- LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
- BLI_dynstr_appendf(ds, "tmp%d", output->id);
- if (output->next) {
- BLI_dynstr_append(ds, ", ");
- }
- }
-
- BLI_dynstr_append(ds, ");\n");
- }
-}
-
-static void codegen_final_output(DynStr *ds, GPUOutput *finaloutput)
-{
- BLI_dynstr_appendf(ds, "return tmp%d;\n", finaloutput->id);
-}
-
-static char *code_generate_fragment(GPUMaterial *material,
- GPUNodeGraph *graph,
- const char *interface_str)
-{
- DynStr *ds = BLI_dynstr_new();
- char *code;
- int builtins;
-
- codegen_set_unique_ids(graph);
-
- /* Attributes, Shader stage interface. */
- if (interface_str) {
- BLI_dynstr_appendf(ds, "in codegenInterface {%s};\n\n", interface_str);
- }
-
- builtins = codegen_process_uniforms_functions(material, ds, graph);
-
- if (builtins & (GPU_OBJECT_INFO | GPU_OBJECT_COLOR)) {
- BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
- }
-
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl);
- }
-
- BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n");
-
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, " vec2 barytexco = barycentric_resolve(barycentricTexCo);\n");
- }
- /* TODO(fclem): get rid of that. */
- if (builtins & GPU_VIEW_MATRIX) {
- BLI_dynstr_append(ds, " #define viewmat ViewMatrix\n");
- }
- if (builtins & GPU_CAMERA_TEXCO_FACTORS) {
- BLI_dynstr_append(ds, " #define camtexfac CameraTexCoFactors\n");
- }
- if (builtins & GPU_OBJECT_MATRIX) {
- BLI_dynstr_append(ds, " #define objmat ModelMatrix\n");
- }
- if (builtins & GPU_INVERSE_OBJECT_MATRIX) {
- BLI_dynstr_append(ds, " #define objinv ModelMatrixInverse\n");
- }
- if (builtins & GPU_INVERSE_VIEW_MATRIX) {
- BLI_dynstr_append(ds, " #define viewinv ViewMatrixInverse\n");
- }
- if (builtins & GPU_LOC_TO_VIEW_MATRIX) {
- BLI_dynstr_append(ds, " #define localtoviewmat (ViewMatrix * ModelMatrix)\n");
- }
- if (builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) {
- BLI_dynstr_append(ds,
- " #define invlocaltoviewmat (ModelMatrixInverse * ViewMatrixInverse)\n");
- }
- if (builtins & GPU_VIEW_NORMAL) {
- BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
- BLI_dynstr_append(ds, " vec3 n;\n");
- BLI_dynstr_append(ds, " world_normals_get(n);\n");
- BLI_dynstr_append(ds, " vec3 facingnormal = transform_direction(ViewMatrix, n);\n");
- BLI_dynstr_append(ds, "#else\n");
- BLI_dynstr_append(ds, " vec3 facingnormal = gl_FrontFacing ? viewNormal: -viewNormal;\n");
- BLI_dynstr_append(ds, "#endif\n");
- }
- if (builtins & GPU_WORLD_NORMAL) {
- BLI_dynstr_append(ds, " vec3 facingwnormal;\n");
- if (builtins & GPU_VIEW_NORMAL) {
- BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
- BLI_dynstr_append(ds, " facingwnormal = n;\n");
- BLI_dynstr_append(ds, "#else\n");
- BLI_dynstr_append(ds, " world_normals_get(facingwnormal);\n");
- BLI_dynstr_append(ds, "#endif\n");
- }
- else {
- BLI_dynstr_append(ds, " world_normals_get(facingwnormal);\n");
- }
- }
- if (builtins & GPU_VIEW_POSITION) {
- BLI_dynstr_append(ds, " #define viewposition viewPosition\n");
- }
-
- codegen_declare_tmps(ds, graph);
- codegen_call_functions(ds, graph);
-
- BLI_dynstr_append(ds, " #ifndef VOLUMETRICS\n");
- BLI_dynstr_append(ds, " if (renderPassAOV) {\n");
- BLI_dynstr_append(ds, " switch (render_pass_aov_hash()) {\n");
- GSet *aovhashes_added = BLI_gset_int_new(__func__);
- LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) {
- void *aov_key = POINTER_FROM_INT(aovlink->hash);
- if (BLI_gset_haskey(aovhashes_added, aov_key)) {
- continue;
- }
- BLI_dynstr_appendf(ds, " case %d: {\n ", aovlink->hash);
- codegen_final_output(ds, aovlink->outlink->output);
- BLI_dynstr_append(ds, " }\n");
- BLI_gset_add(aovhashes_added, aov_key);
- }
- BLI_gset_free(aovhashes_added, NULL);
- BLI_dynstr_append(ds, " default: {\n");
- BLI_dynstr_append(ds, " Closure no_aov = CLOSURE_DEFAULT;\n");
- BLI_dynstr_append(ds, " no_aov.holdout = 1.0;\n");
- BLI_dynstr_append(ds, " return no_aov;\n");
- BLI_dynstr_append(ds, " }\n");
- BLI_dynstr_append(ds, " }\n");
- BLI_dynstr_append(ds, " } else {\n");
- BLI_dynstr_append(ds, " #else /* VOLUMETRICS */\n");
- BLI_dynstr_append(ds, " {\n");
- BLI_dynstr_append(ds, " #endif /* VOLUMETRICS */\n ");
- codegen_final_output(ds, graph->outlink->output);
- BLI_dynstr_append(ds, " }\n");
-
- BLI_dynstr_append(ds, "}\n");
-
- /* create shader */
- code = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
-#if 0
- if (G.debug & G_DEBUG) {
- printf("%s\n", code);
- }
-#endif
-
- return code;
-}
-
-static const char *attr_prefix_get(CustomDataType type)
-{
- switch (type) {
- case CD_ORCO:
- return "orco";
- case CD_MTFACE:
- return "u";
- case CD_TANGENT:
- return "t";
- case CD_MCOL:
- case CD_MLOOPCOL:
- return "c";
- case CD_PROP_COLOR:
- return "c";
- case CD_AUTO_FROM_NAME:
- return "a";
- case CD_HAIRLENGTH:
- return "hl";
- default:
- BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!");
- return "";
- }
-}
-
-/* We talk about shader stage interface, not to be mistaken with GPUShaderInterface. */
-static char *code_generate_interface(GPUNodeGraph *graph, int builtins)
-{
- if (BLI_listbase_is_empty(&graph->attributes) &&
- (builtins & (GPU_BARYCENTRIC_DIST | GPU_BARYCENTRIC_TEXCO)) == 0) {
- return NULL;
- }
-
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, "\n");
-
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- if (attr->type == CD_HAIRLENGTH) {
- BLI_dynstr_appendf(ds, "float var%d;\n", attr->id);
- }
- else {
- BLI_dynstr_appendf(ds, "%s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id);
- }
- }
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "vec2 barycentricTexCo;\n");
- }
- if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds, "vec3 barycentricDist;\n");
- }
-
- char *code = BLI_dynstr_get_cstring(ds);
-
- BLI_dynstr_free(ds);
-
- return code;
-}
-
-static char *code_generate_vertex(GPUNodeGraph *graph,
- const char *interface_str,
- const char *vert_code,
- int builtins)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl);
-
- /* Inputs */
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- const char *type_str = gpu_data_type_to_string(attr->gputype);
- const char *prefix = attr_prefix_get(attr->type);
- /* XXX FIXME: see notes in mesh_render_data_create() */
- /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
- if (attr->type == CD_ORCO) {
- /* OPTI: orco is computed from local positions, but only if no modifier is present. */
- BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
- BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n");
- }
- else if (attr->type == CD_HAIRLENGTH) {
- BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
- BLI_dynstr_append(ds, "DEFINE_ATTR(float, hairLen);\n");
- }
- else if (attr->name[0] == '\0') {
- BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s);\n", type_str, prefix);
- BLI_dynstr_appendf(ds, "#define att%d %s\n", attr->id, prefix);
- }
- else {
- char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
- GPU_vertformat_safe_attr_name(attr->name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
- BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s%s);\n", type_str, prefix, attr_safe_name);
- BLI_dynstr_appendf(ds, "#define att%d %s%s\n", attr->id, prefix, attr_safe_name);
- }
- }
-
- /* Outputs interface */
- if (interface_str) {
- BLI_dynstr_appendf(ds, "out codegenInterface {%s};\n\n", interface_str);
- }
-
- /* Prototype. Needed for hair functions. */
- BLI_dynstr_append(ds, "void pass_attr(vec3 position, mat3 normalmat, mat4 modelmatinv);\n");
- BLI_dynstr_append(ds, "#define USE_ATTR\n\n");
-
- BLI_dynstr_append(ds, vert_code);
- BLI_dynstr_append(ds, "\n\n");
-
- BLI_dynstr_append(ds, "void pass_attr(vec3 position, mat3 normalmat, mat4 modelmatinv) {\n");
-
- /* GPU_BARYCENTRIC_TEXCO cannot be computed based on gl_VertexID
- * for MESH_SHADER because of indexed drawing. In this case a
- * geometry shader is needed. */
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_appendf(ds, " barycentricTexCo = barycentric_get();\n");
- }
- if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_appendf(ds, " barycentricDist = vec3(0);\n");
- }
-
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- if (attr->type == CD_TANGENT) { /* silly exception */
- BLI_dynstr_appendf(ds, " var%d = tangent_get(att%d, normalmat);\n", attr->id, attr->id);
- }
- else if (attr->type == CD_ORCO) {
- BLI_dynstr_appendf(
- ds, " var%d = orco_get(position, modelmatinv, OrcoTexCoFactors, orco);\n", attr->id);
- }
- else if (attr->type == CD_HAIRLENGTH) {
- BLI_dynstr_appendf(ds, " var%d = hair_len_get(hair_get_strand_id(), hairLen);\n", attr->id);
- }
- else {
- const char *type_str = gpu_data_type_to_string(attr->gputype);
- BLI_dynstr_appendf(ds, " var%d = GET_ATTR(%s, att%d);\n", attr->id, type_str, attr->id);
- }
- }
-
- BLI_dynstr_append(ds, "}\n");
-
- char *code = BLI_dynstr_get_cstring(ds);
-
- BLI_dynstr_free(ds);
-
-#if 0
- if (G.debug & G_DEBUG) {
- printf("%s\n", code);
- }
-#endif
-
- return code;
-}
-
-static char *code_generate_geometry(GPUNodeGraph *graph,
- const char *interface_str,
- const char *geom_code,
- int builtins)
-{
- if (!geom_code) {
- return NULL;
- }
-
- DynStr *ds = BLI_dynstr_new();
-
- /* Attributes, Shader interface; */
- if (interface_str) {
- BLI_dynstr_appendf(ds, "in codegenInterface {%s} dataAttrIn[];\n\n", interface_str);
- BLI_dynstr_appendf(ds, "out codegenInterface {%s} dataAttrOut;\n\n", interface_str);
- }
-
- BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl);
-
- if (builtins & GPU_BARYCENTRIC_DIST) {
- /* geom_code should do something with this, but may not. */
- BLI_dynstr_append(ds, "#define DO_BARYCENTRIC_DISTANCES\n");
- }
-
- /* Generate varying assignments. */
- BLI_dynstr_append(ds, "#define USE_ATTR\n");
- /* This needs to be a define. Some drivers don't like variable vert index inside dataAttrIn. */
- BLI_dynstr_append(ds, "#define pass_attr(vert) {\\\n");
-
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "dataAttrOut.barycentricTexCo = calc_barycentric_co(vert);\\\n");
- }
-
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- /* TODO: let shader choose what to do depending on what the attribute is. */
- BLI_dynstr_appendf(ds, "dataAttrOut.var%d = dataAttrIn[vert].var%d;\\\n", attr->id, attr->id);
- }
- BLI_dynstr_append(ds, "}\n\n");
-
- BLI_dynstr_append(ds, geom_code);
-
- char *code = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- return code;
-}
-
-GPUShader *GPU_pass_shader_get(GPUPass *pass)
-{
- return pass->shader;
-}
-
-/* Pass create/free */
-
-static bool gpu_pass_is_valid(GPUPass *pass)
-{
- /* Shader is not null if compilation is successful. */
- return (pass->compiled == false || pass->shader != NULL);
-}
-
-GPUPass *GPU_generate_pass(GPUMaterial *material,
- GPUNodeGraph *graph,
- const char *vert_code,
- const char *geom_code,
- const char *frag_lib,
- const char *defines)
-{
- /* Prune the unused nodes and extract attributes before compiling so the
- * generated VBOs are ready to accept the future shader. */
- gpu_node_graph_prune_unused(graph);
- gpu_node_graph_finalize_uniform_attrs(graph);
-
- int builtins = 0;
- LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
- if (input->source == GPU_SOURCE_BUILTIN) {
- builtins |= input->builtin;
- }
- }
- }
- /* generate code */
- char *interface_str = code_generate_interface(graph, builtins);
- char *fragmentgen = code_generate_fragment(material, graph, interface_str);
-
- /* Cache lookup: Reuse shaders already compiled */
- uint32_t hash = gpu_pass_hash(fragmentgen, defines, &graph->attributes);
- GPUPass *pass_hash = gpu_pass_cache_lookup(hash);
-
- if (pass_hash && (pass_hash->next == NULL || pass_hash->next->hash != hash)) {
- /* No collision, just return the pass. */
- MEM_SAFE_FREE(interface_str);
- MEM_freeN(fragmentgen);
- if (!gpu_pass_is_valid(pass_hash)) {
- /* Shader has already been created but failed to compile. */
- return NULL;
- }
- pass_hash->refcount += 1;
- return pass_hash;
- }
-
- /* Either the shader is not compiled or there is a hash collision...
- * continue generating the shader strings. */
- GSet *used_libraries = gpu_material_used_libraries(material);
- char *tmp = gpu_material_library_generate_code(used_libraries, frag_lib);
-
- char *geometrycode = code_generate_geometry(graph, interface_str, geom_code, builtins);
- char *vertexcode = code_generate_vertex(graph, interface_str, vert_code, builtins);
- char *fragmentcode = BLI_strdupcat(tmp, fragmentgen);
-
- MEM_SAFE_FREE(interface_str);
- MEM_freeN(fragmentgen);
- MEM_freeN(tmp);
-
- GPUPass *pass = NULL;
- if (pass_hash) {
- /* Cache lookup: Reuse shaders already compiled */
- pass = gpu_pass_cache_resolve_collision(
- pass_hash, vertexcode, geometrycode, fragmentcode, defines, hash);
- }
-
- if (pass) {
- MEM_SAFE_FREE(vertexcode);
- MEM_SAFE_FREE(fragmentcode);
- MEM_SAFE_FREE(geometrycode);
-
- /* Cache hit. Reuse the same GPUPass and GPUShader. */
- if (!gpu_pass_is_valid(pass)) {
- /* Shader has already been created but failed to compile. */
- return NULL;
- }
-
- pass->refcount += 1;
- }
- else {
- /* We still create a pass even if shader compilation
- * fails to avoid trying to compile again and again. */
- pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
- pass->shader = NULL;
- pass->refcount = 1;
- pass->hash = hash;
- pass->vertexcode = vertexcode;
- pass->fragmentcode = fragmentcode;
- pass->geometrycode = geometrycode;
- pass->defines = (defines) ? BLI_strdup(defines) : NULL;
- pass->compiled = false;
-
- BLI_spin_lock(&pass_cache_spin);
- if (pass_hash != NULL) {
- /* Add after the first pass having the same hash. */
- pass->next = pass_hash->next;
- pass_hash->next = pass;
- }
- else {
- /* No other pass have same hash, just prepend to the list. */
- BLI_LINKS_PREPEND(pass_cache, pass);
- }
- BLI_spin_unlock(&pass_cache_spin);
- }
-
- return pass;
-}
-
-static int count_active_texture_sampler(GPUShader *shader, const char *source)
-{
- const char *code = source;
-
- /* Remember this is per stage. */
- GSet *sampler_ids = BLI_gset_int_new(__func__);
- int num_samplers = 0;
-
- while ((code = strstr(code, "uniform "))) {
- /* Move past "uniform". */
- code += 7;
- /* Skip following spaces. */
- while (*code == ' ') {
- code++;
- }
- /* Skip "i" from potential isamplers. */
- if (*code == 'i') {
- code++;
- }
- /* Skip following spaces. */
- if (BLI_str_startswith(code, "sampler")) {
- /* Move past "uniform". */
- code += 7;
- /* Skip sampler type suffix. */
- while (!ELEM(*code, ' ', '\0')) {
- code++;
- }
- /* Skip following spaces. */
- while (*code == ' ') {
- code++;
- }
-
- if (*code != '\0') {
- char sampler_name[64];
- code = gpu_str_skip_token(code, sampler_name, sizeof(sampler_name));
- int id = GPU_shader_get_uniform(shader, sampler_name);
-
- if (id == -1) {
- continue;
- }
- /* Catch duplicates. */
- if (BLI_gset_add(sampler_ids, POINTER_FROM_INT(id))) {
- num_samplers++;
- }
- }
- }
- }
-
- BLI_gset_free(sampler_ids, NULL);
-
- return num_samplers;
-}
-
-static bool gpu_pass_shader_validate(GPUPass *pass, GPUShader *shader)
-{
- if (shader == NULL) {
- return false;
- }
-
- /* NOTE: The only drawback of this method is that it will count a sampler
- * used in the fragment shader and only declared (but not used) in the vertex
- * shader as used by both. But this corner case is not happening for now. */
- int vert_samplers_len = count_active_texture_sampler(shader, pass->vertexcode);
- int frag_samplers_len = count_active_texture_sampler(shader, pass->fragmentcode);
-
- int total_samplers_len = vert_samplers_len + frag_samplers_len;
-
- /* Validate against opengl limit. */
- if ((frag_samplers_len > GPU_max_textures_frag()) ||
- (vert_samplers_len > GPU_max_textures_vert())) {
- return false;
- }
-
- if (pass->geometrycode) {
- int geom_samplers_len = count_active_texture_sampler(shader, pass->geometrycode);
- total_samplers_len += geom_samplers_len;
- if (geom_samplers_len > GPU_max_textures_geom()) {
- return false;
- }
- }
-
- return (total_samplers_len <= GPU_max_textures());
-}
-
-bool GPU_pass_compile(GPUPass *pass, const char *shname)
-{
- bool success = true;
- if (!pass->compiled) {
- GPUShader *shader = GPU_shader_create(
- pass->vertexcode, pass->fragmentcode, pass->geometrycode, NULL, pass->defines, shname);
-
- /* NOTE: Some drivers / gpu allows more active samplers than the opengl limit.
- * We need to make sure to count active samplers to avoid undefined behavior. */
- if (!gpu_pass_shader_validate(pass, shader)) {
- success = false;
- if (shader != NULL) {
- fprintf(stderr, "GPUShader: error: too many samplers in shader.\n");
- GPU_shader_free(shader);
- shader = NULL;
- }
- }
- pass->shader = shader;
- pass->compiled = true;
- }
-
- return success;
-}
-
-void GPU_pass_release(GPUPass *pass)
-{
- BLI_assert(pass->refcount > 0);
- pass->refcount--;
-}
-
-static void gpu_pass_free(GPUPass *pass)
-{
- BLI_assert(pass->refcount == 0);
- if (pass->shader) {
- GPU_shader_free(pass->shader);
- }
- MEM_SAFE_FREE(pass->fragmentcode);
- MEM_SAFE_FREE(pass->geometrycode);
- MEM_SAFE_FREE(pass->vertexcode);
- MEM_SAFE_FREE(pass->defines);
- MEM_freeN(pass);
-}
-
-void GPU_pass_cache_garbage_collect(void)
-{
- static int lasttime = 0;
- const int shadercollectrate = 60; /* hardcoded for now. */
- int ctime = (int)PIL_check_seconds_timer();
-
- if (ctime < shadercollectrate + lasttime) {
- return;
- }
-
- lasttime = ctime;
-
- BLI_spin_lock(&pass_cache_spin);
- GPUPass *next, **prev_pass = &pass_cache;
- for (GPUPass *pass = pass_cache; pass; pass = next) {
- next = pass->next;
- if (pass->refcount == 0) {
- /* Remove from list */
- *prev_pass = next;
- gpu_pass_free(pass);
- }
- else {
- prev_pass = &pass->next;
- }
- }
- BLI_spin_unlock(&pass_cache_spin);
-}
-
-void GPU_pass_cache_init(void)
-{
- BLI_spin_init(&pass_cache_spin);
-}
-
-void GPU_pass_cache_free(void)
-{
- BLI_spin_lock(&pass_cache_spin);
- while (pass_cache) {
- GPUPass *next = pass_cache->next;
- gpu_pass_free(pass_cache);
- pass_cache = next;
- }
- BLI_spin_unlock(&pass_cache_spin);
-
- BLI_spin_end(&pass_cache_spin);
-}
-
-/* Module */
-
-void gpu_codegen_init(void)
-{
-}
-
-void gpu_codegen_exit(void)
-{
- BKE_material_defaults_free_gpu();
- GPU_shader_free_builtin_shaders();
-}
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
new file mode 100644
index 00000000000..8963fa45c96
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -0,0 +1,825 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2005 Blender Foundation. */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Convert material node-trees to GLSL.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_customdata_types.h"
+#include "DNA_image_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+#include "BLI_ghash.h"
+#include "BLI_hash_mm2a.h"
+#include "BLI_link_utils.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "PIL_time.h"
+
+#include "BKE_material.h"
+#include "BKE_world.h"
+
+#include "GPU_capabilities.h"
+#include "GPU_material.h"
+#include "GPU_shader.h"
+#include "GPU_uniform_buffer.h"
+#include "GPU_vertex_format.h"
+
+#include "BLI_sys_types.h" /* for intptr_t support */
+
+#include "gpu_codegen.h"
+#include "gpu_material_library.h"
+#include "gpu_node_graph.h"
+#include "gpu_shader_create_info.hh"
+#include "gpu_shader_dependency_private.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <sstream>
+#include <string>
+
+using namespace blender::gpu::shader;
+
+struct GPUCodegenCreateInfo : ShaderCreateInfo {
+ struct NameBuffer {
+ char attr_names[16][GPU_MAX_SAFE_ATTR_NAME + 1];
+ char var_names[16][8];
+ };
+
+ /** Optional generated interface. */
+ StageInterfaceInfo *interface_generated = nullptr;
+ /** Optional name buffer containing names referenced by StringRefNull. */
+ NameBuffer *name_buffer = nullptr;
+
+ GPUCodegenCreateInfo(const char *name) : ShaderCreateInfo(name){};
+ ~GPUCodegenCreateInfo()
+ {
+ delete interface_generated;
+ MEM_delete(name_buffer);
+ };
+};
+
+struct GPUPass {
+ struct GPUPass *next;
+
+ GPUShader *shader;
+ GPUCodegenCreateInfo *create_info = nullptr;
+ /** Orphaned GPUPasses gets freed by the garbage collector. */
+ uint refcount;
+ /** Identity hash generated from all GLSL code. */
+ uint32_t hash;
+ /** Did we already tried to compile the attached GPUShader. */
+ bool compiled;
+};
+
+/* -------------------------------------------------------------------- */
+/** \name GPUPass Cache
+ *
+ * Internal shader cache: This prevent the shader recompilation / stall when
+ * using undo/redo AND also allows for GPUPass reuse if the Shader code is the
+ * same for 2 different Materials. Unused GPUPasses are free by Garbage collection.
+ */
+
+/* Only use one linklist that contains the GPUPasses grouped by hash. */
+static GPUPass *pass_cache = nullptr;
+static SpinLock pass_cache_spin;
+
+/* Search by hash only. Return first pass with the same hash.
+ * There is hash collision if (pass->next && pass->next->hash == hash) */
+static GPUPass *gpu_pass_cache_lookup(uint32_t hash)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ /* Could be optimized with a Lookup table. */
+ for (GPUPass *pass = pass_cache; pass; pass = pass->next) {
+ if (pass->hash == hash) {
+ BLI_spin_unlock(&pass_cache_spin);
+ return pass;
+ }
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+ return nullptr;
+}
+
+static void gpu_pass_cache_insert_after(GPUPass *node, GPUPass *pass)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ if (node != nullptr) {
+ /* Add after the first pass having the same hash. */
+ pass->next = node->next;
+ node->next = pass;
+ }
+ else {
+ /* No other pass have same hash, just prepend to the list. */
+ BLI_LINKS_PREPEND(pass_cache, pass);
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+}
+
+/* Check all possible passes with the same hash. */
+static GPUPass *gpu_pass_cache_resolve_collision(GPUPass *pass,
+ GPUShaderCreateInfo *info,
+ uint32_t hash)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ for (; pass && (pass->hash == hash); pass = pass->next) {
+ if (*reinterpret_cast<ShaderCreateInfo *>(info) ==
+ *reinterpret_cast<ShaderCreateInfo *>(pass->create_info)) {
+ BLI_spin_unlock(&pass_cache_spin);
+ return pass;
+ }
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+ return nullptr;
+}
+
+static bool gpu_pass_is_valid(GPUPass *pass)
+{
+ /* Shader is not null if compilation is successful. */
+ return (pass->compiled == false || pass->shader != nullptr);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Type > string conversion
+ * \{ */
+
+static std::ostream &operator<<(std::ostream &stream, const GPUInput *input)
+{
+ switch (input->source) {
+ case GPU_SOURCE_FUNCTION_CALL:
+ case GPU_SOURCE_OUTPUT:
+ return stream << "tmp" << input->id;
+ case GPU_SOURCE_CONSTANT:
+ return stream << "cons" << input->id;
+ case GPU_SOURCE_UNIFORM:
+ return stream << "node_tree.u" << input->id;
+ case GPU_SOURCE_ATTR:
+ return stream << "var_attrs.v" << input->attr->id;
+ case GPU_SOURCE_UNIFORM_ATTR:
+ return stream << "unf_attrs[resource_id].attr" << input->uniform_attr->id;
+ case GPU_SOURCE_STRUCT:
+ return stream << "strct" << input->id;
+ case GPU_SOURCE_TEX:
+ return stream << input->texture->sampler_name;
+ case GPU_SOURCE_TEX_TILED_MAPPING:
+ return stream << input->texture->tiled_mapping_name;
+ case GPU_SOURCE_VOLUME_GRID:
+ return stream << input->volume_grid->sampler_name;
+ case GPU_SOURCE_VOLUME_GRID_TRANSFORM:
+ return stream << input->volume_grid->transform_name;
+ default:
+ BLI_assert(0);
+ return stream;
+ }
+}
+
+static std::ostream &operator<<(std::ostream &stream, const GPUOutput *output)
+{
+ return stream << "tmp" << output->id;
+}
+
+/* Trick type to change overload and keep a somewhat nice syntax. */
+struct GPUConstant : public GPUInput {
+};
+
+/* Print data constructor (i.e: vec2(1.0f, 1.0f)). */
+static std::ostream &operator<<(std::ostream &stream, const GPUConstant *input)
+{
+ stream << input->type << "(";
+ for (int i = 0; i < input->type; i++) {
+ char formated_float[32];
+ /* Print with the maximum precision for single precision float using scientific notation.
+ * See https://stackoverflow.com/questions/16839658/#answer-21162120 */
+ SNPRINTF(formated_float, "%.9g", input->vec[i]);
+ stream << formated_float;
+ if (i < input->type - 1) {
+ stream << ", ";
+ }
+ }
+ stream << ")";
+ return stream;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GLSL code generation
+ * \{ */
+
+class GPUCodegen {
+ public:
+ GPUMaterial &mat;
+ GPUNodeGraph &graph;
+ GPUCodegenOutput output = {};
+ GPUCodegenCreateInfo *create_info = nullptr;
+
+ private:
+ uint32_t hash_ = 0;
+ BLI_HashMurmur2A hm2a_;
+ ListBase ubo_inputs_ = {nullptr, nullptr};
+
+ public:
+ GPUCodegen(GPUMaterial *mat_, GPUNodeGraph *graph_) : mat(*mat_), graph(*graph_)
+ {
+ BLI_hash_mm2a_init(&hm2a_, GPU_material_uuid_get(&mat));
+ BLI_hash_mm2a_add_int(&hm2a_, GPU_material_flag(&mat));
+ create_info = new GPUCodegenCreateInfo("codegen");
+ output.create_info = reinterpret_cast<GPUShaderCreateInfo *>(
+ static_cast<ShaderCreateInfo *>(create_info));
+
+ if (GPU_material_flag_get(mat_, GPU_MATFLAG_OBJECT_INFO)) {
+ create_info->additional_info("draw_object_infos");
+ }
+ }
+
+ ~GPUCodegen()
+ {
+ MEM_SAFE_FREE(output.attr_load);
+ MEM_SAFE_FREE(output.surface);
+ MEM_SAFE_FREE(output.volume);
+ MEM_SAFE_FREE(output.thickness);
+ MEM_SAFE_FREE(output.displacement);
+ MEM_SAFE_FREE(output.material_functions);
+ delete create_info;
+ BLI_freelistN(&ubo_inputs_);
+ };
+
+ void generate_graphs();
+ void generate_uniform_buffer();
+ void generate_attribs();
+ void generate_resources();
+ void generate_library();
+
+ uint32_t hash_get() const
+ {
+ return hash_;
+ }
+
+ private:
+ void set_unique_ids();
+
+ void node_serialize(std::stringstream &eval_ss, const GPUNode *node);
+ char *graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link);
+
+ static char *extract_c_str(std::stringstream &stream)
+ {
+ auto string = stream.str();
+ return BLI_strdup(string.c_str());
+ }
+};
+
+static char attr_prefix_get(CustomDataType type)
+{
+ switch (type) {
+ case CD_MTFACE:
+ return 'u';
+ case CD_TANGENT:
+ return 't';
+ case CD_MCOL:
+ case CD_MLOOPCOL:
+ return 'c';
+ case CD_PROP_COLOR:
+ return 'c';
+ case CD_AUTO_FROM_NAME:
+ return 'a';
+ case CD_HAIRLENGTH:
+ return 'l';
+ default:
+ BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!");
+ return '\0';
+ }
+}
+
+void GPUCodegen::generate_attribs()
+{
+ if (BLI_listbase_is_empty(&graph.attributes)) {
+ output.attr_load = nullptr;
+ return;
+ }
+
+ GPUCodegenCreateInfo &info = *create_info;
+
+ info.name_buffer = MEM_new<GPUCodegenCreateInfo::NameBuffer>("info.name_buffer");
+ info.interface_generated = new StageInterfaceInfo("codegen_iface", "var_attrs");
+ StageInterfaceInfo &iface = *info.interface_generated;
+ info.vertex_out(iface);
+
+ /* Input declaration, loading / assignment to interface and geometry shader passthrough. */
+ std::stringstream decl_ss, iface_ss, load_ss;
+
+ int slot = 15;
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph.attributes) {
+
+ /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
+ if (attr->type == CD_ORCO) {
+ /* OPTI: orco is computed from local positions, but only if no modifier is present. */
+ STRNCPY(info.name_buffer->attr_names[slot], "orco");
+ }
+ else {
+ char *name = info.name_buffer->attr_names[slot];
+ name[0] = attr_prefix_get(static_cast<CustomDataType>(attr->type));
+ name[1] = '\0';
+ if (attr->name[0] != '\0') {
+ /* XXX FIXME: see notes in mesh_render_data_create() */
+ GPU_vertformat_safe_attr_name(attr->name, &name[1], GPU_MAX_SAFE_ATTR_NAME);
+ }
+ }
+ SNPRINTF(info.name_buffer->var_names[slot], "v%d", attr->id);
+
+ blender::StringRefNull attr_name = info.name_buffer->attr_names[slot];
+ blender::StringRefNull var_name = info.name_buffer->var_names[slot];
+
+ eGPUType input_type, iface_type;
+
+ load_ss << "var_attrs." << var_name;
+ switch (attr->type) {
+ case CD_ORCO:
+ /* Need vec4 to detect usage of default attribute. */
+ input_type = GPU_VEC4;
+ iface_type = GPU_VEC3;
+ load_ss << " = attr_load_orco(" << attr_name << ");\n";
+ break;
+ case CD_HAIRLENGTH:
+ iface_type = input_type = GPU_FLOAT;
+ load_ss << " = attr_load_" << input_type << "(" << attr_name << ");\n";
+ break;
+ case CD_TANGENT:
+ iface_type = input_type = GPU_VEC4;
+ load_ss << " = attr_load_tangent(" << attr_name << ");\n";
+ break;
+ case CD_MTFACE:
+ iface_type = input_type = GPU_VEC3;
+ load_ss << " = attr_load_uv(" << attr_name << ");\n";
+ break;
+ case CD_MCOL:
+ iface_type = input_type = GPU_VEC4;
+ load_ss << " = attr_load_color(" << attr_name << ");\n";
+ break;
+ default:
+ iface_type = input_type = GPU_VEC4;
+ load_ss << " = attr_load_" << input_type << "(" << attr_name << ");\n";
+ break;
+ }
+
+ info.vertex_in(slot--, to_type(input_type), attr_name);
+ iface.smooth(to_type(iface_type), var_name);
+ }
+
+ output.attr_load = extract_c_str(load_ss);
+}
+
+void GPUCodegen::generate_resources()
+{
+ GPUCodegenCreateInfo &info = *create_info;
+
+ std::stringstream ss;
+
+ /* Textures. */
+ LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph.textures) {
+ if (tex->colorband) {
+ info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->sampler_name, Frequency::BATCH);
+ }
+ else if (tex->tiled_mapping_name[0] != '\0') {
+ info.sampler(0, ImageType::FLOAT_2D_ARRAY, tex->sampler_name, Frequency::BATCH);
+ info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->tiled_mapping_name, Frequency::BATCH);
+ }
+ else {
+ info.sampler(0, ImageType::FLOAT_2D, tex->sampler_name, Frequency::BATCH);
+ }
+ }
+ /* Volume Grids. */
+ LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph.volume_grids) {
+ info.sampler(0, ImageType::FLOAT_3D, grid->sampler_name, Frequency::BATCH);
+ /* TODO(@fclem): Global uniform. To put in an UBO. */
+ info.push_constant(Type::MAT4, grid->transform_name);
+ }
+
+ if (!BLI_listbase_is_empty(&ubo_inputs_)) {
+ /* NOTE: generate_uniform_buffer() should have sorted the inputs before this. */
+ ss << "struct NodeTree {\n";
+ LISTBASE_FOREACH (LinkData *, link, &ubo_inputs_) {
+ GPUInput *input = (GPUInput *)(link->data);
+ ss << input->type << " u" << input->id << ";\n";
+ }
+ ss << "};\n\n";
+
+ info.uniform_buf(0, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH);
+ }
+
+ if (!BLI_listbase_is_empty(&graph.uniform_attrs.list)) {
+ ss << "struct UniformAttrs {\n";
+ LISTBASE_FOREACH (GPUUniformAttr *, attr, &graph.uniform_attrs.list) {
+ ss << "vec4 attr" << attr->id << ";\n";
+ }
+ ss << "};\n\n";
+
+ /* TODO(fclem): Use the macro for length. Currently not working for EEVEE. */
+ /* DRW_RESOURCE_CHUNK_LEN = 512 */
+ info.uniform_buf(0, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH);
+ }
+
+ info.typedef_source_generated = ss.str();
+}
+
+void GPUCodegen::generate_library()
+{
+ GPUCodegenCreateInfo &info = *create_info;
+
+ void *value;
+ GSetIterState pop_state = {};
+ while (BLI_gset_pop(graph.used_libraries, &pop_state, &value)) {
+ auto deps = gpu_shader_dependency_get_resolved_source((const char *)value);
+ info.dependencies_generated.extend_non_duplicates(deps);
+ }
+}
+
+void GPUCodegen::node_serialize(std::stringstream &eval_ss, const GPUNode *node)
+{
+ /* Declare constants. */
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
+ switch (input->source) {
+ case GPU_SOURCE_FUNCTION_CALL:
+ eval_ss << input->type << " " << input << "; " << input->function_call << input << ");\n";
+ break;
+ case GPU_SOURCE_STRUCT:
+ eval_ss << input->type << " " << input << " = CLOSURE_DEFAULT;\n";
+ break;
+ case GPU_SOURCE_CONSTANT:
+ eval_ss << input->type << " " << input << " = " << (GPUConstant *)input << ";\n";
+ break;
+ default:
+ break;
+ }
+ }
+ /* Declare temporary variables for node output storage. */
+ LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
+ eval_ss << output->type << " " << output << ";\n";
+ }
+
+ /* Function call. */
+ eval_ss << node->name << "(";
+ /* Input arguments. */
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
+ switch (input->source) {
+ case GPU_SOURCE_OUTPUT:
+ case GPU_SOURCE_ATTR: {
+ /* These inputs can have non matching types. Do conversion. */
+ eGPUType to = input->type;
+ eGPUType from = (input->source == GPU_SOURCE_ATTR) ? input->attr->gputype :
+ input->link->output->type;
+ if (from != to) {
+ /* Use defines declared inside codegen_lib (i.e: vec4_from_float). */
+ eval_ss << to << "_from_" << from << "(";
+ }
+
+ if (input->source == GPU_SOURCE_ATTR) {
+ eval_ss << input;
+ }
+ else {
+ eval_ss << input->link->output;
+ }
+
+ if (from != to) {
+ eval_ss << ")";
+ }
+ break;
+ }
+ default:
+ eval_ss << input;
+ break;
+ }
+ eval_ss << ", ";
+ }
+ /* Output arguments. */
+ LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
+ eval_ss << output;
+ if (output->next) {
+ eval_ss << ", ";
+ }
+ }
+ eval_ss << ");\n\n";
+}
+
+char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link)
+{
+ if (output_link == nullptr) {
+ return nullptr;
+ }
+
+ std::stringstream eval_ss;
+ /* NOTE: The node order is already top to bottom (or left to right in node editor)
+ * because of the evaluation order inside ntreeExecGPUNodes(). */
+ LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) {
+ if ((node->tag & tree_tag) == 0) {
+ continue;
+ }
+ node_serialize(eval_ss, node);
+ }
+ eval_ss << "return " << output_link->output << ";\n";
+
+ char *eval_c_str = extract_c_str(eval_ss);
+ BLI_hash_mm2a_add(&hm2a_, (uchar *)eval_c_str, eval_ss.str().size());
+ return eval_c_str;
+}
+
+void GPUCodegen::generate_uniform_buffer()
+{
+ /* Extract uniform inputs. */
+ LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) {
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
+ if (input->source == GPU_SOURCE_UNIFORM && !input->link) {
+ /* We handle the UBO uniforms separately. */
+ BLI_addtail(&ubo_inputs_, BLI_genericNodeN(input));
+ }
+ }
+ }
+ if (!BLI_listbase_is_empty(&ubo_inputs_)) {
+ /* This sorts the inputs based on size. */
+ GPU_material_uniform_buffer_create(&mat, &ubo_inputs_);
+ }
+}
+
+/* Sets id for unique names for all inputs, resources and temp variables. */
+void GPUCodegen::set_unique_ids()
+{
+ int id = 1;
+ LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) {
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
+ input->id = id++;
+ }
+ LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
+ output->id = id++;
+ }
+ }
+}
+
+void GPUCodegen::generate_graphs()
+{
+ set_unique_ids();
+
+ output.surface = graph_serialize(GPU_NODE_TAG_SURFACE | GPU_NODE_TAG_AOV, graph.outlink_surface);
+ output.volume = graph_serialize(GPU_NODE_TAG_VOLUME, graph.outlink_volume);
+ output.displacement = graph_serialize(GPU_NODE_TAG_DISPLACEMENT, graph.outlink_displacement);
+ output.thickness = graph_serialize(GPU_NODE_TAG_THICKNESS, graph.outlink_thickness);
+
+ if (!BLI_listbase_is_empty(&graph.material_functions)) {
+ std::stringstream eval_ss;
+ eval_ss << "\n/* Generated Functions */\n\n";
+ LISTBASE_FOREACH (GPUNodeGraphFunctionLink *, func_link, &graph.material_functions) {
+ char *fn = graph_serialize(GPU_NODE_TAG_FUNCTION, func_link->outlink);
+ eval_ss << "float " << func_link->name << "() {\n" << fn << "}\n\n";
+ MEM_SAFE_FREE(fn);
+ }
+ output.material_functions = extract_c_str(eval_ss);
+ }
+
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph.attributes) {
+ BLI_hash_mm2a_add(&hm2a_, (uchar *)attr->name, strlen(attr->name));
+ }
+
+ hash_ = BLI_hash_mm2a_end(&hm2a_);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GPUPass
+ * \{ */
+
+GPUPass *GPU_generate_pass(GPUMaterial *material,
+ GPUNodeGraph *graph,
+ GPUCodegenCallbackFn finalize_source_cb,
+ void *thunk)
+{
+ /* Prune the unused nodes and extract attributes before compiling so the
+ * generated VBOs are ready to accept the future shader. */
+ gpu_node_graph_prune_unused(graph);
+ gpu_node_graph_finalize_uniform_attrs(graph);
+
+ GPUCodegen codegen(material, graph);
+ codegen.generate_graphs();
+ codegen.generate_uniform_buffer();
+
+ /* Cache lookup: Reuse shaders already compiled. */
+ GPUPass *pass_hash = gpu_pass_cache_lookup(codegen.hash_get());
+
+ /* FIXME(fclem): This is broken. Since we only check for the hash and not the full source
+ * there is no way to have a collision currently. Some advocated to only use a bigger hash. */
+ if (pass_hash && (pass_hash->next == nullptr || pass_hash->next->hash != codegen.hash_get())) {
+ if (!gpu_pass_is_valid(pass_hash)) {
+ /* Shader has already been created but failed to compile. */
+ return nullptr;
+ }
+ /* No collision, just return the pass. */
+ pass_hash->refcount += 1;
+ return pass_hash;
+ }
+
+ /* Either the shader is not compiled or there is a hash collision...
+ * continue generating the shader strings. */
+ codegen.generate_attribs();
+ codegen.generate_resources();
+ codegen.generate_library();
+
+ /* Make engine add its own code and implement the generated functions. */
+ finalize_source_cb(thunk, material, &codegen.output);
+
+ GPUPass *pass = nullptr;
+ if (pass_hash) {
+ /* Cache lookup: Reuse shaders already compiled. */
+ pass = gpu_pass_cache_resolve_collision(
+ pass_hash, codegen.output.create_info, codegen.hash_get());
+ }
+
+ if (pass) {
+ /* Cache hit. Reuse the same GPUPass and GPUShader. */
+ if (!gpu_pass_is_valid(pass)) {
+ /* Shader has already been created but failed to compile. */
+ return nullptr;
+ }
+ pass->refcount += 1;
+ }
+ else {
+ /* We still create a pass even if shader compilation
+ * fails to avoid trying to compile again and again. */
+ pass = (GPUPass *)MEM_callocN(sizeof(GPUPass), "GPUPass");
+ pass->shader = nullptr;
+ pass->refcount = 1;
+ pass->create_info = codegen.create_info;
+ pass->hash = codegen.hash_get();
+ pass->compiled = false;
+
+ codegen.create_info = nullptr;
+
+ gpu_pass_cache_insert_after(pass_hash, pass);
+ }
+ return pass;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Compilation
+ * \{ */
+
+static int count_active_texture_sampler(GPUPass *pass, GPUShader *shader)
+{
+ int num_samplers = 0;
+
+ for (const ShaderCreateInfo::Resource &res : pass->create_info->pass_resources_) {
+ if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) {
+ if (GPU_shader_get_uniform(shader, res.sampler.name.c_str()) != -1) {
+ num_samplers += 1;
+ }
+ }
+ }
+
+ return num_samplers;
+}
+
+static bool gpu_pass_shader_validate(GPUPass *pass, GPUShader *shader)
+{
+ if (shader == nullptr) {
+ return false;
+ }
+
+ /* NOTE: The only drawback of this method is that it will count a sampler
+ * used in the fragment shader and only declared (but not used) in the vertex
+ * shader as used by both. But this corner case is not happening for now. */
+ int active_samplers_len = count_active_texture_sampler(pass, shader);
+
+ /* Validate against opengl limit. */
+ if ((active_samplers_len > GPU_max_textures_frag()) ||
+ (active_samplers_len > GPU_max_textures_vert())) {
+ return false;
+ }
+
+ if (pass->create_info->geometry_source_.is_empty() == false) {
+ if (active_samplers_len > GPU_max_textures_geom()) {
+ return false;
+ }
+ }
+
+ return (active_samplers_len * 3 <= GPU_max_textures());
+}
+
+bool GPU_pass_compile(GPUPass *pass, const char *shname)
+{
+ bool success = true;
+ if (!pass->compiled) {
+ GPUShaderCreateInfo *info = reinterpret_cast<GPUShaderCreateInfo *>(
+ static_cast<ShaderCreateInfo *>(pass->create_info));
+
+ pass->create_info->name_ = shname;
+
+ GPUShader *shader = GPU_shader_create_from_info(info);
+
+ /* NOTE: Some drivers / gpu allows more active samplers than the opengl limit.
+ * We need to make sure to count active samplers to avoid undefined behavior. */
+ if (!gpu_pass_shader_validate(pass, shader)) {
+ success = false;
+ if (shader != nullptr) {
+ fprintf(stderr, "GPUShader: error: too many samplers in shader.\n");
+ GPU_shader_free(shader);
+ shader = nullptr;
+ }
+ }
+ pass->shader = shader;
+ pass->compiled = true;
+ }
+ return success;
+}
+
+GPUShader *GPU_pass_shader_get(GPUPass *pass)
+{
+ return pass->shader;
+}
+
+void GPU_pass_release(GPUPass *pass)
+{
+ BLI_assert(pass->refcount > 0);
+ pass->refcount--;
+}
+
+static void gpu_pass_free(GPUPass *pass)
+{
+ BLI_assert(pass->refcount == 0);
+ if (pass->shader) {
+ GPU_shader_free(pass->shader);
+ }
+ delete pass->create_info;
+ MEM_freeN(pass);
+}
+
+void GPU_pass_cache_garbage_collect(void)
+{
+ static int lasttime = 0;
+ const int shadercollectrate = 60; /* hardcoded for now. */
+ int ctime = (int)PIL_check_seconds_timer();
+
+ if (ctime < shadercollectrate + lasttime) {
+ return;
+ }
+
+ lasttime = ctime;
+
+ BLI_spin_lock(&pass_cache_spin);
+ GPUPass *next, **prev_pass = &pass_cache;
+ for (GPUPass *pass = pass_cache; pass; pass = next) {
+ next = pass->next;
+ if (pass->refcount == 0) {
+ /* Remove from list */
+ *prev_pass = next;
+ gpu_pass_free(pass);
+ }
+ else {
+ prev_pass = &pass->next;
+ }
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+}
+
+void GPU_pass_cache_init(void)
+{
+ BLI_spin_init(&pass_cache_spin);
+}
+
+void GPU_pass_cache_free(void)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ while (pass_cache) {
+ GPUPass *next = pass_cache->next;
+ gpu_pass_free(pass_cache);
+ pass_cache = next;
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+
+ BLI_spin_end(&pass_cache_spin);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Module
+ * \{ */
+
+void gpu_codegen_init(void)
+{
+}
+
+void gpu_codegen_exit(void)
+{
+ // BKE_world_defaults_free_gpu();
+ BKE_material_defaults_free_gpu();
+ GPU_shader_free_builtin_shaders();
+}
+
+/** \} */ \ No newline at end of file
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 0e99476d3ea..95a672c0400 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -9,36 +9,24 @@
#pragma once
+#include "GPU_material.h"
+#include "GPU_shader.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-struct GPUMaterial;
struct GPUNodeGraph;
-struct GPUShader;
-
-typedef struct GPUPass {
- struct GPUPass *next;
- struct GPUShader *shader;
- char *fragmentcode;
- char *geometrycode;
- char *vertexcode;
- char *defines;
- uint refcount; /* Orphaned GPUPasses gets freed by the garbage collector. */
- uint32_t hash; /* Identity hash generated from all GLSL code. */
- bool compiled; /* Did we already tried to compile the attached GPUShader. */
-} GPUPass;
+typedef struct GPUPass GPUPass;
/* Pass */
-GPUPass *GPU_generate_pass(struct GPUMaterial *material,
+GPUPass *GPU_generate_pass(GPUMaterial *material,
struct GPUNodeGraph *graph,
- const char *vert_code,
- const char *geom_code,
- const char *frag_lib,
- const char *defines);
-struct GPUShader *GPU_pass_shader_get(GPUPass *pass);
+ GPUCodegenCallbackFn finalize_source_cb,
+ void *thunk);
+GPUShader *GPU_pass_shader_get(GPUPass *pass);
bool GPU_pass_compile(GPUPass *pass, const char *shname);
void GPU_pass_release(GPUPass *pass);
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 7ccb0f89dc3..e97c9e9c829 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -39,7 +39,6 @@ void GPU_init(void)
gpu_shader_create_info_init();
gpu_codegen_init();
- gpu_material_library_init();
gpu_batch_init();
@@ -56,7 +55,6 @@ void GPU_exit(void)
gpu_batch_exit();
- gpu_material_library_exit();
gpu_codegen_exit();
gpu_shader_dependency_exit();
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 49732240125..711a3943a25 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -16,7 +16,6 @@
#include "DNA_scene_types.h"
#include "DNA_world_types.h"
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -27,6 +26,7 @@
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_scene.h"
+#include "BKE_world.h"
#include "NOD_shader.h"
@@ -49,56 +49,50 @@ typedef struct GPUColorBandBuilder {
} GPUColorBandBuilder;
struct GPUMaterial {
- Scene *scene; /* DEPRECATED was only useful for lights. */
- Material *ma;
-
+ /* Contains GPUShader and source code for deferred compilation.
+ * Can be shared between similar material (i.e: sharing same nodetree topology). */
+ GPUPass *pass;
+ /** UBOs for this material parameters. */
+ GPUUniformBuf *ubo;
+ /** Compilation status. Do not use if shader is not GPU_MAT_SUCCESS. */
eGPUMaterialStatus status;
-
- const void *engine_type; /* attached engine type */
- int options; /* to identify shader variations (shadow, probe, world background...) */
- bool is_volume_shader; /* is volumetric shader */
-
- /* Nodes */
+ /** Some flags about the nodetree & the needed resources. */
+ eGPUMaterialFlag flag;
+ /* Identify shader variations (shadow, probe, world background...).
+ * Should be unique even across render engines. */
+ uint64_t uuid;
+ /* Number of generated function. */
+ int generated_function_len;
+ /** Object type for attribute fetching. */
+ bool is_volume_shader;
+
+ /** DEPRECATED Currently only used for deferred compilation. */
+ Scene *scene;
+ /** Source material, might be null. */
+ Material *ma;
+ /** 1D Texture array containing all color bands. */
+ GPUTexture *coba_tex;
+ /** Builder for coba_tex. */
+ GPUColorBandBuilder *coba_builder;
+ /* Low level node graph(s). Also contains resources needed by the material. */
GPUNodeGraph graph;
- /* for binding the material */
- GPUPass *pass;
-
- /* XXX: Should be in Material. But it depends on the output node
- * used and since the output selection is different for GPUMaterial...
- */
- bool has_volume_output;
+ /** DEPRECATED: To remove. */
bool has_surface_output;
-
- /* Only used by Eevee to know which BSDF are used. */
- eGPUMatFlag flag;
-
- /* Used by 2.8 pipeline */
- GPUUniformBuf *ubo; /* UBOs for shader uniforms. */
-
- /* Eevee SSS */
+ bool has_volume_output;
+ /** DEPRECATED: To remove. */
GPUUniformBuf *sss_profile; /* UBO containing SSS profile. */
GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
- float sss_enabled;
+ bool sss_enabled;
float sss_radii[3];
int sss_samples;
bool sss_dirty;
- GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */
- GPUColorBandBuilder *coba_builder;
-
- GSet *used_libraries;
-
#ifndef NDEBUG
char name[64];
#endif
};
-enum {
- GPU_USE_SURFACE_OUTPUT = (1 << 0),
- GPU_USE_VOLUME_OUTPUT = (1 << 1),
-};
-
/* Functions */
GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat,
@@ -159,17 +153,15 @@ static void gpu_material_free_single(GPUMaterial *material)
if (material->ubo != NULL) {
GPU_uniformbuf_free(material->ubo);
}
- if (material->sss_tex_profile != NULL) {
- GPU_texture_free(material->sss_tex_profile);
+ if (material->coba_tex != NULL) {
+ GPU_texture_free(material->coba_tex);
}
if (material->sss_profile != NULL) {
GPU_uniformbuf_free(material->sss_profile);
}
- if (material->coba_tex != NULL) {
- GPU_texture_free(material->coba_tex);
+ if (material->sss_tex_profile != NULL) {
+ GPU_texture_free(material->sss_tex_profile);
}
-
- BLI_gset_free(material->used_libraries, NULL);
}
void GPU_material_free(ListBase *gpumaterial)
@@ -217,17 +209,40 @@ void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
material->ubo = GPU_uniformbuf_create_from_list(inputs, name);
}
+ListBase GPU_material_attributes(GPUMaterial *material)
+{
+ return material->graph.attributes;
+}
+
+ListBase GPU_material_textures(GPUMaterial *material)
+{
+ return material->graph.textures;
+}
+
+ListBase GPU_material_volume_grids(GPUMaterial *material)
+{
+ return material->graph.volume_grids;
+}
+
+GPUUniformAttrList *GPU_material_uniform_attributes(GPUMaterial *material)
+{
+ GPUUniformAttrList *attrs = &material->graph.uniform_attrs;
+ return attrs->count > 0 ? attrs : NULL;
+}
+
+#if 1 /* End of life code. */
/* Eevee Subsurface scattering. */
/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */
-#define SSS_SAMPLES 65
-#define SSS_EXPONENT 2.0f /* Importance sampling exponent */
+# define SSS_SAMPLES 65
+# define SSS_EXPONENT 2.0f /* Importance sampling exponent */
typedef struct GPUSssKernelData {
float kernel[SSS_SAMPLES][4];
float param[3], max_radius;
+ float avg_inv_radius;
int samples;
- int pad[3];
+ int pad[2];
} GPUSssKernelData;
BLI_STATIC_ASSERT_ALIGN(GPUSssKernelData, 16)
@@ -243,8 +258,8 @@ static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponen
}
}
-#define BURLEY_TRUNCATE 16.0f
-#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
+# define BURLEY_TRUNCATE 16.0f
+# define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
static float burley_profile(float r, float d)
{
float exp_r_3_d = expf(-r / (3.0f * d));
@@ -259,7 +274,7 @@ static float eval_profile(float r, float param)
}
/* Resolution for each sample of the precomputed kernel profile */
-#define INTEGRAL_RESOLUTION 32
+# define INTEGRAL_RESOLUTION 32
static float eval_integral(float x0, float x1, float param)
{
const float range = x1 - x0;
@@ -274,7 +289,7 @@ static float eval_integral(float x0, float x1, float param)
return integral;
}
-#undef INTEGRAL_RESOLUTION
+# undef INTEGRAL_RESOLUTION
static void compute_sss_kernel(GPUSssKernelData *kd, const float radii[3], int sample_len)
{
@@ -284,6 +299,8 @@ static void compute_sss_kernel(GPUSssKernelData *kd, const float radii[3], int s
rad[1] = MAX2(radii[1], 1e-15f);
rad[2] = MAX2(radii[2], 1e-15f);
+ kd->avg_inv_radius = 3.0f / (rad[0] + rad[1] + rad[2]);
+
/* Christensen-Burley fitting */
float l[3], d[3];
@@ -358,7 +375,7 @@ static void compute_sss_kernel(GPUSssKernelData *kd, const float radii[3], int s
kd->samples = sample_len;
}
-#define INTEGRAL_RESOLUTION 512
+# define INTEGRAL_RESOLUTION 512
static void compute_sss_translucence_kernel(const GPUSssKernelData *kd,
int resolution,
float **output)
@@ -417,10 +434,14 @@ static void compute_sss_translucence_kernel(const GPUSssKernelData *kd,
mul_v3_fl(texels[resolution - 3], 0.5f);
mul_v3_fl(texels[resolution - 4], 0.75f);
}
-#undef INTEGRAL_RESOLUTION
+# undef INTEGRAL_RESOLUTION
-void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3])
+bool GPU_material_sss_profile_create(GPUMaterial *material, float radii[3])
{
+ /* Enable only once. */
+ if (material->sss_enabled) {
+ return false;
+ }
copy_v3_v3(material->sss_radii, radii);
material->sss_dirty = true;
material->sss_enabled = true;
@@ -429,6 +450,7 @@ void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3])
if (material->sss_profile == NULL) {
material->sss_profile = GPU_uniformbuf_create(sizeof(GPUSssKernelData));
}
+ return true;
}
struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material,
@@ -475,34 +497,37 @@ struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void)
return GPU_uniformbuf_create(sizeof(GPUSssKernelData));
}
-#undef SSS_EXPONENT
-#undef SSS_SAMPLES
-
-ListBase GPU_material_attributes(GPUMaterial *material)
-{
- return material->graph.attributes;
-}
+# undef SSS_EXPONENT
+# undef SSS_SAMPLES
+#endif
-ListBase GPU_material_textures(GPUMaterial *material)
+void GPU_material_output_surface(GPUMaterial *material, GPUNodeLink *link)
{
- return material->graph.textures;
+ if (!material->graph.outlink_surface) {
+ material->graph.outlink_surface = link;
+ material->has_surface_output = true;
+ }
}
-ListBase GPU_material_volume_grids(GPUMaterial *material)
+void GPU_material_output_volume(GPUMaterial *material, GPUNodeLink *link)
{
- return material->graph.volume_grids;
+ if (!material->graph.outlink_volume) {
+ material->graph.outlink_volume = link;
+ material->has_volume_output = true;
+ }
}
-GPUUniformAttrList *GPU_material_uniform_attributes(GPUMaterial *material)
+void GPU_material_output_displacement(GPUMaterial *material, GPUNodeLink *link)
{
- GPUUniformAttrList *attrs = &material->graph.uniform_attrs;
- return attrs->count > 0 ? attrs : NULL;
+ if (!material->graph.outlink_displacement) {
+ material->graph.outlink_displacement = link;
+ }
}
-void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
+void GPU_material_output_thickness(GPUMaterial *material, GPUNodeLink *link)
{
- if (!material->graph.outlink) {
- material->graph.outlink = link;
+ if (!material->graph.outlink_thickness) {
+ material->graph.outlink_thickness = link;
}
}
@@ -514,23 +539,71 @@ void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link,
BLI_addtail(&material->graph.outlink_aovs, aov_link);
}
+char *GPU_material_split_sub_function(GPUMaterial *material,
+ eGPUType return_type,
+ GPUNodeLink **link)
+{
+ /* Force cast to return type. */
+ switch (return_type) {
+ case GPU_FLOAT:
+ GPU_link(material, "set_value", *link, link);
+ break;
+ case GPU_VEC3:
+ GPU_link(material, "set_rgb", *link, link);
+ break;
+ case GPU_VEC4:
+ GPU_link(material, "set_rgba", *link, link);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ GPUNodeGraphFunctionLink *func_link = MEM_callocN(sizeof(GPUNodeGraphFunctionLink), __func__);
+ func_link->outlink = *link;
+ SNPRINTF(func_link->name, "ntree_fn%d", material->generated_function_len++);
+ BLI_addtail(&material->graph.material_functions, func_link);
+
+ /* Set value to break the link with the main graph. */
+ switch (return_type) {
+ case GPU_FLOAT:
+ GPU_link(material, "set_value_one", link);
+ break;
+ case GPU_VEC3:
+ GPU_link(material, "set_rgb_one", link);
+ break;
+ case GPU_VEC4:
+ GPU_link(material, "set_rgba_one", link);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ return func_link->name;
+}
+
GPUNodeGraph *gpu_material_node_graph(GPUMaterial *material)
{
return &material->graph;
}
-GSet *gpu_material_used_libraries(GPUMaterial *material)
+eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
{
- return material->used_libraries;
+ return mat->status;
}
-eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
+void GPU_material_status_set(GPUMaterial *mat, eGPUMaterialStatus status)
{
- return mat->status;
+ mat->status = status;
}
/* Code generation */
+bool GPU_material_is_volume_shader(GPUMaterial *mat)
+{
+ return mat->is_volume_shader;
+}
+
bool GPU_material_has_surface_output(GPUMaterial *mat)
{
return mat->has_surface_output;
@@ -541,100 +614,79 @@ bool GPU_material_has_volume_output(GPUMaterial *mat)
return mat->has_volume_output;
}
-bool GPU_material_is_volume_shader(GPUMaterial *mat)
+void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag)
{
- return mat->is_volume_shader;
+ mat->flag |= flag;
}
-void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag)
+bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag)
{
- mat->flag |= flag;
+ return (mat->flag & flag) != 0;
}
-bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag)
+eGPUMaterialFlag GPU_material_flag(const GPUMaterial *mat)
{
- return (mat->flag & flag) != 0;
+ return mat->flag;
}
-GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials,
- const void *engine_type,
- int options)
+/* Note: Consumes the flags. */
+bool GPU_material_recalc_flag_get(GPUMaterial *mat)
{
- LISTBASE_FOREACH (LinkData *, link, gpumaterials) {
- GPUMaterial *current_material = (GPUMaterial *)link->data;
- if (current_material->engine_type == engine_type && current_material->options == options) {
- return current_material;
- }
- }
+ bool updated = (mat->flag & GPU_MATFLAG_UPDATED) != 0;
+ mat->flag &= ~GPU_MATFLAG_UPDATED;
+ return updated;
+}
- return NULL;
+uint64_t GPU_material_uuid_get(GPUMaterial *mat)
+{
+ return mat->uuid;
}
GPUMaterial *GPU_material_from_nodetree(Scene *scene,
- struct Material *ma,
- struct bNodeTree *ntree,
+ Material *ma,
+ bNodeTree *ntree,
ListBase *gpumaterials,
- const void *engine_type,
- const int options,
- const bool is_volume_shader,
- const char *vert_code,
- const char *geom_code,
- const char *frag_lib,
- const char *defines,
const char *name,
- GPUMaterialEvalCallbackFn callback)
+ uint64_t shader_uuid,
+ bool is_volume_shader,
+ bool is_lookdev,
+ GPUCodegenCallbackFn callback,
+ void *thunk)
{
- LinkData *link;
- bool has_volume_output, has_surface_output;
-
- /* Caller must re-use materials. */
- BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
-
- /* HACK: Eevee assume this to create #GHash keys. */
- BLI_assert(sizeof(GPUPass) > 16);
+ /* Search if this material is not already compiled. */
+ LISTBASE_FOREACH (LinkData *, link, gpumaterials) {
+ GPUMaterial *mat = (GPUMaterial *)link->data;
+ if (mat->uuid == shader_uuid) {
+ return mat;
+ }
+ }
- /* allocate material */
GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
mat->ma = ma;
mat->scene = scene;
- mat->engine_type = engine_type;
- mat->options = options;
+ mat->uuid = shader_uuid;
+ mat->flag = GPU_MATFLAG_UPDATED;
mat->is_volume_shader = is_volume_shader;
+ mat->graph.used_libraries = BLI_gset_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries");
#ifndef NDEBUG
BLI_snprintf(mat->name, sizeof(mat->name), "%s", name);
#else
UNUSED_VARS(name);
#endif
+ if (is_lookdev) {
+ mat->flag |= GPU_MATFLAG_LOOKDEV_HACK;
+ }
- mat->used_libraries = BLI_gset_new(
- BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUMaterial.used_libraries");
-
- /* localize tree to create links for reroute and mute */
+ /* Localize tree to create links for reroute and mute. */
bNodeTree *localtree = ntreeLocalize(ntree);
- ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output);
+ ntreeGPUMaterialNodes(localtree, mat);
gpu_material_ramp_texture_build(mat);
- mat->has_surface_output = has_surface_output;
- mat->has_volume_output = has_volume_output;
-
- if (mat->graph.outlink) {
- if (callback) {
- callback(mat, options, &vert_code, &geom_code, &frag_lib, &defines);
- }
- /* HACK: this is only for eevee. We add the define here after the nodetree evaluation. */
- if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) {
- defines = BLI_string_joinN(defines,
- "#ifndef USE_ALPHA_BLEND\n"
- "# define USE_SSS\n"
- "#endif\n");
- }
+ {
/* Create source code and search pass cache for an already compiled version. */
- mat->pass = GPU_generate_pass(mat, &mat->graph, vert_code, geom_code, frag_lib, defines);
-
- if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) {
- MEM_freeN((char *)defines);
- }
+ mat->pass = GPU_generate_pass(mat, &mat->graph, callback, thunk);
if (mat->pass == NULL) {
/* We had a cache hit and the shader has already failed to compile. */
@@ -649,26 +701,20 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
gpu_node_graph_free_nodes(&mat->graph);
}
else {
- mat->status = GPU_MAT_QUEUED;
+ mat->status = GPU_MAT_CREATED;
}
}
}
- else {
- mat->status = GPU_MAT_FAILED;
- gpu_node_graph_free(&mat->graph);
- }
- /* Only free after GPU_pass_shader_get where GPUUniformBuf
- * read data from the local tree. */
+ /* Only free after GPU_pass_shader_get where GPUUniformBuf read data from the local tree. */
ntreeFreeLocalTree(localtree);
BLI_assert(!localtree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
MEM_freeN(localtree);
- /* note that even if building the shader fails in some way, we still keep
+ /* Note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simply do not use
- * the actual shader on drawing */
-
- link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
+ * the actual shader on drawing. */
+ LinkData *link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
link->data = mat;
BLI_addtail(gpumaterials, link);
@@ -690,6 +736,8 @@ void GPU_material_compile(GPUMaterial *mat)
success = GPU_pass_compile(mat->pass, __func__);
#endif
+ mat->flag |= GPU_MATFLAG_UPDATED;
+
if (success) {
GPUShader *sh = GPU_pass_shader_get(mat->pass);
if (sh != NULL) {
@@ -715,5 +763,6 @@ void GPU_materials_free(Main *bmain)
GPU_material_free(&wo->gpumaterial);
}
+ // BKE_world_defaults_free_gpu();
BKE_material_defaults_free_gpu();
}
diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c
deleted file mode 100644
index ca5c3d4bb45..00000000000
--- a/source/blender/gpu/intern/gpu_material_library.c
+++ /dev/null
@@ -1,904 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later
- * Copyright 2005 Blender Foundation. All rights reserved. */
-
-/** \file
- * \ingroup gpu
- *
- * GPU material library parsing and code generation.
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_dynstr.h"
-#include "BLI_ghash.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
-
-#include "gpu_material_library.h"
-
-/* List of all gpu_shader_material_*.glsl files used by GLSL materials. These
- * will be parsed to make all functions in them available to use for GPU_link().
- *
- * If a file uses functions from another file, it must be added to the list of
- * dependencies, and be placed after that file in the list. */
-
-extern char datatoc_gpu_shader_material_add_shader_glsl[];
-extern char datatoc_gpu_shader_material_ambient_occlusion_glsl[];
-extern char datatoc_gpu_shader_material_anisotropic_glsl[];
-extern char datatoc_gpu_shader_material_attribute_glsl[];
-extern char datatoc_gpu_shader_material_background_glsl[];
-extern char datatoc_gpu_shader_material_bevel_glsl[];
-extern char datatoc_gpu_shader_material_wavelength_glsl[];
-extern char datatoc_gpu_shader_material_blackbody_glsl[];
-extern char datatoc_gpu_shader_material_bright_contrast_glsl[];
-extern char datatoc_gpu_shader_material_bump_glsl[];
-extern char datatoc_gpu_shader_material_camera_glsl[];
-extern char datatoc_gpu_shader_material_clamp_glsl[];
-extern char datatoc_gpu_shader_material_color_ramp_glsl[];
-extern char datatoc_gpu_shader_material_color_util_glsl[];
-extern char datatoc_gpu_shader_material_combine_hsv_glsl[];
-extern char datatoc_gpu_shader_material_combine_rgb_glsl[];
-extern char datatoc_gpu_shader_material_combine_xyz_glsl[];
-extern char datatoc_gpu_shader_material_diffuse_glsl[];
-extern char datatoc_gpu_shader_material_displacement_glsl[];
-extern char datatoc_gpu_shader_material_eevee_specular_glsl[];
-extern char datatoc_gpu_shader_material_emission_glsl[];
-extern char datatoc_gpu_shader_material_float_curve_glsl[];
-extern char datatoc_gpu_shader_material_fractal_noise_glsl[];
-extern char datatoc_gpu_shader_material_fresnel_glsl[];
-extern char datatoc_gpu_shader_material_gamma_glsl[];
-extern char datatoc_gpu_shader_material_geometry_glsl[];
-extern char datatoc_gpu_shader_material_glass_glsl[];
-extern char datatoc_gpu_shader_material_glossy_glsl[];
-extern char datatoc_gpu_shader_material_hair_info_glsl[];
-extern char datatoc_gpu_shader_material_hash_glsl[];
-extern char datatoc_gpu_shader_material_holdout_glsl[];
-extern char datatoc_gpu_shader_material_hue_sat_val_glsl[];
-extern char datatoc_gpu_shader_material_invert_glsl[];
-extern char datatoc_gpu_shader_material_layer_weight_glsl[];
-extern char datatoc_gpu_shader_material_light_falloff_glsl[];
-extern char datatoc_gpu_shader_material_light_path_glsl[];
-extern char datatoc_gpu_shader_material_mapping_glsl[];
-extern char datatoc_gpu_shader_material_map_range_glsl[];
-extern char datatoc_gpu_shader_material_math_glsl[];
-extern char datatoc_gpu_shader_material_math_util_glsl[];
-extern char datatoc_gpu_shader_material_mix_rgb_glsl[];
-extern char datatoc_gpu_shader_material_mix_shader_glsl[];
-extern char datatoc_gpu_shader_material_noise_glsl[];
-extern char datatoc_gpu_shader_material_normal_glsl[];
-extern char datatoc_gpu_shader_material_normal_map_glsl[];
-extern char datatoc_gpu_shader_material_object_info_glsl[];
-extern char datatoc_gpu_shader_material_output_aov_glsl[];
-extern char datatoc_gpu_shader_material_output_material_glsl[];
-extern char datatoc_gpu_shader_material_output_world_glsl[];
-extern char datatoc_gpu_shader_material_particle_info_glsl[];
-extern char datatoc_gpu_shader_material_point_info_glsl[];
-extern char datatoc_gpu_shader_material_principled_glsl[];
-extern char datatoc_gpu_shader_material_refraction_glsl[];
-extern char datatoc_gpu_shader_material_rgb_curves_glsl[];
-extern char datatoc_gpu_shader_material_rgb_to_bw_glsl[];
-extern char datatoc_gpu_shader_material_separate_hsv_glsl[];
-extern char datatoc_gpu_shader_material_separate_rgb_glsl[];
-extern char datatoc_gpu_shader_material_separate_xyz_glsl[];
-extern char datatoc_gpu_shader_material_set_glsl[];
-extern char datatoc_gpu_shader_material_shader_to_rgba_glsl[];
-extern char datatoc_gpu_shader_material_squeeze_glsl[];
-extern char datatoc_gpu_shader_material_subsurface_scattering_glsl[];
-extern char datatoc_gpu_shader_material_tangent_glsl[];
-extern char datatoc_gpu_shader_material_tex_brick_glsl[];
-extern char datatoc_gpu_shader_material_tex_checker_glsl[];
-extern char datatoc_gpu_shader_material_tex_environment_glsl[];
-extern char datatoc_gpu_shader_material_tex_gradient_glsl[];
-extern char datatoc_gpu_shader_material_tex_image_glsl[];
-extern char datatoc_gpu_shader_material_tex_magic_glsl[];
-extern char datatoc_gpu_shader_material_tex_musgrave_glsl[];
-extern char datatoc_gpu_shader_material_tex_noise_glsl[];
-extern char datatoc_gpu_shader_material_tex_sky_glsl[];
-extern char datatoc_gpu_shader_material_texture_coordinates_glsl[];
-extern char datatoc_gpu_shader_material_tex_voronoi_glsl[];
-extern char datatoc_gpu_shader_material_tex_wave_glsl[];
-extern char datatoc_gpu_shader_material_tex_white_noise_glsl[];
-extern char datatoc_gpu_shader_material_toon_glsl[];
-extern char datatoc_gpu_shader_material_translucent_glsl[];
-extern char datatoc_gpu_shader_material_transparent_glsl[];
-extern char datatoc_gpu_shader_material_uv_map_glsl[];
-extern char datatoc_gpu_shader_material_vector_curves_glsl[];
-extern char datatoc_gpu_shader_material_vector_displacement_glsl[];
-extern char datatoc_gpu_shader_material_vector_math_glsl[];
-extern char datatoc_gpu_shader_material_vector_rotate_glsl[];
-extern char datatoc_gpu_shader_material_velvet_glsl[];
-extern char datatoc_gpu_shader_material_vertex_color_glsl[];
-extern char datatoc_gpu_shader_material_volume_absorption_glsl[];
-extern char datatoc_gpu_shader_material_volume_info_glsl[];
-extern char datatoc_gpu_shader_material_volume_principled_glsl[];
-extern char datatoc_gpu_shader_material_volume_scatter_glsl[];
-extern char datatoc_gpu_shader_material_wireframe_glsl[];
-extern char datatoc_gpu_shader_material_world_normals_glsl[];
-
-static GPUMaterialLibrary gpu_shader_material_math_util_library = {
- .code = datatoc_gpu_shader_material_math_util_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_color_util_library = {
- .code = datatoc_gpu_shader_material_color_util_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_hash_library = {
- .code = datatoc_gpu_shader_material_hash_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_noise_library = {
- .code = datatoc_gpu_shader_material_noise_glsl,
- .dependencies = {&gpu_shader_material_hash_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_fractal_noise_library = {
- .code = datatoc_gpu_shader_material_fractal_noise_glsl,
- .dependencies = {&gpu_shader_material_noise_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_add_shader_library = {
- .code = datatoc_gpu_shader_material_add_shader_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_ambient_occlusion_library = {
- .code = datatoc_gpu_shader_material_ambient_occlusion_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_glossy_library = {
- .code = datatoc_gpu_shader_material_glossy_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_anisotropic_library = {
- .code = datatoc_gpu_shader_material_anisotropic_glsl,
- .dependencies = {&gpu_shader_material_glossy_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_attribute_library = {
- .code = datatoc_gpu_shader_material_attribute_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_background_library = {
- .code = datatoc_gpu_shader_material_background_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_bevel_library = {
- .code = datatoc_gpu_shader_material_bevel_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_wavelength_library = {
- .code = datatoc_gpu_shader_material_wavelength_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_blackbody_library = {
- .code = datatoc_gpu_shader_material_blackbody_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_bright_contrast_library = {
- .code = datatoc_gpu_shader_material_bright_contrast_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_bump_library = {
- .code = datatoc_gpu_shader_material_bump_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_camera_library = {
- .code = datatoc_gpu_shader_material_camera_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_clamp_library = {
- .code = datatoc_gpu_shader_material_clamp_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_color_ramp_library = {
- .code = datatoc_gpu_shader_material_color_ramp_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_combine_hsv_library = {
- .code = datatoc_gpu_shader_material_combine_hsv_glsl,
- .dependencies = {&gpu_shader_material_color_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_combine_rgb_library = {
- .code = datatoc_gpu_shader_material_combine_rgb_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_combine_xyz_library = {
- .code = datatoc_gpu_shader_material_combine_xyz_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_diffuse_library = {
- .code = datatoc_gpu_shader_material_diffuse_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_displacement_library = {
- .code = datatoc_gpu_shader_material_displacement_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_eevee_specular_library = {
- .code = datatoc_gpu_shader_material_eevee_specular_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_emission_library = {
- .code = datatoc_gpu_shader_material_emission_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_float_curve_library = {
- .code = datatoc_gpu_shader_material_float_curve_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_fresnel_library = {
- .code = datatoc_gpu_shader_material_fresnel_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_gamma_library = {
- .code = datatoc_gpu_shader_material_gamma_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tangent_library = {
- .code = datatoc_gpu_shader_material_tangent_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_geometry_library = {
- .code = datatoc_gpu_shader_material_geometry_glsl,
- .dependencies = {&gpu_shader_material_tangent_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_glass_library = {
- .code = datatoc_gpu_shader_material_glass_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_hair_info_library = {
- .code = datatoc_gpu_shader_material_hair_info_glsl,
- .dependencies = {&gpu_shader_material_hash_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_holdout_library = {
- .code = datatoc_gpu_shader_material_holdout_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_hue_sat_val_library = {
- .code = datatoc_gpu_shader_material_hue_sat_val_glsl,
- .dependencies = {&gpu_shader_material_color_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_invert_library = {
- .code = datatoc_gpu_shader_material_invert_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_layer_weight_library = {
- .code = datatoc_gpu_shader_material_layer_weight_glsl,
- .dependencies = {&gpu_shader_material_fresnel_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_light_falloff_library = {
- .code = datatoc_gpu_shader_material_light_falloff_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_light_path_library = {
- .code = datatoc_gpu_shader_material_light_path_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_mapping_library = {
- .code = datatoc_gpu_shader_material_mapping_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_map_range_library = {
- .code = datatoc_gpu_shader_material_map_range_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_math_library = {
- .code = datatoc_gpu_shader_material_math_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_mix_rgb_library = {
- .code = datatoc_gpu_shader_material_mix_rgb_glsl,
- .dependencies = {&gpu_shader_material_color_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_mix_shader_library = {
- .code = datatoc_gpu_shader_material_mix_shader_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_normal_library = {
- .code = datatoc_gpu_shader_material_normal_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_normal_map_library = {
- .code = datatoc_gpu_shader_material_normal_map_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_object_info_library = {
- .code = datatoc_gpu_shader_material_object_info_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_output_aov_library = {
- .code = datatoc_gpu_shader_material_output_aov_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_output_material_library = {
- .code = datatoc_gpu_shader_material_output_material_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_output_world_library = {
- .code = datatoc_gpu_shader_material_output_world_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_particle_info_library = {
- .code = datatoc_gpu_shader_material_particle_info_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_point_info_library = {
- .code = datatoc_gpu_shader_material_point_info_glsl,
- .dependencies = {&gpu_shader_material_hash_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_principled_library = {
- .code = datatoc_gpu_shader_material_principled_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_refraction_library = {
- .code = datatoc_gpu_shader_material_refraction_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_rgb_curves_library = {
- .code = datatoc_gpu_shader_material_rgb_curves_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_rgb_to_bw_library = {
- .code = datatoc_gpu_shader_material_rgb_to_bw_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_separate_hsv_library = {
- .code = datatoc_gpu_shader_material_separate_hsv_glsl,
- .dependencies = {&gpu_shader_material_color_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_separate_rgb_library = {
- .code = datatoc_gpu_shader_material_separate_rgb_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_separate_xyz_library = {
- .code = datatoc_gpu_shader_material_separate_xyz_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_set_library = {
- .code = datatoc_gpu_shader_material_set_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_shader_to_rgba_library = {
- .code = datatoc_gpu_shader_material_shader_to_rgba_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_squeeze_library = {
- .code = datatoc_gpu_shader_material_squeeze_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_subsurface_scattering_library = {
- .code = datatoc_gpu_shader_material_subsurface_scattering_glsl,
- .dependencies = {&gpu_shader_material_diffuse_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_brick_library = {
- .code = datatoc_gpu_shader_material_tex_brick_glsl,
- .dependencies = {&gpu_shader_material_math_util_library,
- &gpu_shader_material_hash_library,
- NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_checker_library = {
- .code = datatoc_gpu_shader_material_tex_checker_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_environment_library = {
- .code = datatoc_gpu_shader_material_tex_environment_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_gradient_library = {
- .code = datatoc_gpu_shader_material_tex_gradient_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_image_library = {
- .code = datatoc_gpu_shader_material_tex_image_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_magic_library = {
- .code = datatoc_gpu_shader_material_tex_magic_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_musgrave_library = {
- .code = datatoc_gpu_shader_material_tex_musgrave_glsl,
- .dependencies = {&gpu_shader_material_noise_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_noise_library = {
- .code = datatoc_gpu_shader_material_tex_noise_glsl,
- .dependencies = {&gpu_shader_material_fractal_noise_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_sky_library = {
- .code = datatoc_gpu_shader_material_tex_sky_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_texture_coordinates_library = {
- .code = datatoc_gpu_shader_material_texture_coordinates_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_voronoi_library = {
- .code = datatoc_gpu_shader_material_tex_voronoi_glsl,
- .dependencies = {&gpu_shader_material_math_util_library,
- &gpu_shader_material_hash_library,
- NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_wave_library = {
- .code = datatoc_gpu_shader_material_tex_wave_glsl,
- .dependencies = {&gpu_shader_material_fractal_noise_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_white_noise_library = {
- .code = datatoc_gpu_shader_material_tex_white_noise_glsl,
- .dependencies = {&gpu_shader_material_hash_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_toon_library = {
- .code = datatoc_gpu_shader_material_toon_glsl,
- .dependencies = {&gpu_shader_material_diffuse_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_translucent_library = {
- .code = datatoc_gpu_shader_material_translucent_glsl,
- .dependencies = {&gpu_shader_material_diffuse_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_transparent_library = {
- .code = datatoc_gpu_shader_material_transparent_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_uv_map_library = {
- .code = datatoc_gpu_shader_material_uv_map_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_vector_curves_library = {
- .code = datatoc_gpu_shader_material_vector_curves_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_vector_displacement_library = {
- .code = datatoc_gpu_shader_material_vector_displacement_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_vector_math_library = {
- .code = datatoc_gpu_shader_material_vector_math_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_vector_rotate_library = {
- .code = datatoc_gpu_shader_material_vector_rotate_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_velvet_library = {
- .code = datatoc_gpu_shader_material_velvet_glsl,
- .dependencies = {&gpu_shader_material_diffuse_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_vertex_color_library = {
- .code = datatoc_gpu_shader_material_vertex_color_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_volume_absorption_library = {
- .code = datatoc_gpu_shader_material_volume_absorption_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_volume_info_library = {
- .code = datatoc_gpu_shader_material_volume_info_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_volume_principled_library = {
- .code = datatoc_gpu_shader_material_volume_principled_glsl,
- .dependencies = {&gpu_shader_material_blackbody_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_volume_scatter_library = {
- .code = datatoc_gpu_shader_material_volume_scatter_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_wireframe_library = {
- .code = datatoc_gpu_shader_material_wireframe_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_world_normals_library = {
- .code = datatoc_gpu_shader_material_world_normals_glsl,
- .dependencies = {&gpu_shader_material_texture_coordinates_library, NULL},
-};
-
-static GPUMaterialLibrary *gpu_material_libraries[] = {
- &gpu_shader_material_math_util_library,
- &gpu_shader_material_color_util_library,
- &gpu_shader_material_hash_library,
- &gpu_shader_material_noise_library,
- &gpu_shader_material_float_curve_library,
- &gpu_shader_material_fractal_noise_library,
- &gpu_shader_material_add_shader_library,
- &gpu_shader_material_ambient_occlusion_library,
- &gpu_shader_material_glossy_library,
- &gpu_shader_material_anisotropic_library,
- &gpu_shader_material_attribute_library,
- &gpu_shader_material_background_library,
- &gpu_shader_material_bevel_library,
- &gpu_shader_material_wavelength_library,
- &gpu_shader_material_blackbody_library,
- &gpu_shader_material_bright_contrast_library,
- &gpu_shader_material_bump_library,
- &gpu_shader_material_camera_library,
- &gpu_shader_material_clamp_library,
- &gpu_shader_material_color_ramp_library,
- &gpu_shader_material_combine_hsv_library,
- &gpu_shader_material_combine_rgb_library,
- &gpu_shader_material_combine_xyz_library,
- &gpu_shader_material_diffuse_library,
- &gpu_shader_material_displacement_library,
- &gpu_shader_material_eevee_specular_library,
- &gpu_shader_material_emission_library,
- &gpu_shader_material_fresnel_library,
- &gpu_shader_material_gamma_library,
- &gpu_shader_material_tangent_library,
- &gpu_shader_material_geometry_library,
- &gpu_shader_material_glass_library,
- &gpu_shader_material_hair_info_library,
- &gpu_shader_material_holdout_library,
- &gpu_shader_material_hue_sat_val_library,
- &gpu_shader_material_invert_library,
- &gpu_shader_material_layer_weight_library,
- &gpu_shader_material_light_falloff_library,
- &gpu_shader_material_light_path_library,
- &gpu_shader_material_mapping_library,
- &gpu_shader_material_map_range_library,
- &gpu_shader_material_math_library,
- &gpu_shader_material_mix_rgb_library,
- &gpu_shader_material_mix_shader_library,
- &gpu_shader_material_normal_library,
- &gpu_shader_material_normal_map_library,
- &gpu_shader_material_object_info_library,
- &gpu_shader_material_output_aov_library,
- &gpu_shader_material_output_material_library,
- &gpu_shader_material_output_world_library,
- &gpu_shader_material_particle_info_library,
- &gpu_shader_material_point_info_library,
- &gpu_shader_material_principled_library,
- &gpu_shader_material_refraction_library,
- &gpu_shader_material_rgb_curves_library,
- &gpu_shader_material_rgb_to_bw_library,
- &gpu_shader_material_separate_hsv_library,
- &gpu_shader_material_separate_rgb_library,
- &gpu_shader_material_separate_xyz_library,
- &gpu_shader_material_set_library,
- &gpu_shader_material_shader_to_rgba_library,
- &gpu_shader_material_squeeze_library,
- &gpu_shader_material_subsurface_scattering_library,
- &gpu_shader_material_tex_brick_library,
- &gpu_shader_material_tex_checker_library,
- &gpu_shader_material_tex_environment_library,
- &gpu_shader_material_tex_gradient_library,
- &gpu_shader_material_tex_image_library,
- &gpu_shader_material_tex_magic_library,
- &gpu_shader_material_tex_musgrave_library,
- &gpu_shader_material_tex_noise_library,
- &gpu_shader_material_tex_sky_library,
- &gpu_shader_material_texture_coordinates_library,
- &gpu_shader_material_tex_voronoi_library,
- &gpu_shader_material_tex_wave_library,
- &gpu_shader_material_tex_white_noise_library,
- &gpu_shader_material_toon_library,
- &gpu_shader_material_translucent_library,
- &gpu_shader_material_transparent_library,
- &gpu_shader_material_uv_map_library,
- &gpu_shader_material_vector_curves_library,
- &gpu_shader_material_vector_displacement_library,
- &gpu_shader_material_vector_math_library,
- &gpu_shader_material_vector_rotate_library,
- &gpu_shader_material_velvet_library,
- &gpu_shader_material_vertex_color_library,
- &gpu_shader_material_volume_absorption_library,
- &gpu_shader_material_volume_info_library,
- &gpu_shader_material_volume_principled_library,
- &gpu_shader_material_volume_scatter_library,
- &gpu_shader_material_wireframe_library,
- &gpu_shader_material_world_normals_library,
- NULL};
-
-/* GLSL code parsing for finding function definitions.
- * These are stored in a hash for lookup when creating a material. */
-
-static GHash *FUNCTION_HASH = NULL;
-
-const char *gpu_str_skip_token(const char *str, char *token, int max)
-{
- int len = 0;
-
- /* skip a variable/function name */
- while (*str) {
- if (ELEM(*str, ' ', '(', ')', ',', ';', '\t', '\n', '\r')) {
- break;
- }
-
- if (token && len < max - 1) {
- *token = *str;
- token++;
- len++;
- }
- str++;
- }
-
- if (token) {
- *token = '\0';
- }
-
- /* skip the next special characters:
- * note the missing ')' */
- while (*str) {
- if (ELEM(*str, ' ', '(', ',', ';', '\t', '\n', '\r')) {
- str++;
- }
- else {
- break;
- }
- }
-
- return str;
-}
-
-/* Indices match the eGPUType enum */
-static const char *GPU_DATATYPE_STR[17] = {
- "",
- "float",
- "vec2",
- "vec3",
- "vec4",
- NULL,
- NULL,
- NULL,
- NULL,
- "mat3",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "mat4",
-};
-
-const char *gpu_data_type_to_string(const eGPUType type)
-{
- return GPU_DATATYPE_STR[type];
-}
-
-static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library)
-{
- GPUFunction *function;
- eGPUType type;
- GPUFunctionQual qual;
- int i;
- const char *code = library->code;
-
- while ((code = strstr(code, "void "))) {
- function = MEM_callocN(sizeof(GPUFunction), "GPUFunction");
- function->library = library;
-
- code = gpu_str_skip_token(code, NULL, 0);
- code = gpu_str_skip_token(code, function->name, MAX_FUNCTION_NAME);
-
- /* get parameters */
- while (*code && *code != ')') {
- if (BLI_str_startswith(code, "const ")) {
- code = gpu_str_skip_token(code, NULL, 0);
- }
-
- /* test if it's an input or output */
- qual = FUNCTION_QUAL_IN;
- if (BLI_str_startswith(code, "out ")) {
- qual = FUNCTION_QUAL_OUT;
- }
- if (BLI_str_startswith(code, "inout ")) {
- qual = FUNCTION_QUAL_INOUT;
- }
- if ((qual != FUNCTION_QUAL_IN) || BLI_str_startswith(code, "in ")) {
- code = gpu_str_skip_token(code, NULL, 0);
- }
-
- /* test for type */
- type = GPU_NONE;
- for (i = 1; i < ARRAY_SIZE(GPU_DATATYPE_STR); i++) {
- if (GPU_DATATYPE_STR[i] && BLI_str_startswith(code, GPU_DATATYPE_STR[i])) {
- type = i;
- break;
- }
- }
-
- if (!type && BLI_str_startswith(code, "samplerCube")) {
- type = GPU_TEXCUBE;
- }
- if (!type && BLI_str_startswith(code, "sampler2DShadow")) {
- type = GPU_SHADOW2D;
- }
- if (!type && BLI_str_startswith(code, "sampler1DArray")) {
- type = GPU_TEX1D_ARRAY;
- }
- if (!type && BLI_str_startswith(code, "sampler2DArray")) {
- type = GPU_TEX2D_ARRAY;
- }
- if (!type && BLI_str_startswith(code, "sampler2D")) {
- type = GPU_TEX2D;
- }
- if (!type && BLI_str_startswith(code, "sampler3D")) {
- type = GPU_TEX3D;
- }
-
- if (!type && BLI_str_startswith(code, "Closure")) {
- type = GPU_CLOSURE;
- }
-
- if (type) {
- /* add parameter */
- code = gpu_str_skip_token(code, NULL, 0);
- code = gpu_str_skip_token(code, NULL, 0);
- function->paramqual[function->totparam] = qual;
- function->paramtype[function->totparam] = type;
- function->totparam++;
- }
- else {
- fprintf(stderr, "GPU invalid function parameter in %s.\n", function->name);
- break;
- }
- }
-
- if (function->name[0] == '\0' || function->totparam == 0) {
- fprintf(stderr, "GPU functions parse error.\n");
- MEM_freeN(function);
- break;
- }
-
- BLI_ghash_insert(hash, function->name, function);
- }
-}
-
-/* Module */
-
-void gpu_material_library_init(void)
-{
- /* Only parse GLSL shader files once. */
- if (FUNCTION_HASH) {
- return;
- }
-
- FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh");
- for (int i = 0; gpu_material_libraries[i]; i++) {
- gpu_parse_material_library(FUNCTION_HASH, gpu_material_libraries[i]);
- }
-}
-
-void gpu_material_library_exit(void)
-{
- if (FUNCTION_HASH) {
- BLI_ghash_free(FUNCTION_HASH, NULL, MEM_freeN);
- FUNCTION_HASH = NULL;
- }
-}
-
-/* Code Generation */
-
-static void gpu_material_use_library_with_dependencies(GSet *used_libraries,
- GPUMaterialLibrary *library)
-{
- if (BLI_gset_add(used_libraries, library->code)) {
- for (int i = 0; library->dependencies[i]; i++) {
- gpu_material_use_library_with_dependencies(used_libraries, library->dependencies[i]);
- }
- }
-}
-
-GPUFunction *gpu_material_library_use_function(GSet *used_libraries, const char *name)
-{
- GPUFunction *function = BLI_ghash_lookup(FUNCTION_HASH, (const void *)name);
- if (function) {
- gpu_material_use_library_with_dependencies(used_libraries, function->library);
- }
- return function;
-}
-
-char *gpu_material_library_generate_code(GSet *used_libraries, const char *frag_lib)
-{
- DynStr *ds = BLI_dynstr_new();
-
- if (frag_lib) {
- BLI_dynstr_append(ds, frag_lib);
- }
-
- /* Always include those because they may be needed by the execution function. */
- gpu_material_use_library_with_dependencies(used_libraries,
- &gpu_shader_material_world_normals_library);
-
- /* Add library code in order, for dependencies. */
- for (int i = 0; gpu_material_libraries[i]; i++) {
- GPUMaterialLibrary *library = gpu_material_libraries[i];
- if (BLI_gset_haskey(used_libraries, library->code)) {
- BLI_dynstr_append(ds, library->code);
- }
- }
-
- char *result = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- return result;
-}
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
index 96e1a265c72..ffc2228a49b 100644
--- a/source/blender/gpu/intern/gpu_material_library.h
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -10,16 +10,15 @@
#include "GPU_material.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define MAX_FUNCTION_NAME 64
#define MAX_PARAMETER 36
struct GSet;
-typedef struct GPUMaterialLibrary {
- char *code;
- struct GPUMaterialLibrary *dependencies[8];
-} GPUMaterialLibrary;
-
typedef enum {
FUNCTION_QUAL_IN,
FUNCTION_QUAL_OUT,
@@ -31,20 +30,12 @@ typedef struct GPUFunction {
eGPUType paramtype[MAX_PARAMETER];
GPUFunctionQual paramqual[MAX_PARAMETER];
int totparam;
- GPUMaterialLibrary *library;
+ /* TOOD(@fclem): Clean that void pointer. */
+ void *source; /* GPUSource */
} GPUFunction;
-/* Module */
-
-void gpu_material_library_init(void);
-void gpu_material_library_exit(void);
-
-/* Code Generation */
-
GPUFunction *gpu_material_library_use_function(struct GSet *used_libraries, const char *name);
-char *gpu_material_library_generate_code(struct GSet *used_libraries, const char *frag_lib);
-
-/* Code Parsing */
-const char *gpu_str_skip_token(const char *str, char *token, int max);
-const char *gpu_data_type_to_string(eGPUType type);
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 57e415a8183..d9143a12d5b 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -87,10 +87,6 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
input->type = type;
switch (link->link_type) {
- case GPU_NODE_LINK_BUILTIN:
- input->source = GPU_SOURCE_BUILTIN;
- input->builtin = link->builtin;
- break;
case GPU_NODE_LINK_OUTPUT:
input->source = GPU_SOURCE_OUTPUT;
input->link = link;
@@ -132,6 +128,11 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
case GPU_NODE_LINK_UNIFORM:
input->source = GPU_SOURCE_UNIFORM;
break;
+ case GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN:
+ input->source = GPU_SOURCE_FUNCTION_CALL;
+ /* NOTE(@fclem): End of function call is the return variable set during codegen. */
+ SNPRINTF(input->function_call, "dF_branch(%s(), ", link->function_name);
+ break;
default:
break;
}
@@ -478,6 +479,11 @@ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const ch
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, type, name);
+ if (type == CD_ORCO) {
+ /* OPTI: orco might be computed from local positions and needs object infos. */
+ GPU_material_flag_set(mat, GPU_MATFLAG_OBJECT_INFO);
+ }
+
/* Dummy fallback if out of slots. */
if (attr == NULL) {
static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
@@ -523,6 +529,14 @@ GPUNodeLink *GPU_uniform(const float *num)
return link;
}
+GPUNodeLink *GPU_differentiate_float_function(const char *function_name)
+{
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN;
+ link->function_name = function_name;
+ return link;
+}
+
GPUNodeLink *GPU_image(GPUMaterial *mat,
Image *ima,
ImageUser *iuser,
@@ -588,41 +602,35 @@ GPUNodeLink *GPU_volume_grid(GPUMaterial *mat,
transform_link->volume_grid = link->volume_grid;
transform_link->volume_grid->users++;
+ GPUNodeLink *cos_link = GPU_attribute(mat, CD_ORCO, "");
+
/* Two special cases, where we adjust the output values of smoke grids to
* bring the into standard range without having to modify the grid values. */
if (STREQ(name, "color")) {
- GPU_link(mat, "node_attribute_volume_color", link, transform_link, &link);
+ GPU_link(mat, "node_attribute_volume_color", link, transform_link, cos_link, &link);
}
else if (STREQ(name, "temperature")) {
- GPU_link(mat, "node_attribute_volume_temperature", link, transform_link, &link);
+ GPU_link(mat, "node_attribute_volume_temperature", link, transform_link, cos_link, &link);
}
else {
- GPU_link(mat, "node_attribute_volume", link, transform_link, &link);
+ GPU_link(mat, "node_attribute_volume", link, transform_link, cos_link, &link);
}
return link;
}
-GPUNodeLink *GPU_builtin(eGPUBuiltin builtin)
-{
- GPUNodeLink *link = gpu_node_link_create();
- link->link_type = GPU_NODE_LINK_BUILTIN;
- link->builtin = builtin;
- return link;
-}
-
/* Creating Nodes */
bool GPU_link(GPUMaterial *mat, const char *name, ...)
{
- GSet *used_libraries = gpu_material_used_libraries(mat);
+ GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUNode *node;
GPUFunction *function;
GPUNodeLink *link, **linkptr;
va_list params;
int i;
- function = gpu_material_library_use_function(used_libraries, name);
+ function = gpu_material_library_use_function(graph->used_libraries, name);
if (!function) {
fprintf(stderr, "GPU failed to find function %s\n", name);
return false;
@@ -643,27 +651,25 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
}
va_end(params);
- GPUNodeGraph *graph = gpu_material_node_graph(mat);
BLI_addtail(&graph->nodes, node);
return true;
}
-bool GPU_stack_link(GPUMaterial *material,
- bNode *bnode,
- const char *name,
- GPUNodeStack *in,
- GPUNodeStack *out,
- ...)
+static bool gpu_stack_link_v(GPUMaterial *material,
+ bNode *bnode,
+ const char *name,
+ GPUNodeStack *in,
+ GPUNodeStack *out,
+ va_list params)
{
- GSet *used_libraries = gpu_material_used_libraries(material);
+ GPUNodeGraph *graph = gpu_material_node_graph(material);
GPUNode *node;
GPUFunction *function;
GPUNodeLink *link, **linkptr;
- va_list params;
int i, totin, totout;
- function = gpu_material_library_use_function(used_libraries, name);
+ function = gpu_material_library_use_function(graph->used_libraries, name);
if (!function) {
fprintf(stderr, "GPU failed to find function %s\n", name);
return false;
@@ -691,7 +697,6 @@ bool GPU_stack_link(GPUMaterial *material,
}
}
- va_start(params, out);
for (i = 0; i < function->totparam; i++) {
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
if (totout == 0) {
@@ -717,14 +722,27 @@ bool GPU_stack_link(GPUMaterial *material,
}
}
}
- va_end(params);
- GPUNodeGraph *graph = gpu_material_node_graph(material);
BLI_addtail(&graph->nodes, node);
return true;
}
+bool GPU_stack_link(GPUMaterial *material,
+ bNode *bnode,
+ const char *name,
+ GPUNodeStack *in,
+ GPUNodeStack *out,
+ ...)
+{
+ va_list params;
+ va_start(params, out);
+ bool valid = gpu_stack_link_v(material, bnode, name, in, out, params);
+ va_end(params);
+
+ return valid;
+}
+
GPUNodeLink *GPU_uniformbuf_link_out(GPUMaterial *mat,
bNode *node,
GPUNodeStack *stack,
@@ -786,12 +804,16 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
gpu_node_free(node);
}
- graph->outlink = NULL;
+ graph->outlink_surface = NULL;
+ graph->outlink_volume = NULL;
+ graph->outlink_displacement = NULL;
+ graph->outlink_thickness = NULL;
}
void gpu_node_graph_free(GPUNodeGraph *graph)
{
BLI_freelistN(&graph->outlink_aovs);
+ BLI_freelistN(&graph->material_functions);
gpu_node_graph_free_nodes(graph);
LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) {
@@ -801,28 +823,32 @@ void gpu_node_graph_free(GPUNodeGraph *graph)
BLI_freelistN(&graph->textures);
BLI_freelistN(&graph->attributes);
GPU_uniform_attr_list_free(&graph->uniform_attrs);
+
+ if (graph->used_libraries) {
+ BLI_gset_free(graph->used_libraries, NULL);
+ graph->used_libraries = NULL;
+ }
}
/* Prune Unused Nodes */
-static void gpu_nodes_tag(GPUNodeLink *link)
+static void gpu_nodes_tag(GPUNodeLink *link, eGPUNodeTag tag)
{
GPUNode *node;
- GPUInput *input;
- if (!link->output) {
+ if (!link || !link->output) {
return;
}
node = link->output->node;
- if (node->tag) {
+ if (node->tag & tag) {
return;
}
- node->tag = true;
- for (input = node->inputs.first; input; input = input->next) {
+ node->tag |= tag;
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
if (input->link) {
- gpu_nodes_tag(input->link);
+ gpu_nodes_tag(input->link, tag);
}
}
}
@@ -830,18 +856,25 @@ static void gpu_nodes_tag(GPUNodeLink *link)
void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
{
LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- node->tag = false;
+ node->tag = GPU_NODE_TAG_NONE;
}
- gpu_nodes_tag(graph->outlink);
+ gpu_nodes_tag(graph->outlink_surface, GPU_NODE_TAG_SURFACE);
+ gpu_nodes_tag(graph->outlink_volume, GPU_NODE_TAG_VOLUME);
+ gpu_nodes_tag(graph->outlink_displacement, GPU_NODE_TAG_DISPLACEMENT);
+ gpu_nodes_tag(graph->outlink_thickness, GPU_NODE_TAG_THICKNESS);
+
LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) {
- gpu_nodes_tag(aovlink->outlink);
+ gpu_nodes_tag(aovlink->outlink, GPU_NODE_TAG_AOV);
+ }
+ LISTBASE_FOREACH (GPUNodeGraphFunctionLink *, funclink, &graph->material_functions) {
+ gpu_nodes_tag(funclink->outlink, GPU_NODE_TAG_FUNCTION);
}
for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) {
next = node->next;
- if (!node->tag) {
+ if (node->tag == GPU_NODE_TAG_NONE) {
BLI_remlink(&graph->nodes, node);
gpu_node_free(node);
}
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index 5856001d548..024119e1c24 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -12,9 +12,15 @@
#include "DNA_customdata_types.h"
#include "DNA_listBase.h"
+#include "BLI_ghash.h"
+
#include "GPU_material.h"
#include "GPU_shader.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct GPUNode;
struct GPUOutput;
struct ListBase;
@@ -25,19 +31,18 @@ typedef enum eGPUDataSource {
GPU_SOURCE_UNIFORM,
GPU_SOURCE_ATTR,
GPU_SOURCE_UNIFORM_ATTR,
- GPU_SOURCE_BUILTIN,
GPU_SOURCE_STRUCT,
GPU_SOURCE_TEX,
GPU_SOURCE_TEX_TILED_MAPPING,
GPU_SOURCE_VOLUME_GRID,
GPU_SOURCE_VOLUME_GRID_TRANSFORM,
+ GPU_SOURCE_FUNCTION_CALL,
} eGPUDataSource;
typedef enum {
GPU_NODE_LINK_NONE = 0,
GPU_NODE_LINK_ATTR,
GPU_NODE_LINK_UNIFORM_ATTR,
- GPU_NODE_LINK_BUILTIN,
GPU_NODE_LINK_COLORBAND,
GPU_NODE_LINK_CONSTANT,
GPU_NODE_LINK_IMAGE,
@@ -47,15 +52,28 @@ typedef enum {
GPU_NODE_LINK_VOLUME_GRID_TRANSFORM,
GPU_NODE_LINK_OUTPUT,
GPU_NODE_LINK_UNIFORM,
+ GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN,
} GPUNodeLinkType;
+typedef enum {
+ GPU_NODE_TAG_NONE = 0,
+ GPU_NODE_TAG_SURFACE = (1 << 0),
+ GPU_NODE_TAG_VOLUME = (1 << 1),
+ GPU_NODE_TAG_DISPLACEMENT = (1 << 2),
+ GPU_NODE_TAG_THICKNESS = (1 << 3),
+ GPU_NODE_TAG_AOV = (1 << 4),
+ GPU_NODE_TAG_FUNCTION = (1 << 5),
+} eGPUNodeTag;
+
+ENUM_OPERATORS(eGPUNodeTag, GPU_NODE_TAG_FUNCTION)
+
struct GPUNode {
struct GPUNode *next, *prev;
const char *name;
/* Internal flag to mark nodes during pruning */
- bool tag;
+ eGPUNodeTag tag;
ListBase inputs;
ListBase outputs;
@@ -70,8 +88,6 @@ struct GPUNodeLink {
union {
/* GPU_NODE_LINK_CONSTANT | GPU_NODE_LINK_UNIFORM */
const float *data;
- /* GPU_NODE_LINK_BUILTIN */
- eGPUBuiltin builtin;
/* GPU_NODE_LINK_COLORBAND */
struct GPUTexture **colorband;
/* GPU_NODE_LINK_VOLUME_GRID */
@@ -84,6 +100,8 @@ struct GPUNodeLink {
struct GPUUniformAttr *uniform_attr;
/* GPU_NODE_LINK_IMAGE_BLENDER */
struct GPUMaterialTexture *texture;
+ /* GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN */
+ const char *function_name;
};
};
@@ -110,8 +128,6 @@ typedef struct GPUInput {
union {
/* GPU_SOURCE_CONSTANT | GPU_SOURCE_UNIFORM */
float vec[16]; /* vector data */
- /* GPU_SOURCE_BUILTIN */
- eGPUBuiltin builtin; /* builtin uniform */
/* GPU_SOURCE_TEX | GPU_SOURCE_TEX_TILED_MAPPING */
struct GPUMaterialTexture *texture;
/* GPU_SOURCE_ATTR */
@@ -120,6 +136,8 @@ typedef struct GPUInput {
struct GPUUniformAttr *uniform_attr;
/* GPU_SOURCE_VOLUME_GRID | GPU_SOURCE_VOLUME_GRID_TRANSFORM */
struct GPUMaterialVolumeGrid *volume_grid;
+ /* GPU_SOURCE_FUNCTION_CALL */
+ char function_call[64];
};
} GPUInput;
@@ -129,14 +147,25 @@ typedef struct GPUNodeGraphOutputLink {
GPUNodeLink *outlink;
} GPUNodeGraphOutputLink;
+typedef struct GPUNodeGraphFunctionLink {
+ struct GPUNodeGraphFunctionLink *next, *prev;
+ char name[16];
+ GPUNodeLink *outlink;
+} GPUNodeGraphFunctionLink;
+
typedef struct GPUNodeGraph {
/* Nodes */
ListBase nodes;
- /* Main Output. */
- GPUNodeLink *outlink;
+ /* Main Outputs. */
+ GPUNodeLink *outlink_surface;
+ GPUNodeLink *outlink_volume;
+ GPUNodeLink *outlink_displacement;
+ GPUNodeLink *outlink_thickness;
/* List of GPUNodeGraphOutputLink */
ListBase outlink_aovs;
+ /* List of GPUNodeGraphFunctionLink */
+ ListBase material_functions;
/* Requested attributes and textures. */
ListBase attributes;
@@ -145,6 +174,9 @@ typedef struct GPUNodeGraph {
/* The list of uniform attributes. */
GPUUniformAttrList uniform_attrs;
+
+ /** Set of all the GLSL lib code blocks . */
+ GSet *used_libraries;
} GPUNodeGraph;
/* Node Graph */
@@ -171,4 +203,6 @@ struct GPUTexture **gpu_material_ramp_texture_row_set(struct GPUMaterial *mat,
float *pixels,
float *row);
-struct GSet *gpu_material_used_libraries(struct GPUMaterial *material);
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index 76b3402435a..fe9aacb95f9 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -294,7 +294,9 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
std::string defines = shader->defines_declare(info);
std::string resources = shader->resources_declare(info);
- defines += "#define USE_GPU_SHADER_CREATE_INFO\n";
+ if (info.legacy_resource_location_ == false) {
+ defines += "#define USE_GPU_SHADER_CREATE_INFO\n";
+ }
Vector<const char *> typedefs;
if (!info.typedef_sources_.is_empty() || !info.typedef_source_generated.empty()) {
@@ -362,6 +364,7 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
sources.append(resources.c_str());
sources.append(layout.c_str());
sources.append(interface.c_str());
+ sources.append(info.geometry_source_generated.c_str());
sources.extend(code);
shader->geometry_shader_from_glsl(sources);
diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
index 95f9b031fe8..515f65adb73 100644
--- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
+++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
@@ -202,10 +202,7 @@ int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *UNUSED(subdiv_ccg),
/* -------------------------------------------------------------------- */
/** \name Stubs of BKE_node.h
* \{ */
-void ntreeGPUMaterialNodes(struct bNodeTree *UNUSED(localtree),
- struct GPUMaterial *UNUSED(mat),
- bool *UNUSED(has_surface_output),
- bool *UNUSED(has_volume_output))
+void ntreeGPUMaterialNodes(struct bNodeTree *UNUSED(localtree), struct GPUMaterial *UNUSED(mat))
{
BLI_assert_unreachable();
}
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
index dfd73219d1b..3ab96d0d84a 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.hh
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -284,6 +284,8 @@ struct ShaderCreateInfo {
bool auto_resource_location_ = false;
/** If true, force depth and stencil tests to always happen before fragment shader invocation. */
bool early_fragment_test_ = false;
+ /** If true, force the use of the GL shader introspection for resource location. */
+ bool legacy_resource_location_ = false;
/** Allow optimization when fragment shader writes to `gl_FragDepth`. */
DepthWrite depth_write_ = DepthWrite::ANY;
/**
@@ -296,6 +298,7 @@ struct ShaderCreateInfo {
/** Manually set generated code. */
std::string vertex_source_generated = "";
std::string fragment_source_generated = "";
+ std::string geometry_source_generated = "";
std::string typedef_source_generated = "";
/** Manually set generated dependencies. */
Vector<const char *, 0> dependencies_generated;
@@ -721,6 +724,12 @@ struct ShaderCreateInfo {
return *(Self *)this;
}
+ Self &legacy_resource_location(bool value)
+ {
+ legacy_resource_location_ = value;
+ return *(Self *)this;
+ }
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 2c6845334d3..7ee64d7e80f 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -10,11 +10,14 @@
#include <iomanip>
#include <iostream>
+#include <sstream>
+#include "BLI_ghash.h"
#include "BLI_map.hh"
#include "BLI_set.hh"
#include "BLI_string_ref.hh"
+#include "gpu_material_library.h"
#include "gpu_shader_create_info.hh"
#include "gpu_shader_dependency_private.h"
@@ -31,6 +34,7 @@ extern "C" {
namespace blender::gpu {
using GPUSourceDictionnary = Map<StringRef, struct GPUSource *>;
+using GPUFunctionDictionnary = Map<StringRef, struct GPUFunction *>;
struct GPUSource {
StringRefNull fullpath;
@@ -41,7 +45,10 @@ struct GPUSource {
shader::BuiltinBits builtins = (shader::BuiltinBits)0;
std::string processed_source;
- GPUSource(const char *path, const char *file, const char *datatoc)
+ GPUSource(const char *path,
+ const char *file,
+ const char *datatoc,
+ GPUFunctionDictionnary *g_functions)
: fullpath(path), filename(file), source(datatoc)
{
/* Scan for builtins. */
@@ -92,16 +99,20 @@ struct GPUSource {
if (filename.endswith(".h") || filename.endswith(".hh")) {
enum_preprocess();
}
+
+ if (is_from_material_library()) {
+ material_functions_parse(g_functions);
+ }
};
- bool is_in_comment(const StringRef &input, int64_t offset)
+ static bool is_in_comment(const StringRef &input, int64_t offset)
{
return (input.rfind("/*", offset) > input.rfind("*/", offset)) ||
(input.rfind("//", offset) > input.rfind("\n", offset));
}
template<bool check_whole_word = true, bool reversed = false, typename T>
- int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0)
+ static int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0)
{
while (true) {
if constexpr (reversed) {
@@ -114,7 +125,7 @@ struct GPUSource {
if constexpr (check_whole_word) {
/* Fix false positive if something has "enum" as suffix. */
char previous_char = input[offset - 1];
- if (!(ELEM(previous_char, '\n', '\t', ' ', ':'))) {
+ if (!(ELEM(previous_char, '\n', '\t', ' ', ':', '(', ','))) {
offset += (reversed) ? -1 : 1;
continue;
}
@@ -129,9 +140,13 @@ struct GPUSource {
}
}
+#define find_keyword find_str<true, false>
+#define rfind_keyword find_str<true, true>
+#define find_token find_str<false, false>
+#define rfind_token find_str<false, true>
+
void print_error(const StringRef &input, int64_t offset, const StringRef message)
{
- std::cout << " error: " << message << "\n";
StringRef sub = input.substr(0, offset);
int64_t line_number = std::count(sub.begin(), sub.end(), '\n') + 1;
int64_t line_end = input.find("\n", offset);
@@ -152,6 +167,12 @@ struct GPUSource {
std::cout << "^\n";
}
+#define CHECK(test_value, str, ofs, msg) \
+ if ((test_value) == -1) { \
+ print_error(str, ofs, msg); \
+ continue; \
+ }
+
/**
* Transform C,C++ enum declaration into GLSL compatible defines and constants:
*
@@ -193,16 +214,6 @@ struct GPUSource {
int64_t last_pos = 0;
const bool is_cpp = filename.endswith(".hh");
-#define find_keyword find_str<true, false>
-#define find_token find_str<false, false>
-#define rfind_token find_str<false, true>
-#define CHECK(test_value, str, ofs, msg) \
- if ((test_value) == -1) { \
- print_error(str, ofs, msg); \
- cursor++; \
- continue; \
- }
-
while (true) {
cursor = find_keyword(input, "enum ", cursor + 1);
if (cursor == -1) {
@@ -268,10 +279,6 @@ struct GPUSource {
return;
}
-#undef find_keyword
-#undef find_token
-#undef rfind_token
-
if (last_pos != 0) {
output += input.substr(last_pos);
}
@@ -279,37 +286,241 @@ struct GPUSource {
source = processed_source.c_str();
};
+ void material_functions_parse(GPUFunctionDictionnary *g_functions)
+ {
+ const StringRefNull input = source;
+
+ const char whitespace_chars[] = " \n\t";
+
+ auto function_parse = [&](const StringRef &input,
+ int64_t &cursor,
+ StringRef &out_return_type,
+ StringRef &out_name,
+ StringRef &out_args) -> bool {
+ cursor = find_keyword(input, "void ", cursor + 1);
+ if (cursor == -1) {
+ return false;
+ }
+ int64_t arg_start = find_token(input, '(', cursor);
+ if (arg_start == -1) {
+ return false;
+ }
+ int64_t arg_end = find_token(input, ')', arg_start);
+ if (arg_end == -1) {
+ return false;
+ }
+ int64_t body_start = find_token(input, '{', arg_end);
+ int64_t next_semicolon = find_token(input, ';', arg_end);
+ if (body_start != -1 && next_semicolon != -1 && body_start > next_semicolon) {
+ /* Assert no prototypes but could also just skip them. */
+ BLI_assert_msg(false, "No prototypes allowed in node GLSL libraries.");
+ }
+ int64_t name_start = input.find_first_not_of(whitespace_chars, input.find(' ', cursor));
+ if (name_start == -1) {
+ return false;
+ }
+ int64_t name_end = input.find_last_not_of(whitespace_chars, arg_start);
+ if (name_end == -1) {
+ return false;
+ }
+ /* Only support void type for now. */
+ out_return_type = "void";
+ out_name = input.substr(name_start, name_end - name_start);
+ out_args = input.substr(arg_start + 1, arg_end - (arg_start + 1));
+ return true;
+ };
+
+ auto keyword_parse = [&](const StringRef &str, int64_t &cursor) -> const StringRef {
+ int64_t keyword_start = str.find_first_not_of(whitespace_chars, cursor);
+ if (keyword_start == -1) {
+ /* No keyword found. */
+ return str.substr(0, 0);
+ }
+ int64_t keyword_end = str.find_first_of(whitespace_chars, keyword_start);
+ if (keyword_end == -1) {
+ /* Last keyword. */
+ keyword_end = str.size();
+ }
+ cursor = keyword_end + 1;
+ return str.substr(keyword_start, keyword_end - keyword_start);
+ };
+
+ auto arg_parse = [&](const StringRef &str,
+ int64_t &cursor,
+ StringRef &out_qualifier,
+ StringRef &out_type,
+ StringRef &out_name) -> bool {
+ int64_t arg_start = cursor + 1;
+ if (arg_start >= str.size()) {
+ return false;
+ }
+ cursor = find_token(str, ',', arg_start);
+ if (cursor == -1) {
+ /* Last argument. */
+ cursor = str.size();
+ }
+ const StringRef arg = str.substr(arg_start, cursor - arg_start);
+
+ int64_t keyword_cursor = 0;
+ out_qualifier = keyword_parse(arg, keyword_cursor);
+ out_type = keyword_parse(arg, keyword_cursor);
+ out_name = keyword_parse(arg, keyword_cursor);
+ if (out_name.is_empty()) {
+ /* No qualifier case. */
+ out_name = out_type;
+ out_type = out_qualifier;
+ out_qualifier = arg.substr(0, 0);
+ }
+ return true;
+ };
+
+ int64_t cursor = -1;
+ StringRef func_return_type, func_name, func_args;
+ while (function_parse(input, cursor, func_return_type, func_name, func_args)) {
+ GPUFunction *func = MEM_new<GPUFunction>(__func__);
+ func_name.copy(func->name, sizeof(func->name));
+ func->source = reinterpret_cast<void *>(this);
+
+ bool insert = g_functions->add(func->name, func);
+
+ /* NOTE: We allow overloading non void function, but only if the function comes from the
+ * same file. Otherwise the dependency system breaks. */
+ if (!insert) {
+ GPUSource *other_source = reinterpret_cast<GPUSource *>(
+ g_functions->lookup(func_name)->source);
+ if (other_source != this) {
+ print_error(input,
+ source.find(func_name),
+ "Function redefinition or overload in two different files ...");
+ print_error(
+ input, other_source->source.find(func_name), "... previous definition was here");
+ }
+ else {
+ /* Non-void function overload. */
+ MEM_delete(func);
+ }
+ continue;
+ }
+
+ if (func_return_type != "void") {
+ continue;
+ }
+
+ func->totparam = 0;
+ int64_t args_cursor = -1;
+ StringRef arg_qualifier, arg_type, arg_name;
+ while (arg_parse(func_args, args_cursor, arg_qualifier, arg_type, arg_name)) {
+
+ if (func->totparam >= ARRAY_SIZE(func->paramtype)) {
+ print_error(input, source.find(func_name), "Too much parameter in function");
+ break;
+ }
+
+ auto parse_qualifier = [](StringRef &qualifier) -> GPUFunctionQual {
+ if (qualifier == "out") {
+ return FUNCTION_QUAL_OUT;
+ }
+ else if (qualifier == "inout") {
+ return FUNCTION_QUAL_INOUT;
+ }
+ else {
+ return FUNCTION_QUAL_IN;
+ }
+ };
+
+ auto parse_type = [](StringRef &type) -> eGPUType {
+ if (type == "float") {
+ return GPU_FLOAT;
+ }
+ else if (type == "vec2") {
+ return GPU_VEC2;
+ }
+ else if (type == "vec3") {
+ return GPU_VEC3;
+ }
+ else if (type == "vec4") {
+ return GPU_VEC4;
+ }
+ else if (type == "mat3") {
+ return GPU_MAT3;
+ }
+ else if (type == "mat4") {
+ return GPU_MAT4;
+ }
+ else if (type == "sampler1DArray") {
+ return GPU_TEX1D_ARRAY;
+ }
+ else if (type == "sampler2DArray") {
+ return GPU_TEX2D_ARRAY;
+ }
+ else if (type == "sampler2D") {
+ return GPU_TEX2D;
+ }
+ else if (type == "sampler3D") {
+ return GPU_TEX3D;
+ }
+ else if (type == "Closure") {
+ return GPU_CLOSURE;
+ }
+ else {
+ return GPU_NONE;
+ }
+ };
+
+ func->paramqual[func->totparam] = parse_qualifier(arg_qualifier);
+ func->paramtype[func->totparam] = parse_type(arg_type);
+
+ if (func->paramtype[func->totparam] == GPU_NONE) {
+ std::string err = "Unknown parameter type \"" + arg_type + "\"";
+ int64_t err_ofs = source.find(func_name);
+ err_ofs = find_keyword(source, arg_name, err_ofs);
+ err_ofs = rfind_keyword(source, arg_type, err_ofs);
+ print_error(input, err_ofs, err);
+ }
+
+ func->totparam++;
+ }
+ }
+ }
+
+#undef find_keyword
+#undef rfind_keyword
+#undef find_token
+#undef rfind_token
+
/* Return 1 one error. */
- int init_dependencies(const GPUSourceDictionnary &dict)
+ int init_dependencies(const GPUSourceDictionnary &dict,
+ const GPUFunctionDictionnary &g_functions)
{
- if (dependencies_init) {
+ if (this->dependencies_init) {
return 0;
}
- dependencies_init = true;
- int64_t pos = 0;
+ this->dependencies_init = true;
+ int64_t pos = -1;
+
while (true) {
- pos = source.find("pragma BLENDER_REQUIRE(", pos);
- if (pos == -1) {
- return 0;
- }
- int64_t start = source.find('(', pos) + 1;
- int64_t end = source.find(')', pos);
- if (end == -1) {
- /* TODO Use clog. */
- std::cout << "Error: " << filename << " : Malformed BLENDER_REQUIRE: Missing \")\"."
- << std::endl;
- return 1;
- }
- StringRef dependency_name = source.substr(start, end - start);
- GPUSource *dependency_source = dict.lookup_default(dependency_name, nullptr);
- if (dependency_source == nullptr) {
- /* TODO Use clog. */
- std::cout << "Error: " << filename << " : Dependency not found \"" << dependency_name
- << "\"." << std::endl;
- return 1;
+ GPUSource *dependency_source = nullptr;
+
+ {
+ pos = source.find("pragma BLENDER_REQUIRE(", pos + 1);
+ if (pos == -1) {
+ return 0;
+ }
+ int64_t start = source.find('(', pos) + 1;
+ int64_t end = source.find(')', pos);
+ if (end == -1) {
+ print_error(source, start, "Malformed BLENDER_REQUIRE: Missing \")\" token");
+ return 1;
+ }
+ StringRef dependency_name = source.substr(start, end - start);
+ dependency_source = dict.lookup_default(dependency_name, nullptr);
+ if (dependency_source == nullptr) {
+ print_error(source, start, "Dependency not found");
+ return 1;
+ }
}
/* Recursive. */
- int result = dependency_source->init_dependencies(dict);
+ int result = dependency_source->init_dependencies(dict, g_functions);
if (result != 0) {
return 1;
}
@@ -318,8 +529,8 @@ struct GPUSource {
dependencies.append_non_duplicates(dep);
}
dependencies.append_non_duplicates(dependency_source);
- pos++;
- };
+ }
+ return 0;
}
/* Returns the final string with all includes done. */
@@ -339,6 +550,11 @@ struct GPUSource {
}
return out_builtins;
}
+
+ bool is_from_material_library() const
+ {
+ return filename.startswith("gpu_shader_material_") && filename.endswith(".glsl");
+ }
};
} // namespace blender::gpu
@@ -346,13 +562,15 @@ struct GPUSource {
using namespace blender::gpu;
static GPUSourceDictionnary *g_sources = nullptr;
+static GPUFunctionDictionnary *g_functions = nullptr;
void gpu_shader_dependency_init()
{
g_sources = new GPUSourceDictionnary();
+ g_functions = new GPUFunctionDictionnary();
#define SHADER_SOURCE(datatoc, filename, filepath) \
- g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc));
+ g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc, g_functions));
#include "glsl_draw_source_list.h"
#include "glsl_gpu_source_list.h"
#ifdef WITH_OCIO
@@ -362,7 +580,7 @@ void gpu_shader_dependency_init()
int errors = 0;
for (auto *value : g_sources->values()) {
- errors += value->init_dependencies(*g_sources);
+ errors += value->init_dependencies(*g_sources, *g_functions);
}
BLI_assert_msg(errors == 0, "Dependency errors detected: Aborting");
UNUSED_VARS_NDEBUG(errors);
@@ -373,7 +591,20 @@ void gpu_shader_dependency_exit()
for (auto *value : g_sources->values()) {
delete value;
}
+ for (auto *value : g_functions->values()) {
+ MEM_delete(value);
+ }
delete g_sources;
+ delete g_functions;
+}
+
+GPUFunction *gpu_material_library_use_function(GSet *used_libraries, const char *name)
+{
+ GPUFunction *function = g_functions->lookup_default(name, nullptr);
+ BLI_assert_msg(function != nullptr, "Requested function not in the function library");
+ GPUSource *source = reinterpret_cast<GPUSource *>(function->source);
+ BLI_gset_add(used_libraries, const_cast<char *>(source->filename.c_str()));
+ return function;
}
namespace blender::gpu::shader {
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 5938444ce49..9768318f3b6 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -572,10 +572,13 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
}
if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) {
if (!GLContext::native_barycentric_support) {
+ ss << "flat in vec4 gpu_pos[3];\n";
ss << "smooth in vec3 gpu_BaryCoord;\n";
ss << "noperspective in vec3 gpu_BaryCoordNoPersp;\n";
+ ss << "#define gpu_position_at_vertex(v) gpu_pos[v]\n";
}
else if (GLEW_AMD_shader_explicit_vertex_parameter) {
+ std::cout << "native" << std::endl;
/* NOTE(fclem): This won't work with geometry shader. Hopefully, we don't need geometry
* shader workaround if this extension/feature is detected. */
ss << "\n/* Stable Barycentric Coordinates. */\n";
@@ -591,6 +594,12 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { return bary.yzx; }\n";
ss << " return bary.xyz;\n";
ss << "}\n";
+ ss << "\n";
+ ss << "vec4 gpu_position_at_vertex(int v) {\n";
+ ss << " if (interpolateAtVertexAMD(gpu_pos, 0) == gpu_pos_flat) { v = (v + 2) % 3; }\n";
+ ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { v = (v + 1) % 3; }\n";
+ ss << " return interpolateAtVertexAMD(gpu_pos, v);\n";
+ ss << "}\n";
pre_main += " gpu_BaryCoord = stable_bary_(gl_BaryCoordSmoothAMD);\n";
pre_main += " gpu_BaryCoordNoPersp = stable_bary_(gl_BaryCoordNoPerspAMD);\n";
@@ -730,6 +739,7 @@ std::string GLShader::workaround_geometry_shader_source_create(
ss << "in int gpu_Layer[];\n";
}
if (do_barycentric_workaround) {
+ ss << "flat out vec4 gpu_pos[3];\n";
ss << "smooth out vec3 gpu_BaryCoord;\n";
ss << "noperspective out vec3 gpu_BaryCoordNoPersp;\n";
}
@@ -740,6 +750,11 @@ std::string GLShader::workaround_geometry_shader_source_create(
if (do_layer_workaround) {
ss << " gl_Layer = gpu_Layer[0];\n";
}
+ if (do_barycentric_workaround) {
+ ss << " gpu_pos[0] = gl_in[0].gl_Position;\n";
+ ss << " gpu_pos[1] = gl_in[1].gl_Position;\n";
+ ss << " gpu_pos[2] = gl_in[2].gl_Position;\n";
+ }
for (auto i : IndexRange(3)) {
for (StageInterfaceInfo *iface : info_modified.vertex_out_interfaces_) {
for (auto &inout : iface->inouts) {
@@ -977,7 +992,7 @@ bool GLShader::finalize(const shader::ShaderCreateInfo *info)
return false;
}
- if (info != nullptr) {
+ if (info != nullptr && info->legacy_resource_location_ == false) {
interface = new GLShaderInterface(shader_program_, *info);
}
else {
diff --git a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
index 193a4190cbf..5c97eada77d 100644
--- a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
@@ -95,3 +95,176 @@ vec4 tangent_get(vec4 attr, mat3 normalmat)
}
#endif
+
+/* Assumes GPU_VEC4 is color data. So converting to luminance like cycles. */
+#define float_from_vec4(v) dot(v.rgb, vec3(0.2126, 0.7152, 0.0722))
+#define float_from_vec3(v) avg(v.rgb)
+#define float_from_vec2(v) v.r
+
+#define vec2_from_vec4(v) vec2(avg(v.rgb), v.a)
+#define vec2_from_vec3(v) vec2(avg(v.rgb), 1.0)
+#define vec2_from_float(v) vec2(v)
+
+#define vec3_from_vec4(v) v.rgb
+#define vec3_from_vec2(v) v.rrr
+#define vec3_from_float(v) vec3(v)
+
+#define vec4_from_vec3(v) vec4(v, 1.0)
+#define vec4_from_vec2(v) v.rrrg
+#define vec4_from_float(v) vec4(vec3(v), 1.0)
+
+/* TODO: Move to shader_shared. */
+#define RAY_TYPE_CAMERA 0
+#define RAY_TYPE_SHADOW 1
+#define RAY_TYPE_DIFFUSE 2
+#define RAY_TYPE_GLOSSY 3
+
+#ifdef GPU_FRAGMENT_SHADER
+# define FrontFacing gl_FrontFacing
+#else
+# define FrontFacing true
+#endif
+
+struct ClosureDiffuse {
+ float weight;
+ vec3 color;
+ vec3 N;
+ vec3 sss_radius;
+ uint sss_id;
+};
+
+struct ClosureTranslucent {
+ float weight;
+ vec3 color;
+ vec3 N;
+};
+
+struct ClosureReflection {
+ float weight;
+ vec3 color;
+ vec3 N;
+ float roughness;
+};
+
+struct ClosureRefraction {
+ float weight;
+ vec3 color;
+ vec3 N;
+ float roughness;
+ float ior;
+};
+
+struct ClosureHair {
+ float weight;
+ vec3 color;
+ float offset;
+ vec2 roughness;
+ vec3 T;
+};
+
+struct ClosureVolumeScatter {
+ float weight;
+ vec3 scattering;
+ float anisotropy;
+};
+
+struct ClosureVolumeAbsorption {
+ float weight;
+ vec3 absorption;
+};
+
+struct ClosureEmission {
+ float weight;
+ vec3 emission;
+};
+
+struct ClosureTransparency {
+ float weight;
+ vec3 transmittance;
+ float holdout;
+};
+
+struct GlobalData {
+ /** World position. */
+ vec3 P;
+ /** Surface Normal. */
+ vec3 N;
+ /** Geometric Normal. */
+ vec3 Ng;
+ /** Surface default Tangent. */
+ vec3 T;
+ /** Barycentric coordinates. */
+ vec2 barycentric_coords;
+ vec3 barycentric_dists;
+ /** Ray properties (approximation). */
+ int ray_type;
+ float ray_depth;
+ float ray_length;
+ /** Hair time along hair length. 0 at base 1 at tip. */
+ float hair_time;
+ /** Hair time along width of the hair. */
+ float hair_time_width;
+ /** Hair thickness in world space. */
+ float hair_thickness;
+ /** Index of the strand for per strand effects. */
+ int hair_strand_id;
+ /** Is hair. */
+ bool is_strand;
+};
+
+GlobalData g_data;
+
+#ifndef GPU_FRAGMENT_SHADER
+/* Stubs. */
+vec3 dF_impl(vec3 v)
+{
+ return vec3(0.0);
+}
+
+void dF_branch(float fn, out vec2 result)
+{
+ result = vec2(0.0);
+}
+
+#elif 0 /* TODO(@fclem): User Option? */
+/* Fast derivatives */
+vec3 dF_impl(vec3 v)
+{
+ return vec3(0.0);
+}
+
+void dF_branch(float fn, out vec2 result)
+{
+ result.x = DFDX_SIGN * dFdx(fn);
+ result.y = DFDY_SIGN * dFdy(fn);
+}
+
+#else
+/* Precise derivatives */
+int g_derivative_flag = 0;
+
+vec3 dF_impl(vec3 v)
+{
+ if (g_derivative_flag > 0) {
+ return DFDX_SIGN * dFdx(v);
+ }
+ else if (g_derivative_flag < 0) {
+ return DFDY_SIGN * dFdy(v);
+ }
+ return vec3(0.0);
+}
+
+# define dF_branch(fn, result) \
+ if (true) { \
+ g_derivative_flag = 1; \
+ result.x = (fn); \
+ g_derivative_flag = -1; \
+ result.y = (fn); \
+ g_derivative_flag = 0; \
+ result -= vec2((fn)); \
+ }
+
+#endif
+
+/* TODO(fclem): Remove. */
+#define CODEGEN_LIB
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
index 12921a31b23..4ba1f6f7368 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
@@ -1,4 +1,4 @@
-#ifndef VOLUMETRICS
+
void node_ambient_occlusion(vec4 color,
float dist,
vec3 normal,
@@ -7,20 +7,6 @@ void node_ambient_occlusion(vec4 color,
out vec4 result_color,
out float result_ao)
{
- vec3 bent_normal;
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, sample_count);
-
- vec3 V = cameraVec(worldPosition);
- vec3 N = normalize(normal);
- vec3 Ng = safe_normalize(cross(dFdx(worldPosition), dFdy(worldPosition)));
-
- float unused_error;
- vec3 unused;
- occlusion_eval(data, V, N, Ng, inverted, result_ao, unused_error, unused);
+ result_ao = ambient_occlusion_eval(normal, dist, inverted, sample_count);
result_color = result_ao * color;
}
-#else
-/* Stub ambient occlusion because it is not compatible with volumetrics. */
-# define node_ambient_occlusion(a, b, c, d, e, f) (e = vec4(0); f = 0.0)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
index ec49cc86761..77de9e096a6 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
@@ -1,17 +1,27 @@
-#ifndef VOLUMETRICS
+
void node_bsdf_anisotropic(vec4 color,
float roughness,
float anisotropy,
float rotation,
vec3 N,
vec3 T,
- const float use_multiscatter,
- const float ssr_id,
+ float weight,
+ const float do_multiscatter,
out Closure result)
{
- node_bsdf_glossy(color, roughness, N, use_multiscatter, ssr_id, result);
+ N = safe_normalize(N);
+ vec3 V = cameraVec(g_data.P);
+ float NV = dot(N, V);
+
+ vec2 split_sum = brdf_lut(NV, roughness);
+
+ ClosureReflection reflection_data;
+ reflection_data.weight = weight;
+ reflection_data.color = (do_multiscatter != 0.0) ?
+ F_brdf_multi_scatter(color.rgb, color.rgb, split_sum) :
+ F_brdf_single_scatter(color.rgb, color.rgb, split_sum);
+ reflection_data.N = N;
+ reflection_data.roughness = roughness;
+
+ result = closure_eval(reflection_data);
}
-#else
-/* Stub anisotropic because it is not compatible with volumetrics. */
-# define node_bsdf_anisotropic(a, b, c, d, e, f, g, h, result) (result = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl
index 69ef4dcb7c7..2460bd63b38 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl
@@ -1,11 +1,9 @@
-void node_background(vec4 color, float strength, out Closure result)
+
+void node_background(vec4 color, float strength, float weight, out Closure result)
{
-#ifndef VOLUMETRICS
- color *= strength;
- result = CLOSURE_DEFAULT;
- result.radiance = color.rgb;
- result.transmittance = vec3(0.0);
-#else
- result = CLOSURE_DEFAULT;
-#endif
+ ClosureEmission emission_data;
+ emission_data.weight = weight;
+ emission_data.emission = color.rgb * strength;
+
+ result = closure_eval(emission_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl
index 9f73f654217..e0931128485 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl
@@ -1,28 +1,19 @@
-void dfdx_v3(vec3 v, out vec3 dy)
-{
- dy = v + DFDX_SIGN * dFdx(v);
-}
-void dfdy_v3(vec3 v, out vec3 dy)
+void differentiate_texco(vec3 v, out vec3 df)
{
- dy = v + DFDY_SIGN * dFdy(v);
+ /* Implementation defined. */
+ df = v + dF_impl(v);
}
-void node_bump(float strength,
- float dist,
- float height,
- float height_dx,
- float height_dy,
- vec3 N,
- vec3 surf_pos,
- float invert,
- out vec3 result)
+void node_bump(
+ float strength, float dist, float height, vec3 N, vec2 dHd, float invert, out vec3 result)
{
- N = mat3(ViewMatrix) * normalize(N);
- dist *= gl_FrontFacing ? invert : -invert;
+ N = normalize(N);
+ dist *= FrontFacing ? invert : -invert;
- vec3 dPdx = dFdx(surf_pos);
- vec3 dPdy = dFdy(surf_pos);
+#ifdef GPU_FRAGMENT_SHADER
+ vec3 dPdx = dFdx(g_data.P);
+ vec3 dPdy = dFdy(g_data.P);
/* Get surface tangents from normal. */
vec3 Rx = cross(dPdy, N);
@@ -31,14 +22,13 @@ void node_bump(float strength,
/* Compute surface gradient and determinant. */
float det = dot(dPdx, Rx);
- float dHdx = height_dx - height;
- float dHdy = height_dy - height;
- vec3 surfgrad = dHdx * Rx + dHdy * Ry;
+ vec3 surfgrad = dHd.x * Rx + dHd.y * Ry;
strength = max(strength, 0.0);
result = normalize(abs(det) * N - dist * sign(det) * surfgrad);
result = normalize(mix(N, result, strength));
-
- result = mat3(ViewMatrixInverse) * result;
+#else
+ result = N;
+#endif
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
index 03e61e9f472..ff84a0a334c 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
@@ -1,6 +1,6 @@
-void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
+void camera(out vec3 outview, out float outdepth, out float outdist)
{
- outdepth = abs(co.z);
- outdist = length(co);
- outview = normalize(co);
+ outdepth = abs(transform_point(ViewMatrix, g_data.P).z);
+ outdist = distance(g_data.P, cameraPos);
+ outview = normalize(g_data.P - cameraPos);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
index 2ce061da3cb..e8f444080b9 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
void combine_hsv(float h, float s, float v, out vec4 col)
{
hsv_to_rgb(vec4(h, s, v, 1.0), col);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
index ab6024b073d..bbdd86bd664 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
@@ -1,28 +1,11 @@
-#ifndef VOLUMETRICS
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_diffuse, Diffuse)
-
-void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
+void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, float weight, out Closure result)
{
- CLOSURE_VARS_DECLARE_1(Diffuse);
-
- in_Diffuse_0.N = N; /* Normalized during eval. */
- in_Diffuse_0.albedo = color.rgb;
-
- CLOSURE_EVAL_FUNCTION_1(node_bsdf_diffuse, Diffuse);
-
- result = CLOSURE_DEFAULT;
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = weight;
+ diffuse_data.color = color.rgb;
+ diffuse_data.N = N;
+ diffuse_data.sss_id = 0u;
- out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1.0), out_Diffuse_0.radiance);
- out_Diffuse_0.radiance *= color.rgb;
-
- result.radiance = out_Diffuse_0.radiance;
-
- /* TODO(@fclem): Try to not use this. */
- closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
+ result = closure_eval(diffuse_data);
}
-
-#else
-/* Stub diffuse because it is not compatible with volumetrics. */
-# define node_bsdf_diffuse(a, b, c, d) (d = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl
index 0838b5c8b71..cdcdbe50917 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl
@@ -1,9 +1,9 @@
-void node_displacement_object(
- float height, float midlevel, float scale, vec3 N, mat4 obmat, out vec3 result)
+void node_displacement_object(float height, float midlevel, float scale, vec3 N, out vec3 result)
{
- N = (vec4(N, 0.0) * obmat).xyz;
+ N = transform_direction(ModelMatrix, N);
result = (height - midlevel) * scale * normalize(N);
- result = (obmat * vec4(result, 0.0)).xyz;
+ /* Apply object scale and orientation. */
+ result = transform_direction(ModelMatrix, result);
}
void node_displacement_world(float height, float midlevel, float scale, vec3 N, out vec3 result)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
index 0941482df45..c81880184e3 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
@@ -1,80 +1,69 @@
-#ifndef VOLUMETRICS
-
-CLOSURE_EVAL_FUNCTION_DECLARE_3(node_eevee_specular, Diffuse, Glossy, Glossy)
void node_eevee_specular(vec4 diffuse,
vec4 specular,
float roughness,
vec4 emissive,
float transp,
- vec3 normal,
+ vec3 N,
float clearcoat,
float clearcoat_roughness,
- vec3 clearcoat_normal,
+ vec3 CN,
float occlusion,
- float ssr_id,
+ float weight,
+ const float use_clearcoat,
out Closure result)
{
- CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy);
-
- in_common.occlusion = occlusion;
-
- in_Diffuse_0.N = normal; /* Normalized during eval. */
- in_Diffuse_0.albedo = diffuse.rgb;
+ N = safe_normalize(N);
+ CN = safe_normalize(CN);
+ vec3 V = cameraVec(g_data.P);
- in_Glossy_1.N = normal; /* Normalized during eval. */
- in_Glossy_1.roughness = roughness;
+ ClosureEmission emission_data;
+ emission_data.weight = weight;
+ emission_data.emission = emissive.rgb;
- in_Glossy_2.N = clearcoat_normal; /* Normalized during eval. */
- in_Glossy_2.roughness = clearcoat_roughness;
+ ClosureTransparency transparency_data;
+ transparency_data.weight = weight;
+ transparency_data.transmittance = vec3(transp);
+ transparency_data.holdout = 0.0;
- CLOSURE_EVAL_FUNCTION_3(node_eevee_specular, Diffuse, Glossy, Glossy);
+ float alpha = (1.0 - transp) * weight;
- result = CLOSURE_DEFAULT;
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = alpha;
+ diffuse_data.color = diffuse.rgb;
+ diffuse_data.N = N;
+ diffuse_data.sss_id = 0u;
- vec3 V = cameraVec(worldPosition);
-
- {
- /* Diffuse. */
- out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1), out_Diffuse_0.radiance);
- out_Diffuse_0.radiance *= in_Diffuse_0.albedo;
- result.radiance += out_Diffuse_0.radiance;
- }
- {
- /* Glossy. */
- float NV = dot(in_Glossy_1.N, V);
- vec2 split_sum = brdf_lut(NV, in_Glossy_1.roughness);
+ ClosureReflection reflection_data;
+ reflection_data.weight = alpha;
+ if (true) {
+ float NV = dot(N, V);
+ vec2 split_sum = brdf_lut(NV, roughness);
vec3 brdf = F_brdf_single_scatter(specular.rgb, vec3(1.0), split_sum);
- out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);
- out_Glossy_1.radiance *= brdf;
- out_Glossy_1.radiance = render_pass_glossy_mask(specular.rgb, out_Glossy_1.radiance);
- closure_load_ssr_data(
- out_Glossy_1.radiance, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
+ reflection_data.color = specular.rgb * brdf;
+ reflection_data.N = N;
+ reflection_data.roughness = roughness;
}
- {
- /* Clearcoat. */
- float NV = dot(in_Glossy_2.N, V);
- vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
+
+ ClosureReflection clearcoat_data;
+ clearcoat_data.weight = alpha * clearcoat * 0.25;
+ if (true) {
+ float NV = dot(CN, V);
+ vec2 split_sum = brdf_lut(NV, clearcoat_roughness);
vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
- out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
- out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
- result.radiance += out_Glossy_2.radiance;
- }
- {
- /* Emission. */
- vec3 out_emission_radiance = render_pass_emission_mask(emissive.rgb);
- result.radiance += out_emission_radiance;
+ clearcoat_data.color = brdf;
+ clearcoat_data.N = CN;
+ clearcoat_data.roughness = clearcoat_roughness;
}
- float alpha = 1.0 - transp;
- result.transmittance = vec3(transp);
- result.radiance *= alpha;
- result.ssr_data.rgb *= alpha;
+ if (use_clearcoat != 0.0f) {
+ result = closure_eval(diffuse_data, reflection_data, clearcoat_data);
+ }
+ else {
+ result = closure_eval(diffuse_data, reflection_data);
+ }
+ result = closure_add(result, closure_eval(emission_data));
+ result = closure_add(result, closure_eval(transparency_data));
}
-
-#else
-/* Stub specular because it is not compatible with volumetrics. */
-# define node_eevee_specular(a, b, c, d, e, f, g, h, i, j, k, result) (result = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl
index f2de7c2da39..32484491abd 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl
@@ -1,10 +1,9 @@
-void node_emission(vec4 color, float strength, vec3 vN, out Closure result)
+
+void node_emission(vec4 color, float strength, float weight, out Closure result)
{
- result = CLOSURE_DEFAULT;
-#ifndef VOLUMETRICS
- result.radiance = render_pass_emission_mask(color.rgb) * strength;
- result.ssr_normal = normal_encode(vN, viewCameraVec(viewPosition));
-#else
- result.emission = color.rgb * strength;
-#endif
+ ClosureEmission emission_data;
+ emission_data.weight = weight;
+ emission_data.emission = color.rgb * strength;
+
+ result = closure_eval(emission_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
index 95f2be4bd44..7f502f74c0c 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
@@ -1,3 +1,6 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
+
/* The fractal_noise functions are all exactly the same except for the input type. */
float fractal_noise(float p, float octaves, float roughness)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl
index 7a4d28f2dd6..9fb98d598ab 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl
@@ -26,12 +26,11 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
}
-void node_fresnel(float ior, vec3 N, vec3 I, out float result)
+void node_fresnel(float ior, vec3 N, out float result)
{
N = normalize(N);
- /* handle perspective/orthographic */
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ vec3 V = cameraVec(g_data.P);
float eta = max(ior, 0.00001);
- result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
+ result = fresnel_dielectric(V, N, (FrontFacing) ? eta : 1.0 / eta);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
index 5733992f8dd..29fb09ceebd 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
void node_gamma(vec4 col, float gamma, out vec4 outcol)
{
outcol = col;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
index a14ff5021bf..5e86a4577ee 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
@@ -1,9 +1,6 @@
-void node_geometry(vec3 I,
- vec3 N,
- vec3 orco,
- mat4 objmat,
- mat4 toworld,
- vec2 barycentric,
+#pragma BLENDER_REQUIRE(gpu_shader_material_tangent.glsl)
+
+void node_geometry(vec3 orco,
out vec3 position,
out vec3 normal,
out vec3 tangent,
@@ -15,39 +12,21 @@ void node_geometry(vec3 I,
out float random_per_island)
{
/* handle perspective/orthographic */
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
- incoming = -(toworld * vec4(I_view, 0.0)).xyz;
-
-#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- position = -incoming;
- true_normal = normal = incoming;
- tangent = parametric = vec3(0.0);
- vec3(0.0);
- backfacing = 0.0;
- pointiness = 0.0;
-#else
-
- position = worldPosition;
-# ifndef VOLUMETRICS
- normal = normalize(N);
- vec3 B = dFdx(worldPosition);
- vec3 T = dFdy(worldPosition);
- true_normal = normalize(cross(B, T));
-# else
- normal = (toworld * vec4(N, 0.0)).xyz;
- true_normal = normal;
-# endif
+ incoming = coordinate_incoming(g_data.P);
+ position = g_data.P;
+ normal = g_data.N;
+ true_normal = g_data.Ng;
-# ifdef HAIR_SHADER
- tangent = -hairTangent;
-# else
- tangent_orco_z(orco, orco);
- node_tangent(N, orco, objmat, tangent);
-# endif
+ if (g_data.is_strand) {
+ tangent = g_data.T;
+ }
+ else {
+ tangent_orco_z(orco, orco);
+ node_tangent(orco, tangent);
+ }
- parametric = vec3(barycentric, 0.0);
- backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
+ parametric = vec3(g_data.barycentric_coords, 0.0);
+ backfacing = (FrontFacing) ? 0.0 : 1.0;
pointiness = 0.5;
random_per_island = 0.0;
-#endif
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
index aa0a8873596..36c71c27837 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
@@ -1,57 +1,33 @@
-#ifndef VOLUMETRICS
-
-CLOSURE_EVAL_FUNCTION_DECLARE_2(node_bsdf_glass, Glossy, Refraction)
void node_bsdf_glass(vec4 color,
float roughness,
float ior,
vec3 N,
- const float do_multiscatter,
- const float ssr_id,
+ float weight,
+ float do_multiscatter,
out Closure result)
{
- CLOSURE_VARS_DECLARE_2(Glossy, Refraction);
-
- in_Glossy_0.N = N; /* Normalized during eval. */
- in_Glossy_0.roughness = roughness;
-
- in_Refraction_1.N = N; /* Normalized during eval. */
- in_Refraction_1.roughness = roughness;
- in_Refraction_1.ior = ior;
+ N = safe_normalize(N);
+ vec3 V = cameraVec(g_data.P);
+ float NV = dot(N, V);
- CLOSURE_EVAL_FUNCTION_2(node_bsdf_glass, Glossy, Refraction);
+ vec2 split_sum = btdf_lut(NV, roughness, ior);
- result = CLOSURE_DEFAULT;
+ float fresnel = (do_multiscatter != 0.0) ? split_sum.y : F_eta(ior, NV);
+ float btdf = (do_multiscatter != 0.0) ? 1.0 : split_sum.x;
- float NV = dot(in_Refraction_1.N, cameraVec(worldPosition));
+ ClosureReflection reflection_data;
+ reflection_data.weight = fresnel * weight;
+ reflection_data.color = color.rgb;
+ reflection_data.N = N;
+ reflection_data.roughness = roughness;
- float fresnel = (do_multiscatter != 0.0) ?
- btdf_lut(NV, in_Refraction_1.roughness, in_Refraction_1.ior).y :
- F_eta(in_Refraction_1.ior, NV);
+ ClosureRefraction refraction_data;
+ refraction_data.weight = (1.0 - fresnel) * weight;
+ refraction_data.color = color.rgb * btdf;
+ refraction_data.N = N;
+ refraction_data.roughness = roughness;
+ refraction_data.ior = ior;
- vec2 split_sum = brdf_lut(NV, in_Glossy_0.roughness);
- vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) :
- F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum);
-
- out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id);
- out_Glossy_0.radiance *= brdf;
- out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance);
- out_Glossy_0.radiance *= color.rgb * fresnel;
- closure_load_ssr_data(
- out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result);
-
- float btdf = (do_multiscatter != 0.0) ?
- 1.0 :
- btdf_lut(NV, in_Refraction_1.roughness, in_Refraction_1.ior).x;
- out_Refraction_1.radiance *= btdf;
- out_Refraction_1.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_1.radiance);
- out_Refraction_1.radiance *= color.rgb * (1.0 - fresnel);
- /* Simulate 2nd absorption event. */
- out_Refraction_1.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0);
- result.radiance += out_Refraction_1.radiance;
+ result = closure_eval(reflection_data, refraction_data);
}
-
-#else
-/* Stub glass because it is not compatible with volumetrics. */
-# define node_bsdf_glass(a, b, c, d, e, f, result) (result = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
index fa83bfb6c7a..2e48ddd1c5e 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
@@ -1,33 +1,20 @@
-#ifndef VOLUMETRICS
-
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_glossy, Glossy)
void node_bsdf_glossy(
- vec4 color, float roughness, vec3 N, float use_multiscatter, float ssr_id, out Closure result)
+ vec4 color, float roughness, vec3 N, float weight, float do_multiscatter, out Closure result)
{
- bool do_ssr = (ssrToggle && int(ssr_id) == outputSsrId);
-
- CLOSURE_VARS_DECLARE_1(Glossy);
+ N = safe_normalize(N);
+ vec3 V = cameraVec(g_data.P);
+ float NV = dot(N, V);
- in_Glossy_0.N = N; /* Normalized during eval. */
- in_Glossy_0.roughness = roughness;
+ vec2 split_sum = brdf_lut(NV, roughness);
- CLOSURE_EVAL_FUNCTION_1(node_bsdf_glossy, Glossy);
+ ClosureReflection reflection_data;
+ reflection_data.weight = weight;
+ reflection_data.color = (do_multiscatter != 0.0) ?
+ F_brdf_multi_scatter(color.rgb, color.rgb, split_sum) :
+ F_brdf_single_scatter(color.rgb, color.rgb, split_sum);
+ reflection_data.N = N;
+ reflection_data.roughness = roughness;
- result = CLOSURE_DEFAULT;
-
- vec2 split_sum = brdf_lut(dot(in_Glossy_0.N, cameraVec(worldPosition)), in_Glossy_0.roughness);
- vec3 brdf = (use_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) :
- F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum);
- out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id);
- out_Glossy_0.radiance *= brdf;
- out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance);
- out_Glossy_0.radiance *= color.rgb;
- closure_load_ssr_data(
- out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result);
+ result = closure_eval(reflection_data);
}
-
-#else
-/* Stub glossy because it is not compatible with volumetrics. */
-# define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
new file mode 100644
index 00000000000..7bf8795495a
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
@@ -0,0 +1,46 @@
+
+void node_bsdf_hair(vec4 color,
+ float offset,
+ float roughness_u,
+ float roughness_v,
+ vec3 T,
+ float weight,
+ out Closure result)
+{
+ ClosureHair hair_data;
+ hair_data.weight = weight;
+ hair_data.color = color.rgb;
+ hair_data.offset = offset;
+ hair_data.roughness = vec2(roughness_u, roughness_v);
+ hair_data.T = T;
+
+ result = closure_eval(hair_data);
+}
+
+void node_bsdf_hair_principled(vec4 color,
+ float melanin,
+ float melanin_redness,
+ vec4 tint,
+ vec3 absorption_coefficient,
+ float roughness,
+ float radial_roughness,
+ float coat,
+ float ior,
+ float offset,
+ float random_color,
+ float random_roughness,
+ float random,
+ float weight,
+ out Closure result)
+{
+ /* Placeholder closure.
+ * Some computation will have to happen here just like the Principled BSDF. */
+ ClosureHair hair_data;
+ hair_data.weight = weight;
+ hair_data.color = color.rgb;
+ hair_data.offset = offset;
+ hair_data.roughness = vec2(0.0);
+ hair_data.T = g_data.T;
+
+ result = closure_eval(hair_data);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
index 59f0377869b..2885bf4e082 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
@@ -1,25 +1,19 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+
void node_hair_info(float hair_length,
out float is_strand,
out float intercept,
- out float length,
+ out float out_length,
out float thickness,
out vec3 tangent,
out float random)
{
- length = hair_length;
-#ifdef HAIR_SHADER
- is_strand = 1.0;
- intercept = hairTime;
- thickness = hairThickness;
- tangent = normalize(worldNormal);
- random = wang_hash_noise(
- uint(hairStrandID)); /* TODO: could be precomputed per strand instead. */
-#else
- is_strand = 0.0;
- intercept = 0.0;
- thickness = 0.0;
- tangent = vec3(1.0);
- random = 0.0;
-#endif
+ is_strand = float(g_data.is_strand);
+ intercept = g_data.hair_time;
+ thickness = g_data.hair_thickness;
+ out_length = hair_length;
+ tangent = g_data.T;
+ /* TODO: could be precomputed per strand instead. */
+ random = wang_hash_noise(uint(g_data.hair_strand_id));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl
index 50ce2bf2ab8..d022c1ced59 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl
@@ -1,8 +1,10 @@
-void node_holdout(out Closure result)
+
+void node_holdout(float weight, out Closure result)
{
- result = CLOSURE_DEFAULT;
-#ifndef VOLUMETRICS
- result.holdout = 1.0;
- result.flag = CLOSURE_HOLDOUT_FLAG;
-#endif
+ ClosureTransparency transparency_data;
+ transparency_data.weight = weight;
+ transparency_data.transmittance = vec3(0.0);
+ transparency_data.holdout = 1.0;
+
+ result = closure_eval(transparency_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
index 64ac73ecdf3..30b808508e9 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol)
{
vec4 hsv;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl
index 588d295bcc4..2b61343a200 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl
@@ -1,15 +1,17 @@
-void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float facing)
+#pragma BLENDER_REQUIRE(gpu_shader_material_fresnel.glsl)
+
+void node_layer_weight(float blend, vec3 N, out float fresnel, out float facing)
{
N = normalize(N);
/* fresnel */
float eta = max(1.0 - blend, 0.00001);
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ vec3 V = cameraVec(g_data.P);
- fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
+ fresnel = fresnel_dielectric(V, N, (FrontFacing) ? 1.0 / eta : eta);
/* facing */
- facing = abs(dot(I_view, N));
+ facing = abs(dot(V, N));
if (blend != 0.5) {
blend = clamp(blend, 0.0, 0.99999);
blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
index 50c87e3f105..628a3d5e0e5 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
@@ -13,19 +13,19 @@ void node_light_path(out float is_camera_ray,
out float transmission_depth)
{
/* Supported. */
- is_camera_ray = (rayType == EEVEE_RAY_CAMERA) ? 1.0 : 0.0;
- is_shadow_ray = (rayType == EEVEE_RAY_SHADOW) ? 1.0 : 0.0;
- is_diffuse_ray = (rayType == EEVEE_RAY_DIFFUSE) ? 1.0 : 0.0;
- is_glossy_ray = (rayType == EEVEE_RAY_GLOSSY) ? 1.0 : 0.0;
+ is_camera_ray = float(g_data.ray_type == RAY_TYPE_CAMERA);
+ is_shadow_ray = float(g_data.ray_type == RAY_TYPE_SHADOW);
+ is_diffuse_ray = float(g_data.ray_type == RAY_TYPE_DIFFUSE);
+ is_glossy_ray = float(g_data.ray_type == RAY_TYPE_GLOSSY);
/* Kind of supported. */
is_singular_ray = is_glossy_ray;
is_reflection_ray = is_glossy_ray;
is_transmission_ray = is_glossy_ray;
- ray_depth = rayDepth;
- diffuse_depth = (is_diffuse_ray == 1.0) ? rayDepth : 0.0;
- glossy_depth = (is_glossy_ray == 1.0) ? rayDepth : 0.0;
+ ray_depth = g_data.ray_depth;
+ diffuse_depth = (is_diffuse_ray == 1.0) ? g_data.ray_depth : 0.0;
+ glossy_depth = (is_glossy_ray == 1.0) ? g_data.ray_depth : 0.0;
transmission_depth = (is_transmission_ray == 1.0) ? glossy_depth : 0.0;
+ ray_length = g_data.ray_length;
/* Not supported. */
- ray_length = 1.0;
transparent_depth = 0.0;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
index 1def3abec26..119ee3c0eaa 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
float smootherstep(float edge0, float edge1, float x)
{
x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
index 07f152439fe..312c57231c5 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
void mapping_mat4(
vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
index f200d666e28..0948ce2c9fa 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
void math_add(float a, float b, float c, out float result)
{
result = a + b;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
index 2a98d9fadd0..91a8996939a 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
@@ -140,17 +140,74 @@ mat3 euler_to_mat3(vec3 euler)
return mat;
}
-void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+void normal_transform_object_to_world(vec3 vin, out vec3 vout)
{
- vout = (mat * vec4(vin, 0.0)).xyz;
+ vout = normal_object_to_world(vin);
}
-void normal_transform_transposed_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+void normal_transform_world_to_object(vec3 vin, out vec3 vout)
{
- vout = transpose(mat3(mat)) * vin;
+ vout = normal_world_to_object(vin);
}
-void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+void direction_transform_object_to_world(vec3 vin, out vec3 vout)
{
- vout = (mat * vec4(vin, 1.0)).xyz;
+ vout = transform_direction(ModelMatrix, vin);
+}
+
+void direction_transform_object_to_view(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ModelMatrix, vin);
+ vout = transform_direction(ViewMatrix, vout);
+}
+
+void direction_transform_view_to_world(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ViewMatrixInverse, vin);
+}
+
+void direction_transform_view_to_object(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ViewMatrixInverse, vin);
+ vout = transform_direction(ModelMatrixInverse, vout);
+}
+
+void direction_transform_world_to_view(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ViewMatrix, vin);
+}
+
+void direction_transform_world_to_object(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ModelMatrixInverse, vin);
+}
+
+void point_transform_object_to_world(vec3 vin, out vec3 vout)
+{
+ vout = point_object_to_world(vin);
+}
+
+void point_transform_object_to_view(vec3 vin, out vec3 vout)
+{
+ vout = point_object_to_view(vin);
+}
+
+void point_transform_view_to_world(vec3 vin, out vec3 vout)
+{
+ vout = point_view_to_world(vin);
+}
+
+void point_transform_view_to_object(vec3 vin, out vec3 vout)
+{
+ vout = point_view_to_object(vin);
+}
+
+void point_transform_world_to_view(vec3 vin, out vec3 vout)
+{
+ vout = point_world_to_view(vin);
+}
+
+void point_transform_world_to_object(vec3 vin, out vec3 vout)
+{
+ vout = point_world_to_object(vin);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
index e089aec1d92..157a6a27c15 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
void mix_blend(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
index cc65b1eb57c..c84f34a834c 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+
/* clang-format off */
#define FLOORFRAC(x, x_int, x_fract) { float x_floor = floor(x); x_int = int(x_floor); x_fract = x - x_floor; }
/* clang-format on */
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
index 2b4a0204d97..e219e2b9bbe 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
@@ -1,13 +1,13 @@
-void node_normal_map(vec4 info, vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
+void node_normal_map(vec4 tangent, vec3 texnormal, out vec3 outnormal)
{
if (all(equal(tangent, vec4(0.0, 0.0, 0.0, 1.0)))) {
- outnormal = normal;
+ outnormal = g_data.N;
return;
}
- tangent *= (gl_FrontFacing ? 1.0 : -1.0);
- vec3 B = tangent.w * cross(normal, tangent.xyz) * sign(info.w);
+ tangent *= (FrontFacing ? 1.0 : -1.0);
+ vec3 B = tangent.w * cross(g_data.N, tangent.xyz) * sign(ObjectInfo.w);
- outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
+ outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * g_data.N;
outnormal = normalize(outnormal);
}
@@ -21,7 +21,7 @@ void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
normal = vec3(2.0, -2.0, -2.0) * color - vec3(1.0);
}
-void node_normal_map_mix(float strength, vec3 newnormal, vec3 oldnormal, out vec3 outnormal)
+void node_normal_map_mix(float strength, vec3 newnormal, out vec3 outnormal)
{
- outnormal = normalize(mix(oldnormal, newnormal, max(strength, 0.0)));
+ outnormal = normalize(mix(g_data.N, newnormal, max(strength, 0.0)));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl
index 607cf119b36..2dd2993ceb0 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl
@@ -1,7 +1,4 @@
-void node_object_info(mat4 obmat,
- vec4 obcolor,
- vec4 info,
- float mat_index,
+void node_object_info(float mat_index,
out vec3 location,
out vec4 color,
out float alpha,
@@ -9,10 +6,11 @@ void node_object_info(mat4 obmat,
out float material_index,
out float random)
{
- location = obmat[3].xyz;
- color = obcolor;
- alpha = obcolor.w;
- object_index = info.x;
+ location = ModelMatrix[3].xyz;
+ color = ObjectColor;
+ alpha = ObjectColor.a;
+ object_index = ObjectInfo.x;
+ /* TODO(fclem): Put that inside the Material UBO. */
material_index = mat_index;
- random = info.z;
+ random = ObjectInfo.z;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl
index 648994739bf..b166c3e4e9f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl
@@ -1,13 +1,5 @@
-void node_output_aov(vec4 color, float value, out Closure result)
+void node_output_aov(vec4 color, float value, float hash, out Closure dummy)
{
- result = CLOSURE_DEFAULT;
-#ifndef VOLUMETRICS
- if (render_pass_aov_is_color()) {
- result.radiance = color.rgb;
- }
- else {
- result.radiance = vec3(value);
- }
-#endif
+ output_aov(color, value, floatBitsToUint(hash));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
index 14271f9d107..2c24f50264c 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
@@ -1,20 +1,20 @@
-void node_output_material(Closure surface,
- Closure volume,
- vec3 displacement,
- float alpha_threshold,
- float shadow_threshold,
- out Closure result)
+
+void node_output_material_surface(Closure surface, out Closure out_surface)
{
-#ifdef VOLUMETRICS
- result = volume;
-#else
- result = surface;
-# if defined(USE_ALPHA_HASH)
- /* Alpha clip emulation. */
- if ((rayType != EEVEE_RAY_SHADOW) ? (alpha_threshold >= 0.0) : (shadow_threshold >= 0.0)) {
- float alpha = saturate(1.0 - avg(result.transmittance));
- result.transmittance = vec3(step(alpha, max(alpha_threshold, shadow_threshold)));
- }
-# endif
-#endif
+ out_surface = surface;
+}
+
+void node_output_material_volume(Closure volume, out Closure out_volume)
+{
+ out_volume = volume;
+}
+
+void node_output_material_displacement(vec3 displacement, out vec3 out_displacement)
+{
+ out_displacement = displacement;
+}
+
+void node_output_material_thickness(float thickness, out float out_thickness)
+{
+ out_thickness = thickness;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl
index 5eb853a4c1a..37c34a4f0d7 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl
@@ -1,14 +1,10 @@
-uniform float backgroundAlpha;
-void node_output_world(Closure surface, Closure volume, out Closure result)
+void node_output_world_surface(Closure surface, out Closure out_surface)
{
-#ifndef VOLUMETRICS
- float alpha = renderPassEnvironment ? 1.0 : backgroundAlpha;
- result = CLOSURE_DEFAULT;
- result.radiance = surface.radiance * alpha;
- result.transmittance = vec3(0.0);
- result.holdout = (1.0 - alpha);
-#else
- result = volume;
-#endif /* VOLUMETRICS */
+ out_surface = surface;
+}
+
+void node_output_world_volume(Closure volume, out Closure out_volume)
+{
+ out_volume = volume;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl
index bdd60c20a81..5602345ea4a 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl
@@ -1,8 +1,4 @@
-void particle_info(vec4 sprops,
- vec4 loc,
- vec3 vel,
- vec3 avel,
- out float index,
+void particle_info(out float index,
out float random,
out float age,
out float life_time,
@@ -11,13 +7,14 @@ void particle_info(vec4 sprops,
out vec3 velocity,
out vec3 angular_velocity)
{
- index = sprops.x;
- random = loc.w;
- age = sprops.y;
- life_time = sprops.z;
- size = sprops.w;
+ /* Unsupported for now. */
+ index = 0.0;
+ random = 0.0;
+ age = 0.0;
+ life_time = 0.0;
+ size = 0.0;
- location = loc.xyz;
- velocity = vel;
- angular_velocity = avel;
+ location = vec3(0.0);
+ velocity = vec3(0.0);
+ angular_velocity = vec3(0.0);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
index d717ac97b28..1b1fed9502e 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+
void node_point_info(out vec3 position, out float radius, out float random)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
index c97fc090fe2..033dc05c57d 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -1,4 +1,4 @@
-#ifndef VOLUMETRICS
+
vec3 tint_from_color(vec3 color)
{
float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
@@ -13,8 +13,6 @@ float principled_sheen(float NV)
return sheen;
}
-CLOSURE_EVAL_FUNCTION_DECLARE_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction)
-
void node_bsdf_principled(vec4 base_color,
float subsurface,
vec3 subsurface_radius,
@@ -40,169 +38,137 @@ void node_bsdf_principled(vec4 base_color,
vec3 N,
vec3 CN,
vec3 T,
+ float weight,
const float do_diffuse,
const float do_clearcoat,
const float do_refraction,
const float do_multiscatter,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
+ float do_sss,
out Closure result)
{
/* Match cycles. */
- metallic = saturate(metallic);
- transmission = saturate(transmission);
+ metallic = clamp(metallic, 0.0, 1.0);
+ transmission = clamp(transmission, 0.0, 1.0) * (1.0 - metallic);
float diffuse_weight = (1.0 - transmission) * (1.0 - metallic);
- transmission *= (1.0 - metallic);
float specular_weight = (1.0 - transmission);
- clearcoat = max(clearcoat, 0.0);
+ float clearcoat_weight = max(clearcoat, 0.0) * 0.25;
transmission_roughness = 1.0 - (1.0 - roughness) * (1.0 - transmission_roughness);
specular = max(0.0, specular);
- CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction);
-
- in_Diffuse_0.N = N; /* Normalized during eval. */
- in_Diffuse_0.albedo = mix(base_color.rgb, subsurface_color.rgb, subsurface);
-
- in_Glossy_1.N = N; /* Normalized during eval. */
- in_Glossy_1.roughness = roughness;
-
- in_Glossy_2.N = CN; /* Normalized during eval. */
- in_Glossy_2.roughness = clearcoat_roughness;
-
- in_Refraction_3.N = N; /* Normalized during eval. */
- in_Refraction_3.roughness = do_multiscatter != 0.0 ? roughness : transmission_roughness;
- in_Refraction_3.ior = ior;
+ N = safe_normalize(N);
+ CN = safe_normalize(CN);
+ vec3 V = cameraVec(g_data.P);
+ float NV = dot(N, V);
- CLOSURE_EVAL_FUNCTION_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction);
+ float fresnel = (do_multiscatter != 0.0) ? btdf_lut(NV, roughness, ior).y : F_eta(ior, NV);
+ float glass_reflection_weight = fresnel * transmission;
+ float glass_transmission_weight = (1.0 - fresnel) * transmission;
- result = CLOSURE_DEFAULT;
+ vec3 base_color_tint = tint_from_color(base_color.rgb);
- /* This will tag the whole eval for optimisation. */
- if (do_diffuse == 0.0) {
- out_Diffuse_0.radiance = vec3(0);
- }
- if (do_clearcoat == 0.0) {
- out_Glossy_2.radiance = vec3(0);
- }
- if (do_refraction == 0.0) {
- out_Refraction_3.radiance = vec3(0);
+ vec2 split_sum = brdf_lut(NV, roughness);
+
+ ClosureTransparency transparency_data;
+ transparency_data.weight = weight;
+ transparency_data.transmittance = vec3(1.0 - alpha);
+ transparency_data.holdout = 0.0;
+
+ weight *= alpha;
+
+ ClosureEmission emission_data;
+ emission_data.weight = weight;
+ emission_data.emission = emission.rgb * emission_strength;
+
+ /* Diffuse. */
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = diffuse_weight * weight;
+ diffuse_data.color = mix(base_color.rgb, subsurface_color.rgb, subsurface);
+ /* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */
+ vec3 sheen_color = mix(vec3(1.0), base_color_tint, sheen_tint);
+ diffuse_data.color += sheen * sheen_color * principled_sheen(NV);
+ diffuse_data.N = N;
+ diffuse_data.sss_radius = subsurface_radius * subsurface;
+ diffuse_data.sss_id = uint(do_sss);
+
+ /* NOTE(@fclem): We need to blend the reflection color but also need to avoid applying the
+ * weights so we compule the ratio. */
+ float reflection_weight = specular_weight + glass_reflection_weight;
+ float reflection_weight_inv = safe_rcp(reflection_weight);
+ specular_weight *= reflection_weight_inv;
+ glass_reflection_weight *= reflection_weight_inv;
+
+ /* Reflection. */
+ ClosureReflection reflection_data;
+ reflection_data.weight = reflection_weight * weight;
+ reflection_data.N = N;
+ reflection_data.roughness = roughness;
+ if (true) {
+ vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint);
+ vec3 metallic_f0_color = base_color.rgb;
+ vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic);
+ /* Cycles does this blending using the microfacet fresnel factor. However, our fresnel
+ * is already baked inside the split sum LUT. We approximate by changing the f90 color
+ * directly in a non linear fashion. */
+ vec3 f90 = mix(f0, vec3(1.0), fast_sqrt(specular));
+
+ vec3 reflection_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
+ F_brdf_single_scatter(f0, f90, split_sum);
+ reflection_data.color = reflection_brdf * specular_weight;
}
+ if (true) {
+ /* Poor approximation since we baked the LUT using a fixed IOR. */
+ vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
+ vec3 f90 = vec3(1.0);
- vec3 V = cameraVec(worldPosition);
+ vec3 glass_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
+ F_brdf_single_scatter(f0, f90, split_sum);
- /* Glossy_1 will always be evaluated. */
- float NV = dot(in_Glossy_1.N, V);
-
- vec3 base_color_tint = tint_from_color(base_color.rgb);
+ /* Avoid 3 glossy evaluation. Use the same closure for glass reflection. */
+ reflection_data.color += glass_brdf * glass_reflection_weight;
+ }
- float fresnel = (do_multiscatter != 0.0) ?
- btdf_lut(NV, in_Glossy_1.roughness, in_Refraction_3.ior).y :
- F_eta(in_Refraction_3.ior, NV);
-
- {
- /* Glossy reflections.
- * Separate Glass reflections and main specular reflections to match Cycles renderpasses. */
- out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);
-
- vec2 split_sum = brdf_lut(NV, roughness);
-
- vec3 glossy_radiance_final = vec3(0.0);
- if (transmission > 1e-5) {
- /* Glass Reflection: Reuse radiance from Glossy1. */
- vec3 out_glass_refl_radiance = out_Glossy_1.radiance;
-
- /* Poor approximation since we baked the LUT using a fixed IOR. */
- vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
- vec3 f90 = vec3(1);
-
- vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
- F_brdf_single_scatter(f0, f90, split_sum);
-
- out_glass_refl_radiance *= brdf;
- out_glass_refl_radiance = render_pass_glossy_mask(vec3(1), out_glass_refl_radiance);
- out_glass_refl_radiance *= fresnel * transmission;
- glossy_radiance_final += out_glass_refl_radiance;
- }
- if (specular_weight > 1e-5) {
- vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint);
- vec3 metallic_f0_color = base_color.rgb;
- vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic);
- /* Cycles does this blending using the microfacet fresnel factor. However, our fresnel
- * is already baked inside the split sum LUT. We approximate using by modifying the
- * changing the f90 color directly in a non linear fashion. */
- vec3 f90 = mix(f0, vec3(1), fast_sqrt(specular));
-
- vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
- F_brdf_single_scatter(f0, f90, split_sum);
-
- out_Glossy_1.radiance *= brdf;
- out_Glossy_1.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_1.radiance);
- out_Glossy_1.radiance *= specular_weight;
- glossy_radiance_final += out_Glossy_1.radiance;
- }
-
- closure_load_ssr_data(
- glossy_radiance_final, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
+ ClosureReflection clearcoat_data;
+ clearcoat_data.weight = clearcoat_weight * weight;
+ clearcoat_data.N = CN;
+ clearcoat_data.roughness = clearcoat_roughness;
+ if (true) {
+ float NV = dot(clearcoat_data.N, V);
+ vec2 split_sum = brdf_lut(NV, clearcoat_data.roughness);
+ vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
+ clearcoat_data.color = brdf;
}
- if (diffuse_weight > 1e-5) {
- /* Mask over all diffuse radiance. */
- out_Diffuse_0.radiance *= diffuse_weight;
+ /* Refraction. */
+ ClosureRefraction refraction_data;
+ refraction_data.weight = glass_transmission_weight * weight;
+ float btdf = (do_multiscatter != 0.0) ? 1.0 : btdf_lut(NV, roughness, ior).x;
- /* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */
- vec3 sheen_color = mix(vec3(1), base_color_tint, sheen_tint);
- vec3 out_sheen_radiance = out_Diffuse_0.radiance * principled_sheen(NV);
- out_sheen_radiance = render_pass_diffuse_mask(vec3(1), out_sheen_radiance);
- out_sheen_radiance *= sheen * sheen_color;
- result.radiance += out_sheen_radiance;
+ refraction_data.color = base_color.rgb * btdf;
+ refraction_data.N = N;
+ refraction_data.roughness = do_multiscatter != 0.0 ? roughness :
+ max(roughness, transmission_roughness);
+ refraction_data.ior = ior;
- /* Diffuse / Subsurface. */
- float scale = avg(sss_scale) * subsurface;
- closure_load_sss_data(scale, out_Diffuse_0.radiance, in_Diffuse_0.albedo, int(sss_id), result);
+ if (do_diffuse == 0.0 && do_refraction == 0.0 && do_clearcoat != 0.0) {
+ /* Metallic & Clearcoat case. */
+ result = closure_eval(reflection_data, clearcoat_data);
}
-
- if (transmission > 1e-5) {
- float btdf = (do_multiscatter != 0.0) ?
- 1.0 :
- btdf_lut(NV, in_Refraction_3.roughness, in_Refraction_3.ior).x;
- /* TODO(@fclem): This could be going to a transmission render pass instead. */
- out_Refraction_3.radiance *= btdf;
- out_Refraction_3.radiance = render_pass_glossy_mask(vec3(1), out_Refraction_3.radiance);
- out_Refraction_3.radiance *= base_color.rgb;
- /* Simulate 2nd transmission event. */
- out_Refraction_3.radiance *= (refractionDepth > 0.0) ? base_color.rgb : vec3(1);
- out_Refraction_3.radiance *= (1.0 - fresnel) * transmission;
- result.radiance += out_Refraction_3.radiance;
+ else if (do_diffuse == 0.0 && do_refraction == 0.0 && do_clearcoat == 0.0) {
+ /* Metallic case. */
+ result = closure_eval(reflection_data);
}
-
- if (clearcoat > 1e-5) {
- float NV = dot(in_Glossy_2.N, V);
- vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
- vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
-
- out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
- out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
- result.radiance += out_Glossy_2.radiance;
+ else if (do_diffuse != 0.0 && do_refraction == 0.0 && do_clearcoat == 0.0) {
+ /* Dielectric case. */
+ result = closure_eval(diffuse_data, reflection_data);
}
-
- {
- vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb);
- out_emission_radiance *= emission_strength;
- result.radiance += out_emission_radiance;
+ else if (do_diffuse == 0.0 && do_refraction != 0.0 && do_clearcoat == 0.0) {
+ /* Glass case. */
+ result = closure_eval(reflection_data, refraction_data);
}
-
- result.transmittance = vec3(1.0 - alpha);
- result.radiance *= alpha;
- result.ssr_data.rgb *= alpha;
-# ifdef USE_SSS
- result.sss_albedo *= alpha;
-# endif
+ else {
+ /* Un-optimized case. */
+ result = closure_eval(diffuse_data, reflection_data, clearcoat_data, refraction_data);
+ }
+ result = closure_add(result, closure_eval(emission_data));
+ result = closure_add(result, closure_eval(transparency_data));
}
-
-#else
-/* clang-format off */
-/* Stub principled because it is not compatible with volumetrics. */
-# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, cc, dd, ee, ff, result) (result = CLOSURE_DEFAULT)
-/* clang-format on */
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
index 8a42a131f43..871fa00b3d4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
@@ -1,32 +1,15 @@
-#ifndef VOLUMETRICS
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_refraction, Refraction)
-
-void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
+void node_bsdf_refraction(
+ vec4 color, float roughness, float ior, vec3 N, float weight, out Closure result)
{
- CLOSURE_VARS_DECLARE_1(Refraction);
-
- in_Refraction_0.N = N; /* Normalized during eval. */
- in_Refraction_0.roughness = roughness;
- in_Refraction_0.ior = ior;
-
- CLOSURE_EVAL_FUNCTION_1(node_bsdf_refraction, Refraction);
+ N = safe_normalize(N);
- result = CLOSURE_DEFAULT;
+ ClosureRefraction refraction_data;
+ refraction_data.weight = weight;
+ refraction_data.color = color.rgb;
+ refraction_data.N = N;
+ refraction_data.roughness = roughness;
+ refraction_data.ior = ior;
- out_Refraction_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_0.radiance);
- out_Refraction_0.radiance *= color.rgb;
- /* Simulate 2nd absorption event. */
- out_Refraction_0.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0);
-
- result.radiance = out_Refraction_0.radiance;
-
- /* TODO(@fclem): Try to not use this. */
- result.ssr_normal = normal_encode(mat3(ViewMatrix) * in_Refraction_0.N,
- viewCameraVec(viewPosition));
+ result = closure_eval(refraction_data);
}
-
-#else
-/* Stub refraction because it is not compatible with volumetrics. */
-# define node_bsdf_refraction(a, b, c, d, e) (e = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
index fb64e424c6c..180e0fd1940 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
void separate_hsv(vec4 col, out float h, out float s, out float v)
{
vec4 hsv;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
index f0f2f79c60e..d791f067821 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
@@ -1,29 +1,6 @@
-#ifndef VOLUMETRICS
-
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_shader_to_rgba, Glossy)
void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
{
- vec4 spec_accum = vec4(0.0);
- if (ssrToggle && FLAG_TEST(cl.flag, CLOSURE_SSR_FLAG)) {
- CLOSURE_VARS_DECLARE_1(Glossy);
-
- vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec(viewPosition));
- vec3 N = transform_direction(ViewMatrixInverse, vN);
-
- in_Glossy_0.N = N; /* Normalized during eval. */
- in_Glossy_0.roughness = cl.ssr_data.a;
-
- CLOSURE_EVAL_FUNCTION_1(node_shader_to_rgba, Glossy);
-
- spec_accum.rgb = out_Glossy_0.radiance;
- }
-
- outalpha = saturate(1.0 - avg(cl.transmittance));
- outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
-
-# ifdef USE_SSS
- outcol.rgb += cl.sss_irradiance.rgb * cl.sss_albedo;
-# endif
+ outcol = closure_to_rgba(cl);
+ outalpha = outcol.a;
}
-#endif /* VOLUMETRICS */
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
index 20b634aa801..c560dd01c4f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
@@ -1,6 +1,3 @@
-#ifndef VOLUMETRICS
-
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_subsurface_scattering, Diffuse)
void node_subsurface_scattering(vec4 color,
float scale,
@@ -8,25 +5,18 @@ void node_subsurface_scattering(vec4 color,
float ior,
float anisotropy,
vec3 N,
- float sss_id,
+ float weight,
+ float do_sss,
out Closure result)
{
- CLOSURE_VARS_DECLARE_1(Diffuse);
-
- in_Diffuse_0.N = N; /* Normalized during eval. */
- in_Diffuse_0.albedo = color.rgb;
-
- CLOSURE_EVAL_FUNCTION_1(node_subsurface_scattering, Diffuse);
+ N = safe_normalize(N);
- result = CLOSURE_DEFAULT;
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = weight;
+ diffuse_data.color = color.rgb;
+ diffuse_data.N = N;
+ diffuse_data.sss_radius = radius * scale;
+ diffuse_data.sss_id = uint(do_sss);
- closure_load_sss_data(scale, out_Diffuse_0.radiance, color.rgb, int(sss_id), result);
-
- /* TODO(@fclem): Try to not use this. */
- closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
+ result = closure_eval(diffuse_data);
}
-
-#else
-/* Stub subsurface scattering because it is not compatible with volumetrics. */
-# define node_subsurface_scattering(a, b, c, d, e, f, g, h) (h = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl
index ff2dbc7ead3..4e4bf759ec9 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl
@@ -18,8 +18,8 @@ void node_tangentmap(vec4 attr_tangent, out vec3 tangent)
tangent = normalize(attr_tangent.xyz);
}
-void node_tangent(vec3 N, vec3 orco, mat4 objmat, out vec3 T)
+void node_tangent(vec3 orco, out vec3 T)
{
- T = (objmat * vec4(orco, 0.0)).xyz;
- T = cross(N, normalize(cross(T, N)));
+ T = transform_direction(ModelMatrix, orco);
+ T = cross(g_data.N, normalize(cross(T, g_data.N)));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
index e252e5ba726..edc2fa32177 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
@@ -1,3 +1,6 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+
vec2 calc_brick_texture(vec3 p,
float mortar_size,
float mortar_smooth,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
index 434e07e7b86..89091316823 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
@@ -1,19 +1,5 @@
-void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec)
-{
-#ifdef MESH_SHADER
- worldvec = worldPosition;
-#else
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogeneous = (ProjectionMatrixInverse * v);
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
- vec3 co = co_homogeneous.xyz / co_homogeneous.w;
-# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- worldvec = mat3(ViewMatrixInverse) * co;
-# else
- worldvec = mat3(ModelMatrixInverse) * (mat3(ViewMatrixInverse) * co);
-# endif
-#endif
-}
void node_tex_environment_equirectangular(vec3 co, out vec3 uv)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
index 586385b7e86..1552a2facc3 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
@@ -1,3 +1,6 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
+
/* 1D Musgrave fBm
*
* H: fractal increment parameter
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
index 5745f11ede4..c90b2211dcf 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
@@ -1,3 +1,7 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_fractal_noise.glsl)
+
/* The following offset functions generate random offsets to be added to texture
* coordinates to act as a seed since the noise functions don't have seed values.
* A seed value is needed for generating distortion textures and color outputs.
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
index c8219848e29..dd12b602edf 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
@@ -1,3 +1,6 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
/*
* Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez.
*
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
index 070f42a5e30..eed98232d0b 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
@@ -1,3 +1,7 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_fractal_noise.glsl)
+
float calc_wave(vec3 p,
float distortion,
float detail,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
index b11d13a0413..030b58f0736 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+
/* White Noise */
void node_white_noise_1d(vec3 vector, float w, out float value, out vec4 color)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl
index a8ef9687b0a..a3666164cf7 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl
@@ -1,38 +1,5 @@
-vec3 mtex_2d_mapping(vec3 vec)
-{
- return vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
-}
-
-void generated_from_orco(vec3 orco, out vec3 generated)
-{
-#ifdef VOLUMETRICS
-# ifdef MESH_SHADER
- generated = volumeObjectLocalCoord;
-# else
- generated = worldPosition;
-# endif
-#else
- generated = orco;
-#endif
-}
-void generated_texco(vec3 I, vec3 attr_orco, out vec3 generated)
-{
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogeneous = (ProjectionMatrixInverse * v);
- vec4 co = vec4(co_homogeneous.xyz / co_homogeneous.w, 0.0);
- co.xyz = normalize(co.xyz);
-#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- generated = (ViewMatrixInverse * co).xyz;
-#else
- generated_from_orco(attr_orco, generated);
-#endif
-}
-
-void node_tex_coord(vec3 I,
- vec3 wN,
- mat4 obmatinv,
- vec4 camerafac,
+void node_tex_coord(mat4 obmatinv,
vec3 attr_orco,
vec3 attr_uv,
out vec3 generated,
@@ -44,49 +11,10 @@ void node_tex_coord(vec3 I,
out vec3 reflection)
{
generated = attr_orco;
- normal = normalize(normal_world_to_object(wN));
+ normal = normal_world_to_object(g_data.N);
uv = attr_uv;
- object = (obmatinv * (ViewMatrixInverse * vec4(I, 1.0))).xyz;
- camera = vec3(I.xy, -I.z);
- vec4 projvec = ProjectionMatrix * vec4(I, 1.0);
- window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
- reflection = -reflect(cameraVec(worldPosition), normalize(wN));
-}
-
-void node_tex_coord_background(vec3 I,
- vec3 N,
- mat4 obmatinv,
- vec4 camerafac,
- vec3 attr_orco,
- vec3 attr_uv,
- out vec3 generated,
- out vec3 normal,
- out vec3 uv,
- out vec3 object,
- out vec3 camera,
- out vec3 window,
- out vec3 reflection)
-{
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogeneous = (ProjectionMatrixInverse * v);
-
- vec4 co = vec4(co_homogeneous.xyz / co_homogeneous.w, 0.0);
-
- co = normalize(co);
-
- vec3 coords = (ViewMatrixInverse * co).xyz;
-
- generated = coords;
- normal = -coords;
- uv = vec3(attr_uv.xy, 0.0);
- object = (obmatinv * vec4(coords, 1.0)).xyz;
-
- camera = vec3(co.xy, -co.z);
- window = vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0);
-
- reflection = -coords;
+ object = transform_point((obmatinv[3][3] == 0.0) ? ModelMatrixInverse : obmatinv, g_data.P);
+ camera = coordinate_camera(g_data.P);
+ window = coordinate_screen(g_data.P);
+ reflection = coordinate_reflect(g_data.P, g_data.N);
}
-
-#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER))
-# define node_tex_coord node_tex_coord_background
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl
index bbfc99ccc73..ae7d4fc5631 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl
@@ -1,9 +1,15 @@
-#ifndef VOLUMETRICS
-void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
+
+void node_bsdf_toon(
+ vec4 color, float size, float tsmooth, vec3 N, float weight, out Closure result)
{
- node_bsdf_diffuse(color, 0.0, N, result);
+ N = safe_normalize(N);
+
+ /* Fallback to diffuse. */
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = weight;
+ diffuse_data.color = color.rgb;
+ diffuse_data.N = N;
+ diffuse_data.sss_id = 0u;
+
+ result = closure_eval(diffuse_data);
}
-#else
-/* Stub toon because it is not compatible with volumetrics. */
-# define node_bsdf_toon(a, b, c, d, e) (e = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
index 80bd3941b22..0cc162f42f5 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
@@ -1,21 +1,12 @@
-#ifndef VOLUMETRICS
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_translucent, Translucent)
-
-void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
+void node_bsdf_translucent(vec4 color, vec3 N, float weight, out Closure result)
{
- CLOSURE_VARS_DECLARE_1(Translucent);
-
- in_Translucent_0.N = -N; /* Normalized during eval. */
+ N = safe_normalize(N);
- CLOSURE_EVAL_FUNCTION_1(node_bsdf_translucent, Translucent);
+ ClosureTranslucent translucent_data;
+ translucent_data.weight = weight;
+ translucent_data.color = color.rgb;
+ translucent_data.N = -N;
- result = CLOSURE_DEFAULT;
- closure_load_ssr_data(vec3(0.0), 0.0, -in_Translucent_0.N, -1.0, result);
- result.radiance = render_pass_diffuse_mask(color.rgb, out_Translucent_0.radiance * color.rgb);
+ result = closure_eval(translucent_data);
}
-
-#else
-/* Stub translucent because it is not compatible with volumetrics. */
-# define node_bsdf_translucent(a, b, c) (c = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl
index 9040f62bd3f..c650f10b6e4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl
@@ -1,11 +1,10 @@
-#ifndef VOLUMETRICS
-void node_bsdf_transparent(vec4 color, out Closure result)
+
+void node_bsdf_transparent(vec4 color, float weight, out Closure result)
{
- result = CLOSURE_DEFAULT;
- result.radiance = vec3(0.0);
- result.transmittance = abs(color.rgb);
+ ClosureTransparency transparency_data;
+ transparency_data.weight = weight;
+ transparency_data.transmittance = color.rgb;
+ transparency_data.holdout = 0.0;
+
+ result = closure_eval(transparency_data);
}
-#else
-/* Stub transparent because it is not compatible with volumetrics. */
-# define node_bsdf_transparent(a, b) (b = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl
index 4b5ed172081..0ff074bc04f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl
@@ -1,30 +1,22 @@
-void node_vector_displacement_tangent(vec4 vector,
- float midlevel,
- float scale,
- vec4 tangent,
- vec3 normal,
- mat4 obmat,
- mat4 viewmat,
- out vec3 result)
+void node_vector_displacement_tangent(
+ vec4 vector, float midlevel, float scale, vec4 T, out vec3 result)
{
- /* TODO(fclem): this is broken. revisit latter. */
- vec3 N_object = normalize(((vec4(normal, 0.0) * viewmat) * obmat).xyz);
- vec3 T_object = normalize(((vec4(tangent.xyz, 0.0) * viewmat) * obmat).xyz);
- vec3 B_object = tangent.w * normalize(cross(N_object, T_object));
+ vec3 oN = normalize(normal_world_to_object(g_data.N));
+ vec3 oT = normalize(normal_world_to_object(T.xyz));
+ vec3 oB = T.w * normalize(cross(oN, oT));
- vec3 offset = (vector.xyz - vec3(midlevel)) * scale;
- result = offset.x * T_object + offset.y * N_object + offset.z * B_object;
- result = (obmat * vec4(result, 0.0)).xyz;
+ result = (vector.xyz - midlevel) * scale;
+ result = result.x * oT + result.y * oN + result.z * oB;
+ result = transform_point(ModelMatrix, result);
}
-void node_vector_displacement_object(
- vec4 vector, float midlevel, float scale, mat4 obmat, out vec3 result)
+void node_vector_displacement_object(vec4 vector, float midlevel, float scale, out vec3 result)
{
- result = (vector.xyz - vec3(midlevel)) * scale;
- result = (obmat * vec4(result, 0.0)).xyz;
+ result = (vector.xyz - midlevel) * scale;
+ result = transform_point(ModelMatrix, result);
}
void node_vector_displacement_world(vec4 vector, float midlevel, float scale, out vec3 result)
{
- result = (vector.xyz - vec3(midlevel)) * scale;
+ result = (vector.xyz - midlevel) * scale;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
index 4ad5d4232de..8f6bf17f195 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
void vector_math_add(vec3 a, vec3 b, vec3 c, float scale, out vec3 outVector, out float outValue)
{
outVector = a + b;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl
index 41ad16cce0b..ff0fb1c0418 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
vec3 rotate_around_axis(vec3 p, vec3 axis, float angle)
{
float costheta = cos(angle);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl
index 989f18b881a..97726bfe66f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl
@@ -1,9 +1,14 @@
-#ifndef VOLUMETRICS
-void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
+
+void node_bsdf_velvet(vec4 color, float roughness, vec3 N, float weight, out Closure result)
{
- node_bsdf_diffuse(color, 0.0, N, result);
+ N = safe_normalize(N);
+
+ /* Fallback to diffuse. */
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = weight;
+ diffuse_data.color = color.rgb;
+ diffuse_data.N = N;
+ diffuse_data.sss_id = 0u;
+
+ result = closure_eval(diffuse_data);
}
-#else
-/* Stub velvet because it is not compatible with volumetrics. */
-# define node_bsdf_velvet(a, b, c, d) (d = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl
index e6c0880cd07..8fd2e179187 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl
@@ -1,8 +1,9 @@
-void node_volume_absorption(vec4 color, float density, out Closure result)
+
+void node_volume_absorption(vec4 color, float density, float weight, out Closure result)
{
-#ifdef VOLUMETRICS
- result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0);
-#else
- result = CLOSURE_DEFAULT;
-#endif
+ ClosureVolumeAbsorption volume_absorption_data;
+ volume_absorption_data.weight = weight;
+ volume_absorption_data.absorption = (1.0 - color.rgb) * density;
+
+ result = closure_eval(volume_absorption_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
index e6d7b9d3721..464cf5227b4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
@@ -4,14 +4,8 @@ uniform vec3 volumeColor = vec3(1.0);
uniform vec2 volumeTemperature = vec2(0.0);
/* Generic volume attribute. */
-void node_attribute_volume(sampler3D tex, mat4 transform, out vec3 outvec)
+void node_attribute_volume(sampler3D tex, mat4 transform, vec3 cos, out vec3 outvec)
{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
-
/* Optional per-grid transform. */
if (transform[3][3] != 0.0) {
cos = (transform * vec4(cos, 1.0)).xyz;
@@ -21,14 +15,8 @@ void node_attribute_volume(sampler3D tex, mat4 transform, out vec3 outvec)
}
/* Special color attribute for smoke. */
-void node_attribute_volume_color(sampler3D tex, mat4 transform, out vec3 outvec)
+void node_attribute_volume_color(sampler3D tex, mat4 transform, vec3 cos, out vec3 outvec)
{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
-
/* Optional per-grid transform. */
if (transform[3][3] != 0.0) {
cos = (transform * vec4(cos, 1.0)).xyz;
@@ -44,14 +32,8 @@ void node_attribute_volume_color(sampler3D tex, mat4 transform, out vec3 outvec)
}
/* Special temperature attribute for smoke. */
-void node_attribute_volume_temperature(sampler3D tex, mat4 transform, out float outf)
+void node_attribute_volume_temperature(sampler3D tex, mat4 transform, vec3 cos, out float outf)
{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
-
/* Optional per-grid transform. */
if (transform[3][3] != 0.0) {
cos = (transform * vec4(cos, 1.0)).xyz;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
index 884d5415c51..1127c34b3ac 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_blackbody.glsl)
+
void node_volume_principled(vec4 color,
float density,
float anisotropy,
@@ -7,6 +9,7 @@ void node_volume_principled(vec4 color,
float blackbody_intensity,
vec4 blackbody_tint,
float temperature,
+ float weight,
float density_attribute,
vec4 color_attribute,
float temperature_attribute,
@@ -14,7 +17,6 @@ void node_volume_principled(vec4 color,
float layer,
out Closure result)
{
-#ifdef VOLUMETRICS
vec3 absorption_coeff = vec3(0.0);
vec3 scatter_coeff = vec3(0.0);
vec3 emission_coeff = vec3(0.0);
@@ -60,8 +62,18 @@ void node_volume_principled(vec4 color,
}
}
- result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy);
-#else
- result = CLOSURE_DEFAULT;
-#endif
+ ClosureVolumeScatter volume_scatter_data;
+ volume_scatter_data.weight = weight;
+ volume_scatter_data.scattering = scatter_coeff;
+ volume_scatter_data.anisotropy = anisotropy;
+
+ ClosureVolumeAbsorption volume_absorption_data;
+ volume_absorption_data.weight = weight;
+ volume_absorption_data.absorption = absorption_coeff;
+
+ ClosureEmission emission_data;
+ emission_data.weight = weight;
+ emission_data.emission = emission_coeff;
+
+ result = closure_eval(volume_scatter_data, volume_absorption_data, emission_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl
index 02c54658be5..f01ead3618f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl
@@ -1,8 +1,11 @@
-void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
+
+void node_volume_scatter(
+ vec4 color, float density, float anisotropy, float weight, out Closure result)
{
-#ifdef VOLUMETRICS
- result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
-#else
- result = CLOSURE_DEFAULT;
-#endif
+ ClosureVolumeScatter volume_scatter_data;
+ volume_scatter_data.weight = weight;
+ volume_scatter_data.scattering = color.rgb * density;
+ volume_scatter_data.anisotropy = anisotropy;
+
+ result = closure_eval(volume_scatter_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl
index e2789e046e1..0c02dab3ae4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl
@@ -1,20 +1,21 @@
-#ifndef VOLUMETRICS
-void node_wireframe(float size, vec2 barycentric, vec3 barycentric_dist, out float fac)
+
+void node_wireframe(float size, out float fac)
{
- vec3 barys = barycentric.xyy;
- barys.z = 1.0 - barycentric.x - barycentric.y;
+ vec3 barys = g_data.barycentric_coords.xyy;
+ barys.z = 1.0 - barys.x - barys.y;
size *= 0.5;
- vec3 s = step(-size, -barys * barycentric_dist);
+ vec3 s = step(-size, -barys * g_data.barycentric_dists);
fac = max(s.x, max(s.y, s.z));
}
-void node_wireframe_screenspace(float size, vec2 barycentric, out float fac)
+void node_wireframe_screenspace(float size, out float fac)
{
- vec3 barys = barycentric.xyy;
- barys.z = 1.0 - barycentric.x - barycentric.y;
+ vec3 barys = g_data.barycentric_coords.xyy;
+ barys.z = 1.0 - barys.x - barys.y;
+#ifdef GPU_FRAGMENT_SHADER
size *= (1.0 / 3.0);
vec3 dx = dFdx(barys);
vec3 dy = dFdy(barys);
@@ -23,9 +24,7 @@ void node_wireframe_screenspace(float size, vec2 barycentric, out float fac)
vec3 s = step(-deltas * size, -barys);
fac = max(s.x, max(s.y, s.z));
-}
#else
-/* Stub wireframe because it is not compatible with volumetrics. */
-# define node_wireframe(a, b, c, d) (d = 0.0)
-# define node_wireframe_screenspace(a, b, c) (c = 0.0)
+ fac = 1.0;
#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
index 40e46bc250c..5a0aeb2f932 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
@@ -1,25 +1,5 @@
-/* TODO: clean this `ifdef` mess. */
+
void world_normals_get(out vec3 N)
{
-#ifndef VOLUMETRICS
-# ifdef HAIR_SHADER
- vec3 B = normalize(cross(worldNormal, hairTangent));
- float cos_theta;
- if (hairThicknessRes == 1) {
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- /* Random cosine normal distribution on the hair surface. */
- cos_theta = rand.x * 2.0 - 1.0;
- }
- else {
- /* Shade as a cylinder. */
- cos_theta = hairThickTime / hairThickness;
- }
- float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
- N = normalize(worldNormal * sin_theta + B * cos_theta);
-# else
- N = gl_FrontFacing ? worldNormal : -worldNormal;
-# endif
-#else
- generated_from_orco(vec3(0.0), N);
-#endif
+ N = g_data.N;
}