From e48a6fcc6397e5a964f2096d937ac189f07ce999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 1 Sep 2022 14:46:17 +0200 Subject: 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. --- source/blender/draw/CMakeLists.txt | 2 + .../draw/engines/eevee/shaders/shadow_vert.glsl | 4 + .../draw/engines/eevee/shaders/surface_frag.glsl | 4 + .../draw/engines/eevee/shaders/surface_vert.glsl | 4 + .../engines/eevee/shaders/volumetric_frag.glsl | 4 + .../engines/eevee/shaders/volumetric_vert.glsl | 5 + .../eevee_next/shaders/eevee_nodetree_lib.glsl | 23 +++++ source/blender/draw/intern/draw_manager.cc | 25 +++-- source/blender/draw/intern/draw_manager.hh | 52 ++++++++-- source/blender/draw/intern/draw_resource.cc | 109 +++++++++++++++++++++ source/blender/draw/intern/draw_resource.hh | 6 ++ source/blender/draw/intern/draw_shader_shared.h | 24 ++++- .../draw/intern/shaders/common_attribute_lib.glsl | 1 + .../draw/intern/shaders/draw_object_infos_info.hh | 10 +- source/blender/gpu/GPU_material.h | 5 +- source/blender/gpu/intern/gpu_codegen.cc | 10 +- source/blender/gpu/intern/gpu_node_graph.c | 28 +++--- .../material/gpu_shader_material_attribute.glsl | 7 ++ .../nodes/shader/nodes/node_shader_attribute.cc | 16 ++- 19 files changed, 295 insertions(+), 44 deletions(-) create mode 100644 source/blender/draw/intern/draw_resource.cc 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; using ObjectBoundsBuf = StorageArrayBuffer; using ObjectInfosBuf = StorageArrayBuffer; + using ObjectAttributeBuf = StorageArrayBuffer; + /** TODO(fclem): Remove once we get rid of old EEVEE codebase. DRW_RESOURCE_CHUNK_LEN = 512 */ + using ObjectAttributeLegacyBuf = UniformArrayBuffer; 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 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 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 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 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(&data_x) = float4(value, value, value, 1.0f); + return true; + } + + if (type == PROP_FLOAT && array_len <= 4) { + *reinterpret_cast(&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(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(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(&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; -- cgit v1.2.3