diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2022-09-01 15:46:17 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2022-09-02 20:37:15 +0300 |
commit | e48a6fcc6397e5a964f2096d937ac189f07ce999 (patch) | |
tree | 37f98d5dab5c869b7248fc65a35edfc1b618b531 /source | |
parent | 356460f5cf659ef071daa1267ab368b733b4133e (diff) |
DRW-Next: Add uniform attributes (object attributes) support
This replaces the direct shader uniform layout declaration by a linear
search through a global buffer.
Each instance has an attribute offset inside the global buffer and an
attribute count.
This removes any padding and tighly pack all uniform attributes inside
a single buffer.
This would also remove the limit of 8 attribute but it is kept because of
compatibility with the old system that is still used by the old draw
manager.
Diffstat (limited to 'source')
19 files changed, 295 insertions, 44 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 5704c9e6774..f0c0a435e2a 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -227,6 +227,8 @@ set(SRC intern/draw_manager.h intern/draw_manager.hh intern/draw_pass.hh + intern/draw_resource.cc + intern/draw_resource.hh intern/draw_shader_shared.h intern/draw_shader.h intern/draw_subdivision.h diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl index 57d70334651..062a40f35c2 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl @@ -152,3 +152,7 @@ vec4 attr_load_color_post(vec4 attr) { return attr; } +vec4 attr_load_uniform(vec4 attr, const uint attr_hash) +{ + return attr; +} diff --git a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl index 2a212b757c2..f84db01de18 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl @@ -182,3 +182,7 @@ vec4 attr_load_color_post(vec4 attr) { return attr; } +vec4 attr_load_uniform(vec4 attr, const uint attr_hash) +{ + return attr; +} diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl index 4a3a91b8534..54aad7891dc 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl @@ -165,3 +165,7 @@ vec4 attr_load_color_post(vec4 attr) { return attr; } +vec4 attr_load_uniform(vec4 attr, const uint attr_hash) +{ + return attr; +} diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index c6de723ac25..9ed21fc0bf5 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -178,3 +178,7 @@ vec4 attr_load_color_post(vec4 attr) #endif return attr; } +vec4 attr_load_uniform(vec4 attr, const uint attr_hash) +{ + return attr; +} diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl index b3b9c7af19c..2d51fbd9edc 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl @@ -87,3 +87,8 @@ vec4 attr_load_color_post(vec4 attr) { return attr; } + +vec4 attr_load_uniform(vec4 attr, const uint attr_hash) +{ + return attr; +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index 13ad387289d..491e15341f9 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -409,3 +409,26 @@ vec4 attr_load_color_post(vec4 attr) #endif /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Volume Attribute post + * + * TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on + * the engine side. But as of now, the engines are responsible for loading the attributes. + * + * \{ */ + +vec4 attr_load_uniform(vec4 attr, const uint attr_hash) +{ +#if defined(OBINFO_LIB) && defined(OBATTR_LIB) + for (int i = ObjectAttributeStart; i < ObjectAttributeLen; i++) { + if (drw_attrs[i].hash_code == attr_hash) { + return vec4( + drw_attrs[i].data_x, drw_attrs[i].data_y, drw_attrs[i].data_z, drw_attrs[i].data_w); + } + } +#endif + return attr; +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_manager.cc b/source/blender/draw/intern/draw_manager.cc index 8fb2ffb39e8..2841abb53e7 100644 --- a/source/blender/draw/intern/draw_manager.cc +++ b/source/blender/draw/intern/draw_manager.cc @@ -43,6 +43,7 @@ void Manager::begin_sync() memset(infos_buf.data(), 0xF0, resource_len_ * sizeof(*infos_buf.data())); #endif resource_len_ = 0; + attribute_len_ = 0; /* TODO(fclem): Resize buffers if too big, but with an hysteresis threshold. */ object_active = DST.draw_ctx.obact; @@ -58,6 +59,8 @@ void Manager::end_sync() matrix_buf.push_update(); bounds_buf.push_update(); infos_buf.push_update(); + attributes_buf.push_update(); + attributes_buf_legacy.push_update(); debug_bind(); @@ -90,6 +93,16 @@ void Manager::debug_bind() #endif } +void Manager::resource_bind() +{ + GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT); + GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT); + GPU_storagebuf_bind(attributes_buf, DRW_OBJ_ATTR_SLOT); + /* 2 is the hardcoded location of the uniform attr UBO. */ + /* TODO(@fclem): Remove this workaround. */ + GPU_uniformbuf_bind(attributes_buf_legacy, 2); +} + void Manager::submit(PassSimple &pass, View &view) { view.bind(); @@ -101,9 +114,7 @@ void Manager::submit(PassSimple &pass, View &view) pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_); - GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT); - GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT); - // GPU_storagebuf_bind(attribute_buf, DRW_OBJ_ATTR_SLOT); /* TODO */ + resource_bind(); pass.submit(state); @@ -126,9 +137,7 @@ void Manager::submit(PassMain &pass, View &view) pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_, view.visibility_buf_); - GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT); - GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT); - // GPU_storagebuf_bind(attribute_buf, DRW_OBJ_ATTR_SLOT); /* TODO */ + resource_bind(); pass.submit(state); @@ -150,9 +159,7 @@ void Manager::submit(PassSimple &pass) pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_); - GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT); - GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT); - // GPU_storagebuf_bind(attribute_buf, DRW_OBJ_ATTR_SLOT); /* TODO */ + resource_bind(); pass.submit(state); diff --git a/source/blender/draw/intern/draw_manager.hh b/source/blender/draw/intern/draw_manager.hh index 5f110b8bb6b..867b376702c 100644 --- a/source/blender/draw/intern/draw_manager.hh +++ b/source/blender/draw/intern/draw_manager.hh @@ -13,7 +13,9 @@ * \note It is currently work in progress and should replace the old global draw manager. */ +#include "BLI_listbase_wrapper.hh" #include "BLI_sys_types.h" +#include "GPU_material.h" #include "draw_resource.hh" #include "draw_view.hh" @@ -41,6 +43,9 @@ class Manager { using ObjectMatricesBuf = StorageArrayBuffer<ObjectMatrices, 128>; using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>; using ObjectInfosBuf = StorageArrayBuffer<ObjectInfos, 128>; + using ObjectAttributeBuf = StorageArrayBuffer<ObjectAttribute, 128>; + /** TODO(fclem): Remove once we get rid of old EEVEE codebase. DRW_RESOURCE_CHUNK_LEN = 512 */ + using ObjectAttributeLegacyBuf = UniformArrayBuffer<float4, 8 * 512>; public: struct SubmitDebugOutput { @@ -67,14 +72,25 @@ class Manager { ObjectBoundsBuf bounds_buf; ObjectInfosBuf infos_buf; + /** + * Object Attributes are reference by indirection data inside ObjectInfos. + * This is because attribute list is arbitrary. + */ + ObjectAttributeBuf attributes_buf; + /** TODO(fclem): Remove once we get rid of old EEVEE codebase. Only here to satisfy bindings. */ + ObjectAttributeLegacyBuf attributes_buf_legacy; + /** List of textures coming from Image data-blocks. They need to be refcounted in order to avoid * beeing freed in another thread. */ Vector<GPUTexture *> acquired_textures; private: + /** Number of resource handle recorded. */ uint resource_len_ = 0; - Object *object = nullptr; + /** Number of object attribute recorded. */ + uint attribute_len_ = 0; + Object *object = nullptr; Object *object_active = nullptr; public: @@ -104,7 +120,7 @@ class Manager { * Populate additional per resource data on demand. */ void extract_object_attributes(ResourceHandle handle, - Object &object, + const ObjectRef &ref, Span<GPUMaterial *> materials); /** @@ -145,6 +161,7 @@ class Manager { void end_sync(); void debug_bind(); + void resource_bind(); }; inline ResourceHandle Manager::resource_handle(const ObjectRef ref) @@ -175,13 +192,34 @@ inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix, } inline void Manager::extract_object_attributes(ResourceHandle handle, - Object &object, + const ObjectRef &ref, Span<GPUMaterial *> materials) { - /* TODO */ - (void)handle; - (void)object; - (void)materials; + ObjectInfos &infos = infos_buf.get_or_resize(handle.resource_index()); + infos.object_attrs_offset = attribute_len_; + + /* Simple cache solution to avoid duplicates. */ + Vector<uint32_t, 4> hash_cache; + + for (const GPUMaterial *mat : materials) { + const GPUUniformAttrList *attr_list = GPU_material_uniform_attributes(mat); + if (attr_list == nullptr) { + continue; + } + + LISTBASE_FOREACH (const GPUUniformAttr *, attr, &attr_list->list) { + /** WATCH: Linear Search. Avoid duplicate attributes across materials. */ + if ((mat != materials.first()) && (hash_cache.first_index_of_try(attr->hash_code) != -1)) { + /* Attribute has already been added to the attribute buffer by another material. */ + continue; + } + hash_cache.append(attr->hash_code); + if (attributes_buf.get_or_resize(attribute_len_).sync(ref, *attr)) { + infos.object_attrs_len++; + attribute_len_++; + } + } + } } } // namespace blender::draw diff --git a/source/blender/draw/intern/draw_resource.cc b/source/blender/draw/intern/draw_resource.cc new file mode 100644 index 00000000000..689df4edb31 --- /dev/null +++ b/source/blender/draw/intern/draw_resource.cc @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. */ + +/** \file + * \ingroup draw + */ + +#include "DNA_particle_types.h" +#include "RNA_access.h" +#include "RNA_path.h" +#include "RNA_types.h" + +#include "draw_handle.hh" +#include "draw_manager.hh" +#include "draw_shader_shared.h" + +/* -------------------------------------------------------------------- */ +/** \name ObjectAttributes + * \{ */ + +/** + * Extract object attribute from RNA property. + * Returns true if the attribute was correctly extracted. + * This function mirrors lookup_property in cycles/blender/blender_object.cpp + */ +bool ObjectAttribute::id_property_lookup(ID *id, const char *name) +{ + PointerRNA ptr, id_ptr; + PropertyRNA *prop; + + if (id == nullptr) { + return false; + } + + RNA_id_pointer_create(id, &id_ptr); + + if (!RNA_path_resolve(&id_ptr, name, &ptr, &prop)) { + return false; + } + + if (prop == nullptr) { + return false; + } + + PropertyType type = RNA_property_type(prop); + int array_len = RNA_property_array_length(&ptr, prop); + + if (array_len == 0) { + float value; + + if (type == PROP_FLOAT) { + value = RNA_property_float_get(&ptr, prop); + } + else if (type == PROP_INT) { + value = RNA_property_int_get(&ptr, prop); + } + else { + return false; + } + + *reinterpret_cast<float4 *>(&data_x) = float4(value, value, value, 1.0f); + return true; + } + + if (type == PROP_FLOAT && array_len <= 4) { + *reinterpret_cast<float4 *>(&data_x) = float4(0.0f, 0.0f, 0.0f, 1.0f); + RNA_property_float_get_array(&ptr, prop, &data_x); + return true; + } + return false; +} + +/** + * Go through all possible source of the given object uniform attribute. + * Returns true if the attribute was correctly filled. + * This function mirrors lookup_instance_property in cycles/blender/blender_object.cpp + */ +bool ObjectAttribute::sync(const blender::draw::ObjectRef &ref, const GPUUniformAttr &attr) +{ + hash_code = attr.hash_code; + + /* If requesting instance data, check the parent particle system and object. */ + if (attr.use_dupli) { + if ((ref.dupli_object != nullptr) && (ref.dupli_object->particle_system != nullptr)) { + ParticleSettings *settings = ref.dupli_object->particle_system->part; + if (this->id_property_lookup((ID *)settings, attr.name_id_prop) || + this->id_property_lookup((ID *)settings, attr.name)) { + return true; + } + } + if (this->id_property_lookup((ID *)ref.dupli_parent, attr.name_id_prop) || + this->id_property_lookup((ID *)ref.dupli_parent, attr.name)) { + return true; + } + } + + /* Check the object and mesh. */ + if (ref.object != nullptr) { + if (this->id_property_lookup((ID *)ref.object, attr.name_id_prop) || + this->id_property_lookup((ID *)ref.object, attr.name) || + this->id_property_lookup((ID *)ref.object->data, attr.name_id_prop) || + this->id_property_lookup((ID *)ref.object->data, attr.name)) { + return true; + } + } + return false; +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_resource.hh b/source/blender/draw/intern/draw_resource.hh index 503833e8a6d..22ee43592a9 100644 --- a/source/blender/draw/intern/draw_resource.hh +++ b/source/blender/draw/intern/draw_resource.hh @@ -59,11 +59,17 @@ ENUM_OPERATORS(eObjectInfoFlag, OBJECT_NEGATIVE_SCALE) inline void ObjectInfos::sync() { + object_attrs_len = 0; + object_attrs_offset = 0; + flag = eObjectInfoFlag::OBJECT_NO_INFO; } inline void ObjectInfos::sync(const blender::draw::ObjectRef ref, bool is_active_object) { + object_attrs_len = 0; + object_attrs_offset = 0; + color = ref.object->color; index = ref.object->index; SET_FLAG_FROM_TEST(flag, is_active_object, eObjectInfoFlag::OBJECT_ACTIVE); diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index 00d54311548..d43bfe6b159 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -13,6 +13,7 @@ typedef struct ObjectInfos ObjectInfos; typedef struct ObjectBounds ObjectBounds; typedef struct VolumeInfos VolumeInfos; typedef struct CurvesInfos CurvesInfos; +typedef struct ObjectAttribute ObjectAttribute; typedef struct DrawCommand DrawCommand; typedef struct DispatchCommand DispatchCommand; typedef struct DRWDebugPrintBuffer DRWDebugPrintBuffer; @@ -22,6 +23,8 @@ typedef struct DRWDebugDrawBuffer DRWDebugDrawBuffer; # ifdef __cplusplus /* C++ only forward declarations. */ struct Object; +struct ID; +struct GPUUniformAttr; namespace blender::draw { @@ -130,9 +133,9 @@ struct ObjectInfos { #else /** Uploaded as center + size. Converted to mul+bias to local coord. */ float3 orco_add; - float _pad0; + uint object_attrs_offset; float3 orco_mul; - float _pad1; + uint object_attrs_len; float4 color; uint index; @@ -193,6 +196,23 @@ struct CurvesInfos { }; BLI_STATIC_ASSERT_ALIGN(CurvesInfos, 16) +#pragma pack(push, 4) +struct ObjectAttribute { + /* Workaround the padding cost from alignment requirements. + * (see GL spec : 7.6.2.2 Standard Uniform Block Layout) */ + float data_x, data_y, data_z, data_w; + uint hash_code; + +#if !defined(GPU_SHADER) && defined(__cplusplus) + bool sync(const blender::draw::ObjectRef &ref, const GPUUniformAttr &attr); + bool id_property_lookup(ID *id, const char *name); +#endif +}; +#pragma pack(pop) +/** \note we only align to 4 bytes and fetch data manually so make sure + * C++ compiler gives us the same size. */ +BLI_STATIC_ASSERT_ALIGN(ObjectAttribute, 20) + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/draw/intern/shaders/common_attribute_lib.glsl b/source/blender/draw/intern/shaders/common_attribute_lib.glsl index ce5e49c7f63..6b5b6fcc846 100644 --- a/source/blender/draw/intern/shaders/common_attribute_lib.glsl +++ b/source/blender/draw/intern/shaders/common_attribute_lib.glsl @@ -25,3 +25,4 @@ float attr_load_float(sampler3D tex); float attr_load_temperature_post(float attr); vec4 attr_load_color_post(vec4 attr); +vec4 attr_load_uniform(vec4 attr, const uint attr_hash); diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh index 2ec40ab76e3..31fee018fbc 100644 --- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh +++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh @@ -25,4 +25,12 @@ GPU_SHADER_CREATE_INFO(draw_object_infos_new) .define("OrcoTexCoFactors", "(drw_infos[resource_id].orco_mul_bias)") .define("ObjectInfo", "(drw_infos[resource_id].infos)") .define("ObjectColor", "(drw_infos[resource_id].color)") - .storage_buf(DRW_OBJ_INFOS_SLOT, Qualifier::READ, "ObjectInfos", "drw_infos[]");
\ No newline at end of file + .storage_buf(DRW_OBJ_INFOS_SLOT, Qualifier::READ, "ObjectInfos", "drw_infos[]"); + +/** \note Requires draw_object_infos_new. */ +GPU_SHADER_CREATE_INFO(draw_object_attribute_new) + .define("OBATTR_LIB") + .define("ObjectAttributeStart", "(drw_infos[resource_id].orco_mul_bias[0].w)") + .define("ObjectAttributeLen", "(drw_infos[resource_id].orco_mul_bias[1].w)") + .storage_buf(DRW_OBJ_ATTR_SLOT, Qualifier::READ, "ObjectAttribute", "drw_attrs[]") + .additional_info("draw_object_infos_new"); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 042979b3a86..023221543ec 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -149,7 +149,10 @@ GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat, eCustomDataType type, const char *name, eGPUDefaultValue default_value); -GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli); +GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, + const char *name, + bool use_dupli, + uint32_t *r_hash); GPUNodeLink *GPU_image(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser, diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index d58ede4ccd8..f774f33e03d 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -199,8 +199,7 @@ static std::ostream &operator<<(std::ostream &stream, const GPUOutput *output) } /* Trick type to change overload and keep a somewhat nice syntax. */ -struct GPUConstant : public GPUInput { -}; +struct GPUConstant : public GPUInput {}; /* Print data constructor (i.e: vec2(1.0f, 1.0f)). */ static std::ostream &operator<<(std::ostream &stream, const GPUConstant *input) @@ -208,9 +207,10 @@ 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]); + /* Use uint representation to allow exact same bit pattern even if NaN. This is because we can + * pass UINTs as floats for constants. */ + const uint32_t *uint_vec = reinterpret_cast<const uint32_t *>(input->vec); + SNPRINTF(formated_float, "uintBitsToFloat(%uu)", uint_vec[i]); stream << formated_float; if (i < input->type - 1) { stream << ", "; diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 4d391ff9063..f82af7538b5 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -320,20 +320,7 @@ void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph) LISTBASE_FOREACH (GPUUniformAttr *, attr, &attrs->list) { attr->id = next_id++; - - attr->hash_code = BLI_ghashutil_strhash_p(attr->name); - - if (attr->use_dupli) { - attr->hash_code ^= BLI_ghashutil_uinthash(attr->id); - } - - attrs->hash_code ^= attr->hash_code; - - { - char attr_name_esc[sizeof(attr->name) * 2]; - BLI_str_escape(attr_name_esc, attr->name, sizeof(attr_name_esc)); - SNPRINTF(attr->name_id_prop, "[\"%s\"]", attr_name_esc); - } + attrs->hash_code ^= BLI_ghashutil_uinthash(attr->hash_code + (1 << (attr->id + 1))); } } @@ -428,7 +415,13 @@ static GPUUniformAttr *gpu_node_graph_add_uniform_attribute(GPUNodeGraph *graph, if (attr == NULL && attrs->count < GPU_MAX_UNIFORM_ATTR) { attr = MEM_callocN(sizeof(*attr), __func__); STRNCPY(attr->name, name); + { + char attr_name_esc[sizeof(attr->name) * 2]; + BLI_str_escape(attr_name_esc, attr->name, sizeof(attr_name_esc)); + SNPRINTF(attr->name_id_prop, "[\"%s\"]", attr_name_esc); + } attr->use_dupli = use_dupli; + attr->hash_code = BLI_ghashutil_strhash_p(attr->name) << 1 | (attr->use_dupli ? 0 : 1); attr->id = -1; BLI_addtail(&attrs->list, attr); attrs->count++; @@ -532,16 +525,21 @@ GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat, return link; } -GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli) +GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, + const char *name, + bool use_dupli, + uint32_t *r_hash) { GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUUniformAttr *attr = gpu_node_graph_add_uniform_attribute(graph, name, use_dupli); /* Dummy fallback if out of slots. */ if (attr == NULL) { + *r_hash = 0; static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f}; return GPU_constant(zero_data); } + *r_hash = attr->hash_code; GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_UNIFORM_ATTR; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl index af4a511d627..bacf089deb1 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl @@ -22,6 +22,13 @@ void node_attribute_flame(vec4 attr, out float out_attr) out_attr = attr.x; } +void node_attribute_uniform(vec4 attr, const float attr_hash, out vec4 out_attr) +{ + /* Temporary solution to support both old UBO attribs and new SSBO loading. + * Old UBO load is already done through `attr` and will just be passed through. */ + out_attr = attr_load_uniform(attr, floatBitsToUint(attr_hash)); +} + void node_attribute( vec4 attr, out vec4 outcol, out vec3 outvec, out float outf, out float outalpha) { diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.cc b/source/blender/nodes/shader/nodes/node_shader_attribute.cc index d01271c15d3..65d053e6379 100644 --- a/source/blender/nodes/shader/nodes/node_shader_attribute.cc +++ b/source/blender/nodes/shader/nodes/node_shader_attribute.cc @@ -36,6 +36,7 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, { NodeShaderAttribute *attr = static_cast<NodeShaderAttribute *>(node->storage); bool is_varying = attr->type == SHD_ATTRIBUTE_GEOMETRY; + float attr_hash = 0.0f; GPUNodeLink *cd_attr; @@ -43,7 +44,12 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, cd_attr = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->name); } else { - cd_attr = GPU_uniform_attribute(mat, attr->name, attr->type == SHD_ATTRIBUTE_INSTANCER); + cd_attr = GPU_uniform_attribute(mat, + attr->name, + attr->type == SHD_ATTRIBUTE_INSTANCER, + reinterpret_cast<uint32_t *>(&attr_hash)); + + GPU_link(mat, "node_attribute_uniform", cd_attr, GPU_constant(&attr_hash), &cd_attr); } if (STREQ(attr->name, "color")) { @@ -55,9 +61,11 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr); - int i; - LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) { - node_shader_gpu_bump_tex_coord(mat, node, &out[i].link); + if (is_varying) { + int i; + LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) { + node_shader_gpu_bump_tex_coord(mat, node, &out[i].link); + } } return 1; |