diff options
36 files changed, 649 insertions, 22 deletions
diff --git a/intern/cycles/blender/id_map.h b/intern/cycles/blender/id_map.h index e77d2f647bf..5fb17bb0d50 100644 --- a/intern/cycles/blender/id_map.h +++ b/intern/cycles/blender/id_map.h @@ -20,7 +20,7 @@ CCL_NAMESPACE_BEGIN * Utility class to map between Blender datablocks and Cycles data structures, * and keep track of recalc tags from the dependency graph. */ -template<typename K, typename T> class id_map { +template<typename K, typename T, typename Flags = uint> class id_map { public: id_map(Scene *scene_) : scene(scene_) { @@ -63,6 +63,11 @@ template<typename K, typename T> class id_map { b_recalc.insert(id_ptr); } + bool check_recalc(const BL::ID &id) + { + return id.ptr.data && b_recalc.find(id.ptr.data) != b_recalc.end(); + } + bool has_recalc() { return !(b_recalc.empty()); @@ -154,6 +159,7 @@ template<typename K, typename T> class id_map { TMapPair &pair = *jt; if (do_delete && used_set.find(pair.second) == used_set.end()) { + flags.erase(pair.second); scene->delete_node(pair.second); } else { @@ -171,9 +177,33 @@ template<typename K, typename T> class id_map { return b_map; } + bool test_flag(T *data, Flags val) + { + typename map<T *, uint>::iterator it = flags.find(data); + return it != flags.end() && (it->second & (1 << val)) != 0; + } + + void set_flag(T *data, Flags val) + { + flags[data] |= (1 << val); + } + + void clear_flag(T *data, Flags val) + { + typename map<T *, uint>::iterator it = flags.find(data); + if (it != flags.end()) { + it->second &= ~(1 << val); + + if (it->second == 0) { + flags.erase(it); + } + } + } + protected: map<K, T *> b_map; set<T *> used_set; + map<T *, uint> flags; set<void *> b_recalc; Scene *scene; }; diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp index 8a3c1136104..5af1e18a597 100644 --- a/intern/cycles/blender/object.cpp +++ b/intern/cycles/blender/object.cpp @@ -96,6 +96,13 @@ bool BlenderSync::object_is_light(BL::Object &b_ob) return (b_ob_data && b_ob_data.is_a(&RNA_Light)); } +bool BlenderSync::object_is_camera(BL::Object &b_ob) +{ + BL::ID b_ob_data = b_ob.data(); + + return (b_ob_data && b_ob_data.is_a(&RNA_Camera)); +} + void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object) { /* Initialize motion blur for object, detecting if it's enabled and creating motion @@ -400,7 +407,8 @@ bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance std::string real_name; BlenderAttributeType type = blender_attribute_name_split_type(name, &real_name); - if (type != BL::ShaderNodeAttribute::attribute_type_GEOMETRY) { + if (type == BL::ShaderNodeAttribute::attribute_type_OBJECT || + type == BL::ShaderNodeAttribute::attribute_type_INSTANCER) { bool use_instancer = (type == BL::ShaderNodeAttribute::attribute_type_INSTANCER); float4 value = lookup_instance_property(b_instance, real_name, use_instancer); diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index 9505f4ba58f..fd32e7ca1d7 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -22,6 +22,8 @@ #include "util/string.h" #include "util/task.h" +#include "BKE_duplilist.h" + CCL_NAMESPACE_BEGIN typedef map<void *, ShaderInput *> PtrInputMap; @@ -103,6 +105,7 @@ static ImageAlphaType get_image_alpha_type(BL::Image &b_image) static const string_view object_attr_prefix("\x01object:"); static const string_view instancer_attr_prefix("\x01instancer:"); +static const string_view view_layer_attr_prefix("\x01layer:"); static ustring blender_attribute_name_add_type(const string &name, BlenderAttributeType type) { @@ -111,6 +114,8 @@ static ustring blender_attribute_name_add_type(const string &name, BlenderAttrib return ustring::concat(object_attr_prefix, name); case BL::ShaderNodeAttribute::attribute_type_INSTANCER: return ustring::concat(instancer_attr_prefix, name); + case BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER: + return ustring::concat(view_layer_attr_prefix, name); default: return ustring(name); } @@ -130,6 +135,11 @@ BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_r return BL::ShaderNodeAttribute::attribute_type_INSTANCER; } + if (sname.substr(0, view_layer_attr_prefix.size()) == view_layer_attr_prefix) { + *r_real_name = sname.substr(view_layer_attr_prefix.size()); + return BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER; + } + return BL::ShaderNodeAttribute::attribute_type_GEOMETRY; } @@ -1420,6 +1430,89 @@ static void add_nodes(Scene *scene, empty_proxy_map); } +/* Look up and constant fold all references to View Layer attributes. */ +void BlenderSync::resolve_view_layer_attributes(Shader *shader, + ShaderGraph *graph, + BL::Depsgraph &b_depsgraph) +{ + bool updated = false; + + foreach (ShaderNode *node, graph->nodes) { + if (node->is_a(AttributeNode::node_type)) { + AttributeNode *attr_node = static_cast<AttributeNode *>(node); + + std::string real_name; + BlenderAttributeType type = blender_attribute_name_split_type(attr_node->get_attribute(), + &real_name); + + if (type == BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER) { + /* Look up the value. */ + BL::ViewLayer b_layer = b_depsgraph.view_layer_eval(); + BL::Scene b_scene = b_depsgraph.scene_eval(); + float4 value; + + BKE_view_layer_find_rgba_attribute((::Scene *)b_scene.ptr.data, + (::ViewLayer *)b_layer.ptr.data, + real_name.c_str(), + &value.x); + + /* Replace all outgoing links, using appropriate output types. */ + float val_avg = (value.x + value.y + value.z) / 3.0f; + + foreach (ShaderOutput *output, node->outputs) { + float val_float; + float3 val_float3; + + if (output->type() == SocketType::FLOAT) { + val_float = (output->name() == "Alpha") ? value.w : val_avg; + val_float3 = make_float3(val_float); + } + else { + val_float = val_avg; + val_float3 = float4_to_float3(value); + } + + foreach (ShaderInput *sock, output->links) { + if (sock->type() == SocketType::FLOAT) { + sock->set(val_float); + } + else if (SocketType::is_float3(sock->type())) { + sock->set(val_float3); + } + + sock->constant_folded_in = true; + } + + graph->disconnect(output); + } + + /* Clear the attribute name to avoid further attempts to look up. */ + attr_node->set_attribute(ustring()); + updated = true; + } + } + } + + if (updated) { + shader_map.set_flag(shader, SHADER_WITH_LAYER_ATTRS); + } + else { + shader_map.clear_flag(shader, SHADER_WITH_LAYER_ATTRS); + } +} + +bool BlenderSync::scene_attr_needs_recalc(Shader *shader, BL::Depsgraph &b_depsgraph) +{ + if (shader && shader_map.test_flag(shader, SHADER_WITH_LAYER_ATTRS)) { + BL::Scene scene = b_depsgraph.scene_eval(); + + return shader_map.check_recalc(scene) || shader_map.check_recalc(scene.world()) || + shader_map.check_recalc(scene.camera()); + } + + return false; +} + /* Sync Materials */ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) @@ -1438,7 +1531,8 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) Shader *shader; /* test if we need to sync */ - if (shader_map.add_or_update(&shader, b_mat) || update_all) { + if (shader_map.add_or_update(&shader, b_mat) || update_all || + scene_attr_needs_recalc(shader, b_depsgraph)) { ShaderGraph *graph = new ShaderGraph(); shader->name = b_mat.name().c_str(); @@ -1459,6 +1553,8 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) graph->connect(diffuse->output("BSDF"), out->input("Surface")); } + resolve_view_layer_attributes(shader, graph, b_depsgraph); + /* settings */ PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles"); shader->set_use_mis(get_boolean(cmat, "sample_as_light")); @@ -1515,9 +1611,11 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui); + Shader *shader = scene->default_background; + if (world_recalc || update_all || b_world.ptr.data != world_map || - viewport_parameters.shader_modified(new_viewport_parameters)) { - Shader *shader = scene->default_background; + viewport_parameters.shader_modified(new_viewport_parameters) || + scene_attr_needs_recalc(shader, b_depsgraph)) { ShaderGraph *graph = new ShaderGraph(); /* create nodes */ @@ -1615,6 +1713,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, background->set_visibility(visibility); } + resolve_view_layer_attributes(shader, graph, b_depsgraph); + shader->set_graph(graph); shader->tag_update(scene); } @@ -1681,7 +1781,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all) Shader *shader; /* test if we need to sync */ - if (shader_map.add_or_update(&shader, b_light) || update_all) { + if (shader_map.add_or_update(&shader, b_light) || update_all || + scene_attr_needs_recalc(shader, b_depsgraph)) { ShaderGraph *graph = new ShaderGraph(); /* create nodes */ @@ -1702,6 +1803,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all) graph->connect(emission->output("Emission"), out->input("Surface")); } + resolve_view_layer_attributes(shader, graph, b_depsgraph); + shader->set_graph(graph); shader->tag_update(scene); } diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp index 23bc92de022..a69a94614d3 100644 --- a/intern/cycles/blender/sync.cpp +++ b/intern/cycles/blender/sync.cpp @@ -206,6 +206,9 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d } } } + else if (object_is_camera(b_ob)) { + shader_map.set_recalc(b_ob); + } } /* Mesh */ else if (b_id.is_a(&RNA_Mesh)) { @@ -218,6 +221,11 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d if (world_map == b_world.ptr.data) { world_recalc = true; } + shader_map.set_recalc(b_world); + } + /* World */ + else if (b_id.is_a(&RNA_Scene)) { + shader_map.set_recalc(b_id); } /* Volume */ else if (b_id.is_a(&RNA_Volume)) { diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h index ae6c2420e55..fbb17bab0c8 100644 --- a/intern/cycles/blender/sync.h +++ b/intern/cycles/blender/sync.h @@ -120,6 +120,11 @@ class BlenderSync { void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all); void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree); + bool scene_attr_needs_recalc(Shader *shader, BL::Depsgraph &b_depsgraph); + void resolve_view_layer_attributes(Shader *shader, + ShaderGraph *graph, + BL::Depsgraph &b_depsgraph); + /* Object */ Object *sync_object(BL::Depsgraph &b_depsgraph, BL::ViewLayer &b_view_layer, @@ -207,13 +212,16 @@ class BlenderSync { bool object_is_geometry(BObjectInfo &b_ob_info); bool object_can_have_geometry(BL::Object &b_ob); bool object_is_light(BL::Object &b_ob); + bool object_is_camera(BL::Object &b_ob); /* variables */ BL::RenderEngine b_engine; BL::BlendData b_data; BL::Scene b_scene; - id_map<void *, Shader> shader_map; + enum ShaderFlags { SHADER_WITH_LAYER_ATTRS }; + + id_map<void *, Shader, ShaderFlags> shader_map; id_map<ObjectKey, Object> object_map; id_map<void *, Procedural> procedural_map; id_map<GeometryKey, Geometry> geometry_map; diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h index 8a37348377a..44c4df1fc2e 100644 --- a/source/blender/blenkernel/BKE_duplilist.h +++ b/source/blender/blenkernel/BKE_duplilist.h @@ -16,6 +16,7 @@ struct ListBase; struct Object; struct ParticleSystem; struct Scene; +struct ViewLayer; struct ViewerPath; struct GeometrySet; @@ -83,6 +84,13 @@ bool BKE_object_dupli_find_rgba_attribute(struct Object *ob, const char *name, float r_value[4]); +/** Look up the RGBA value of a view layer/scene/world shader attribute. + * \return true if the attribute was found; if not, r_value is also set to zero. */ +bool BKE_view_layer_find_rgba_attribute(struct Scene *scene, + struct ViewLayer *layer, + const char *name, + float r_value[4]); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index a56176b7d9b..306e508dc83 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -57,10 +57,12 @@ #include "DEG_depsgraph_query.h" #include "BLI_hash.h" +#include "DNA_world_types.h" #include "NOD_geometry_nodes_log.hh" #include "RNA_access.h" #include "RNA_path.h" +#include "RNA_prototypes.h" #include "RNA_types.h" using blender::Array; @@ -1916,4 +1918,30 @@ bool BKE_object_dupli_find_rgba_attribute( return false; } +bool BKE_view_layer_find_rgba_attribute(struct Scene *scene, + struct ViewLayer *layer, + const char *name, + float r_value[4]) +{ + if (layer) { + PointerRNA layer_ptr; + RNA_pointer_create(&scene->id, &RNA_ViewLayer, layer, &layer_ptr); + + if (find_rna_property_rgba(&layer_ptr, name, r_value)) { + return true; + } + } + + if (find_rna_property_rgba(&scene->id, name, r_value)) { + return true; + } + + if (scene->world && find_rna_property_rgba(&scene->world->id, name, r_value)) { + return true; + } + + copy_v4_fl(r_value, 0.0f); + return false; +} + /** \} */ diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 8005b27c30e..a0bdf70e254 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -106,6 +106,8 @@ void Instance::begin_sync() gpencil_engine_enabled = false; + scene_sync(); + depth_of_field.sync(); motion_blur.sync(); hiz_buffer.sync(); @@ -115,6 +117,21 @@ void Instance::begin_sync() film.sync(); } +void Instance::scene_sync() +{ + SceneHandle &sc_handle = sync.sync_scene(scene); + + sc_handle.reset_recalc_flag(); + + /* This refers specifically to the Scene camera that can be accessed + * via View Layer Attribute nodes, rather than the actual render camera. */ + if (scene->camera != nullptr) { + ObjectHandle &ob_handle = sync.sync_object(scene->camera); + + ob_handle.reset_recalc_flag(); + } +} + void Instance::object_sync(Object *ob) { const bool is_renderable_type = ELEM(ob->type, OB_CURVES, OB_GPENCIL, OB_MESH, OB_LAMP); diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index c8eecbd812d..bc610cd0642 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -162,6 +162,7 @@ class Instance { void render_sample(); void render_read_result(RenderLayer *render_layer, const char *view_name); + void scene_sync(); void mesh_sync(Object *ob, ObjectHandle &ob_handle); void update_eval_members(); diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc index b63002df2e3..d190a1f17a3 100644 --- a/source/blender/draw/engines/eevee_next/eevee_material.cc +++ b/source/blender/draw/engines/eevee_next/eevee_material.cc @@ -187,6 +187,8 @@ MaterialPass MaterialModule::material_pass_get(Object *ob, /* Returned material should be ready to be drawn. */ BLI_assert(GPU_material_status(matpass.gpumat) == GPU_MAT_SUCCESS); + inst_.manager->register_layer_attributes(matpass.gpumat); + if (GPU_material_recalc_flag_get(matpass.gpumat)) { inst_.sampling.reset(); } @@ -217,6 +219,9 @@ MaterialPass MaterialModule::material_pass_get(Object *ob, matpass.sub_pass = &shader_sub->sub(GPU_material_get_name(matpass.gpumat)); matpass.sub_pass->material_set(*inst_.manager, matpass.gpumat); } + else { + matpass.sub_pass = nullptr; + } } return matpass; diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc index f2daba48d7a..08cda6f47cf 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.cc +++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc @@ -68,6 +68,20 @@ WorldHandle &SyncModule::sync_world(::World *world) return eevee_dd; } +SceneHandle &SyncModule::sync_scene(::Scene *scene) +{ + DrawEngineType *owner = (DrawEngineType *)&DRW_engine_viewport_eevee_next_type; + struct DrawData *dd = DRW_drawdata_ensure( + (ID *)scene, owner, sizeof(eevee::SceneHandle), draw_data_init_cb, nullptr); + SceneHandle &eevee_dd = *reinterpret_cast<SceneHandle *>(dd); + + const int recalc_flags = ID_RECALC_ALL; + if ((eevee_dd.recalc & recalc_flags) != 0) { + inst_.sampling.reset(); + } + return eevee_dd; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.hh b/source/blender/draw/engines/eevee_next/eevee_sync.hh index ab883ce44c2..eda0342c4b6 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.hh +++ b/source/blender/draw/engines/eevee_next/eevee_sync.hh @@ -139,6 +139,15 @@ struct WorldHandle : public DrawData { } }; +struct SceneHandle : public DrawData { + void reset_recalc_flag() + { + if (recalc != 0) { + recalc = 0; + } + } +}; + class SyncModule { private: Instance &inst_; @@ -149,6 +158,7 @@ class SyncModule { ObjectHandle &sync_object(Object *ob); WorldHandle &sync_world(::World *world); + SceneHandle &sync_scene(::Scene *scene); void sync_mesh(Object *ob, ObjectHandle &ob_handle, diff --git a/source/blender/draw/engines/eevee_next/eevee_world.cc b/source/blender/draw/engines/eevee_next/eevee_world.cc index 313c0bda42e..37f90570028 100644 --- a/source/blender/draw/engines/eevee_next/eevee_world.cc +++ b/source/blender/draw/engines/eevee_next/eevee_world.cc @@ -87,6 +87,9 @@ void World::sync() default_tree.nodetree_get(bl_world); GPUMaterial *gpumat = inst_.shaders.world_shader_get(bl_world, ntree); + + inst_.manager->register_layer_attributes(gpumat); + inst_.pipelines.world.sync(gpumat); } diff --git a/source/blender/draw/intern/draw_defines.h b/source/blender/draw/intern/draw_defines.h index f5976ddd34e..57035717bd7 100644 --- a/source/blender/draw/intern/draw_defines.h +++ b/source/blender/draw/intern/draw_defines.h @@ -15,6 +15,8 @@ #define DRW_VIEW_CULLING_UBO_SLOT 1 #define DRW_CLIPPING_UBO_SLOT 2 +#define DRW_LAYER_ATTR_UBO_SLOT 3 + #define DRW_RESOURCE_ID_SLOT 11 #define DRW_OBJ_MAT_SLOT 10 #define DRW_OBJ_INFOS_SLOT 9 diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index a56883ce304..b44c1364af9 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -622,6 +622,62 @@ void drw_uniform_attrs_pool_update(GHash *table, } } +GPUUniformBuf *drw_ensure_layer_attribute_buffer() +{ + DRWData *data = DST.vmempool; + + if (data->vlattrs_ubo_ready && data->vlattrs_ubo != NULL) { + return data->vlattrs_ubo; + } + + /* Allocate the buffer data. */ + const int buf_size = DRW_RESOURCE_CHUNK_LEN; + + if (data->vlattrs_buf == NULL) { + data->vlattrs_buf = MEM_calloc_arrayN( + buf_size, sizeof(LayerAttribute), "View Layer Attr Data"); + } + + /* Look up attributes. + * + * Mirrors code in draw_resource.cc and cycles/blender/shader.cpp. + */ + LayerAttribute *buffer = data->vlattrs_buf; + int count = 0; + + LISTBASE_FOREACH (GPULayerAttr *, attr, &data->vlattrs_name_list) { + float value[4]; + + if (BKE_view_layer_find_rgba_attribute( + DST.draw_ctx.scene, DST.draw_ctx.view_layer, attr->name, value)) { + LayerAttribute *item = &buffer[count++]; + + memcpy(item->data, value, sizeof(item->data)); + item->hash_code = attr->hash_code; + + /* Check if the buffer is full just in case. */ + if (count >= buf_size) { + break; + } + } + } + + buffer[0].buffer_length = count; + + /* Update or create the UBO object. */ + if (data->vlattrs_ubo != NULL) { + GPU_uniformbuf_update(data->vlattrs_ubo, buffer); + } + else { + data->vlattrs_ubo = GPU_uniformbuf_create_ex( + sizeof(*buffer) * buf_size, buffer, "View Layer Attributes"); + } + + data->vlattrs_ubo_ready = true; + + return data->vlattrs_ubo; +} + DRWSparseUniformBuf *DRW_uniform_attrs_pool_find_ubo(GHash *table, const struct GPUUniformAttrList *key) { diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 6dfd434d5c7..28abbc6ab71 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -378,6 +378,8 @@ DRWData *DRW_viewport_data_create(void) drw_data->views = BLI_memblock_create(sizeof(DRWView)); drw_data->images = BLI_memblock_create(sizeof(GPUTexture *)); drw_data->obattrs_ubo_pool = DRW_uniform_attrs_pool_new(); + drw_data->vlattrs_name_cache = BLI_ghash_new( + BLI_ghashutil_inthash_p_simple, BLI_ghashutil_intcmp, "View Layer Attribute names"); { uint chunk_len = sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN; drw_data->obmats = BLI_memblock_create_ex(sizeof(DRWObjectMatrix), chunk_len); @@ -413,9 +415,23 @@ static void draw_texture_release(DRWData *drw_data) } } +static void draw_prune_vlattrs(DRWData *drw_data) +{ + drw_data->vlattrs_ubo_ready = false; + + /* Forget known attributes after they are unused for a few frames. */ + LISTBASE_FOREACH_MUTABLE (GPULayerAttr *, attr, &drw_data->vlattrs_name_list) { + if (++attr->users > 10) { + BLI_ghash_remove(drw_data->vlattrs_name_cache, (void *)attr->hash_code, NULL, NULL); + BLI_freelinkN(&drw_data->vlattrs_name_list, attr); + } + } +} + static void drw_viewport_data_reset(DRWData *drw_data) { draw_texture_release(drw_data); + draw_prune_vlattrs(drw_data); BLI_memblock_clear(drw_data->commands, NULL); BLI_memblock_clear(drw_data->commands_small, NULL); @@ -451,6 +467,12 @@ void DRW_viewport_data_free(DRWData *drw_data) BLI_memblock_destroy(drw_data->passes, NULL); BLI_memblock_destroy(drw_data->images, NULL); DRW_uniform_attrs_pool_free(drw_data->obattrs_ubo_pool); + BLI_ghash_free(drw_data->vlattrs_name_cache, NULL, NULL); + BLI_freelistN(&drw_data->vlattrs_name_list); + if (drw_data->vlattrs_ubo) { + GPU_uniformbuf_free(drw_data->vlattrs_ubo); + MEM_freeN(drw_data->vlattrs_buf); + } DRW_instance_data_list_free(drw_data->idatalist); DRW_texture_pool_free(drw_data->texture_pool); for (int i = 0; i < 2; i++) { @@ -811,6 +833,7 @@ static bool id_type_can_have_drawdata(const short id_type) /* has DrawData */ case ID_OB: case ID_WO: + case ID_SCE: return true; /* no DrawData */ diff --git a/source/blender/draw/intern/draw_manager.cc b/source/blender/draw/intern/draw_manager.cc index 169d86b2ea1..c644cadd18c 100644 --- a/source/blender/draw/intern/draw_manager.cc +++ b/source/blender/draw/intern/draw_manager.cc @@ -35,6 +35,7 @@ void Manager::begin_sync() } acquired_textures.clear(); + layer_attributes.clear(); #ifdef DEBUG /* Detect uninitialized data. */ @@ -52,14 +53,46 @@ void Manager::begin_sync() resource_handle(float4x4::identity()); } +void Manager::sync_layer_attributes() +{ + /* Sort the attribute IDs - the shaders use binary search. */ + Vector<uint32_t> id_list; + + id_list.reserve(layer_attributes.size()); + + for (uint32_t id : layer_attributes.keys()) { + id_list.append(id); + } + + std::sort(id_list.begin(), id_list.end()); + + /* Look up the attributes. */ + int count = 0, size = layer_attributes_buf.end() - layer_attributes_buf.begin(); + + for (uint32_t id : id_list) { + if (layer_attributes_buf[count].sync( + DST.draw_ctx.scene, DST.draw_ctx.view_layer, layer_attributes.lookup(id))) { + /* Check if the buffer is full. */ + if (++count == size) { + break; + } + } + } + + layer_attributes_buf[0].buffer_length = count; +} + void Manager::end_sync() { GPU_debug_group_begin("Manager.end_sync"); + sync_layer_attributes(); + matrix_buf.push_update(); bounds_buf.push_update(); infos_buf.push_update(); attributes_buf.push_update(); + layer_attributes_buf.push_update(); attributes_buf_legacy.push_update(); /* Useful for debugging the following resource finalize. But will trigger the drawing of the GPU @@ -100,6 +133,7 @@ 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); + GPU_uniformbuf_bind(layer_attributes_buf, DRW_LAYER_ATTR_UBO_SLOT); /* 2 is the hardcoded location of the uniform attr UBO. */ /* TODO(@fclem): Remove this workaround. */ GPU_uniformbuf_bind(attributes_buf_legacy, 2); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 6b5a2cc4f6f..ce316a31cf9 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -335,6 +335,7 @@ typedef enum { DRW_UNIFORM_BLOCK_OBMATS, DRW_UNIFORM_BLOCK_OBINFOS, DRW_UNIFORM_BLOCK_OBATTRS, + DRW_UNIFORM_BLOCK_VLATTRS, DRW_UNIFORM_RESOURCE_CHUNK, DRW_UNIFORM_RESOURCE_ID, /** Legacy / Fallback */ @@ -527,6 +528,11 @@ typedef struct DRWData { struct GPUUniformBuf **matrices_ubo; struct GPUUniformBuf **obinfos_ubo; struct GHash *obattrs_ubo_pool; + struct GHash *vlattrs_name_cache; + struct ListBase vlattrs_name_list; + struct LayerAttribute *vlattrs_buf; + struct GPUUniformBuf *vlattrs_ubo; + bool vlattrs_ubo_ready; uint ubo_len; /** Per draw-call volume object data. */ void *volume_grids_ubos; /* VolumeUniformBufPool */ @@ -691,6 +697,8 @@ void drw_uniform_attrs_pool_update(struct GHash *table, struct Object *dupli_parent, struct DupliObject *dupli_source); +GPUUniformBuf *drw_ensure_layer_attribute_buffer(); + double *drw_engine_data_cache_time_get(GPUViewport *viewport); void *drw_engine_data_engine_data_create(GPUViewport *viewport, void *engine_type); void *drw_engine_data_engine_data_get(GPUViewport *viewport, void *engine_handle); diff --git a/source/blender/draw/intern/draw_manager.hh b/source/blender/draw/intern/draw_manager.hh index fbd3d28d3f4..0a865179cee 100644 --- a/source/blender/draw/intern/draw_manager.hh +++ b/source/blender/draw/intern/draw_manager.hh @@ -44,6 +44,7 @@ class Manager { using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>; using ObjectInfosBuf = StorageArrayBuffer<ObjectInfos, 128>; using ObjectAttributeBuf = StorageArrayBuffer<ObjectAttribute, 128>; + using LayerAttributeBuf = UniformArrayBuffer<LayerAttribute, 512>; /** * TODO(@fclem): Remove once we get rid of old EEVEE code-base. * `DRW_RESOURCE_CHUNK_LEN = 512`. @@ -87,6 +88,16 @@ class Manager { ObjectAttributeLegacyBuf attributes_buf_legacy; /** + * Table of all View Layer attributes required by shaders, used to populate the buffer below. + */ + Map<uint32_t, GPULayerAttr> layer_attributes; + + /** + * Buffer of layer attribute values, indexed and sorted by the hash. + */ + LayerAttributeBuf layer_attributes_buf; + + /** * List of textures coming from Image data-blocks. * They need to be reference-counted in order to avoid being freed in another thread. */ @@ -131,6 +142,11 @@ class Manager { Span<GPUMaterial *> materials); /** + * Collect necessary View Layer attributes. + */ + void register_layer_attributes(GPUMaterial *material); + + /** * Submit a pass for drawing. All resource reference will be dereferenced and commands will be * sent to GPU. */ @@ -169,6 +185,9 @@ class Manager { void debug_bind(); void resource_bind(); + + private: + void sync_layer_attributes(); }; inline ResourceHandle Manager::resource_handle(const ObjectRef ref) @@ -229,6 +248,19 @@ inline void Manager::extract_object_attributes(ResourceHandle handle, } } +inline void Manager::register_layer_attributes(GPUMaterial *material) +{ + const ListBase *attr_list = GPU_material_layer_attributes(material); + + if (attr_list != nullptr) { + LISTBASE_FOREACH (const GPULayerAttr *, attr, attr_list) { + /** Since layer attributes are global to the whole render pass, + * this only collects a table of their names. */ + layer_attributes.add(attr->hash_code, *attr); + } + } +} + } // namespace blender::draw /* TODO(@fclem): This is for testing. The manager should be passed to the engine through the diff --git a/source/blender/draw/intern/draw_manager_data.cc b/source/blender/draw/intern/draw_manager_data.cc index 06677344132..030b13177f1 100644 --- a/source/blender/draw/intern/draw_manager_data.cc +++ b/source/blender/draw/intern/draw_manager_data.cc @@ -1840,6 +1840,13 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, GPUMaterial *mater grp, loc, DRW_UNIFORM_BLOCK_OBATTRS, uattrs, GPU_SAMPLER_DEFAULT, 0, 1); grp->uniform_attrs = uattrs; } + + if (GPU_material_layer_attributes(material) != NULL) { + int loc = GPU_shader_get_uniform_block_binding(grp->shader, + GPU_LAYER_ATTRIBUTE_UBO_BLOCK_NAME); + drw_shgroup_uniform_create_ex( + grp, loc, DRW_UNIFORM_BLOCK_VLATTRS, nullptr, GPU_SAMPLER_DEFAULT, 0, 1); + } } GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttrFormat attrs[], diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 3627b0fbf10..8b1b35b5f03 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -44,6 +44,7 @@ typedef struct DRWCommandsState { int obmats_loc; int obinfos_loc; int obattrs_loc; + int vlattrs_loc; int baseinst_loc; int chunkid_loc; int resourceid_loc; @@ -682,6 +683,10 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, uni->uniform_attrs); DRW_sparse_uniform_buffer_bind(state->obattrs_ubo, 0, uni->location); break; + case DRW_UNIFORM_BLOCK_VLATTRS: + state->vlattrs_loc = uni->location; + GPU_uniformbuf_bind(drw_ensure_layer_attribute_buffer(), uni->location); + break; case DRW_UNIFORM_RESOURCE_CHUNK: state->chunkid_loc = uni->location; GPU_shader_uniform_int(shgroup->shader, uni->location, 0); @@ -960,6 +965,9 @@ static void draw_call_batching_finish(DRWShadingGroup *shgroup, DRWCommandsState if (state->obattrs_loc != -1) { DRW_sparse_uniform_buffer_unbind(state->obattrs_ubo, state->resource_chunk); } + if (state->vlattrs_loc != -1) { + GPU_uniformbuf_unbind(DST.vmempool->vlattrs_ubo); + } } static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) @@ -970,6 +978,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) .obmats_loc = -1, .obinfos_loc = -1, .obattrs_loc = -1, + .vlattrs_loc = -1, .baseinst_loc = -1, .chunkid_loc = -1, .resourceid_loc = -1, diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 04a9f3fdd2d..8b287e116bc 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -237,6 +237,42 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred) WM_jobs_start(wm, wm_job); } +static void drw_register_shader_vlattrs(GPUMaterial *mat) +{ + const ListBase *attrs = GPU_material_layer_attributes(mat); + + if (!attrs) { + return; + } + + GHash *hash = DST.vmempool->vlattrs_name_cache; + ListBase *list = &DST.vmempool->vlattrs_name_list; + + LISTBASE_FOREACH (GPULayerAttr *, attr, attrs) { + GPULayerAttr **p_val; + + /* Add to the table and list if newly seen. */ + if (!BLI_ghash_ensure_p(hash, (void *)attr->hash_code, (void ***)&p_val)) { + DST.vmempool->vlattrs_ubo_ready = false; + + GPULayerAttr *new_link = *p_val = MEM_dupallocN(attr); + + /* Insert into the list ensuring sorted order. */ + GPULayerAttr *link = list->first; + + while (link && link->hash_code <= attr->hash_code) { + link = link->next; + } + + new_link->prev = new_link->next = NULL; + BLI_insertlinkbefore(list, link, new_link); + } + + /* Reset the unused frames counter. */ + (*p_val)->users = 0; + } +} + void DRW_deferred_shader_remove(GPUMaterial *mat) { LISTBASE_FOREACH (wmWindowManager *, wm, &G_MAIN->wm) { @@ -382,6 +418,9 @@ GPUMaterial *DRW_shader_from_world(World *wo, false, callback, thunk); + + drw_register_shader_vlattrs(mat); + if (DRW_state_is_image_render()) { /* Do not deferred if doing render. */ deferred = false; @@ -411,6 +450,8 @@ GPUMaterial *DRW_shader_from_material(Material *ma, callback, thunk); + drw_register_shader_vlattrs(mat); + if (DRW_state_is_image_render()) { /* Do not deferred if doing render. */ deferred = false; diff --git a/source/blender/draw/intern/draw_resource.cc b/source/blender/draw/intern/draw_resource.cc index f57058190fb..c1f83c3a5ae 100644 --- a/source/blender/draw/intern/draw_resource.cc +++ b/source/blender/draw/intern/draw_resource.cc @@ -38,3 +38,16 @@ bool ObjectAttribute::sync(const blender::draw::ObjectRef &ref, const GPUUniform } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name LayerAttributes + * \{ */ + +bool LayerAttribute::sync(Scene *scene, ViewLayer *layer, const GPULayerAttr &attr) +{ + hash_code = attr.hash_code; + + return BKE_view_layer_find_rgba_attribute(scene, layer, attr.name, &data.x); +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index 37899e36d8a..75a7e28fa75 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -15,6 +15,7 @@ typedef struct ObjectBounds ObjectBounds; typedef struct VolumeInfos VolumeInfos; typedef struct CurvesInfos CurvesInfos; typedef struct ObjectAttribute ObjectAttribute; +typedef struct LayerAttribute LayerAttribute; typedef struct DrawCommand DrawCommand; typedef struct DispatchCommand DispatchCommand; typedef struct DRWDebugPrintBuffer DRWDebugPrintBuffer; @@ -24,8 +25,10 @@ typedef struct DRWDebugDrawBuffer DRWDebugDrawBuffer; # ifdef __cplusplus /* C++ only forward declarations. */ struct Object; +struct ViewLayer; struct ID; struct GPUUniformAttr; +struct GPULayerAttr; namespace blender::draw { @@ -192,6 +195,20 @@ struct ObjectAttribute { * C++ compiler gives us the same size. */ BLI_STATIC_ASSERT_ALIGN(ObjectAttribute, 20) +#pragma pack(push, 4) +struct LayerAttribute { + float4 data; + uint hash_code; + uint buffer_length; /* Only in the first record. */ + uint _pad1, _pad2; + +#if !defined(GPU_SHADER) && defined(__cplusplus) + bool sync(Scene *scene, ViewLayer *layer, const GPULayerAttr &attr); +#endif +}; +#pragma pack(pop) +BLI_STATIC_ASSERT_ALIGN(LayerAttribute, 32) + /** \} */ /* -------------------------------------------------------------------- */ 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 ad0426e6d3f..33634fb5fcb 100644 --- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh +++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh @@ -19,6 +19,14 @@ GPU_SHADER_CREATE_INFO(draw_curves_infos) .typedef_source("draw_shader_shared.h") .uniform_buf(3, "CurvesInfos", "drw_curves", Frequency::BATCH); +GPU_SHADER_CREATE_INFO(draw_layer_attributes) + .typedef_source("draw_shader_shared.h") + .define("VLATTR_LIB") + .uniform_buf(DRW_LAYER_ATTR_UBO_SLOT, + "LayerAttribute", + "drw_layer_attrs[DRW_RESOURCE_CHUNK_LEN]", + Frequency::BATCH); + GPU_SHADER_CREATE_INFO(draw_object_infos_new) .typedef_source("draw_shader_shared.h") .define("OBINFO_LIB") diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 31354585308..3dad2a1a19a 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -162,6 +162,7 @@ GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli, uint32_t *r_hash); +GPUNodeLink *GPU_layer_attribute(GPUMaterial *mat, const char *name); GPUNodeLink *GPU_image(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser, @@ -357,6 +358,20 @@ struct GHash *GPU_uniform_attr_list_hash_new(const char *info); void GPU_uniform_attr_list_copy(GPUUniformAttrList *dest, const GPUUniformAttrList *src); void GPU_uniform_attr_list_free(GPUUniformAttrList *set); +typedef struct GPULayerAttr { + struct GPULayerAttr *next, *prev; + + /* Meaningful part of the attribute set key. */ + char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + /** Hash of name[64]. */ + uint32_t hash_code; + + /* Helper fields used by code generation. */ + int users; +} GPULayerAttr; + +const ListBase *GPU_material_layer_attributes(const GPUMaterial *material); + /* A callback passed to GPU_material_from_callbacks to construct the material graph by adding and * linking the necessary GPU material nodes. */ typedef void (*ConstructGPUMaterialFn)(void *thunk, GPUMaterial *material); diff --git a/source/blender/gpu/GPU_uniform_buffer.h b/source/blender/gpu/GPU_uniform_buffer.h index f78719d1963..28f06d6071d 100644 --- a/source/blender/gpu/GPU_uniform_buffer.h +++ b/source/blender/gpu/GPU_uniform_buffer.h @@ -44,6 +44,7 @@ void GPU_uniformbuf_unbind_all(void); #define GPU_UBO_BLOCK_NAME "node_tree" #define GPU_ATTRIBUTE_UBO_BLOCK_NAME "unf_attrs" +#define GPU_LAYER_ATTRIBUTE_UBO_BLOCK_NAME "drw_layer_attrs" #ifdef __cplusplus } diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index b02d8a02704..4adeac1b49a 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -183,6 +183,8 @@ static std::ostream &operator<<(std::ostream &stream, const GPUInput *input) 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_LAYER_ATTR: + return stream << "attr_load_layer(" << input->layer_attr->hash_code << ")"; case GPU_SOURCE_STRUCT: return stream << "strct" << input->id; case GPU_SOURCE_TEX: @@ -432,6 +434,10 @@ void GPUCodegen::generate_resources() info.uniform_buf(2, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH); } + if (!BLI_listbase_is_empty(&graph.layer_attrs)) { + info.additional_info("draw_layer_attributes"); + } + info.typedef_source_generated = ss.str(); } diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 0f9dc8be9c5..ca2a9f5cf28 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -291,6 +291,12 @@ const GPUUniformAttrList *GPU_material_uniform_attributes(const GPUMaterial *mat return attrs->count > 0 ? attrs : NULL; } +const ListBase *GPU_material_layer_attributes(const GPUMaterial *material) +{ + const ListBase *attrs = &material->graph.layer_attrs; + return !BLI_listbase_is_empty(attrs) ? attrs : NULL; +} + #if 1 /* End of life code. */ /* Eevee Subsurface scattering. */ /* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */ diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index e1ae731d49c..c72e7097b33 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -83,6 +83,9 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType case GPU_SOURCE_UNIFORM_ATTR: input->uniform_attr->users++; break; + case GPU_SOURCE_LAYER_ATTR: + input->layer_attr->users++; + break; case GPU_SOURCE_TEX: case GPU_SOURCE_TEX_TILED_MAPPING: input->texture->users++; @@ -133,6 +136,10 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType input->source = GPU_SOURCE_UNIFORM_ATTR; input->uniform_attr = link->uniform_attr; break; + case GPU_NODE_LINK_LAYER_ATTR: + input->source = GPU_SOURCE_LAYER_ATTR; + input->layer_attr = link->layer_attr; + break; case GPU_NODE_LINK_CONSTANT: input->source = (type == GPU_CLOSURE) ? GPU_SOURCE_STRUCT : GPU_SOURCE_CONSTANT; break; @@ -430,6 +437,34 @@ static GPUUniformAttr *gpu_node_graph_add_uniform_attribute(GPUNodeGraph *graph, return attr; } +/** Add a new uniform attribute of given type and name. Returns NULL if out of slots. */ +static GPULayerAttr *gpu_node_graph_add_layer_attribute(GPUNodeGraph *graph, const char *name) +{ + /* Find existing attribute. */ + ListBase *attrs = &graph->layer_attrs; + GPULayerAttr *attr = attrs->first; + + for (; attr; attr = attr->next) { + if (STREQ(attr->name, name)) { + break; + } + } + + /* Add new requested attribute to the list. */ + if (attr == NULL) { + attr = MEM_callocN(sizeof(*attr), __func__); + STRNCPY(attr->name, name); + attr->hash_code = BLI_ghashutil_strhash_p(attr->name); + BLI_addtail(attrs, attr); + } + + if (attr != NULL) { + attr->users++; + } + + return attr; +} + static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, Image *ima, ImageUser *iuser, @@ -546,6 +581,17 @@ GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, return link; } +GPUNodeLink *GPU_layer_attribute(GPUMaterial *mat, const char *name) +{ + GPUNodeGraph *graph = gpu_material_node_graph(mat); + GPULayerAttr *attr = gpu_node_graph_add_layer_attribute(graph, name); + + GPUNodeLink *link = gpu_node_link_create(); + link->link_type = GPU_NODE_LINK_LAYER_ATTR; + link->layer_attr = attr; + return link; +} + GPUNodeLink *GPU_constant(const float *num) { GPUNodeLink *link = gpu_node_link_create(); @@ -767,14 +813,22 @@ static void gpu_inputs_free(ListBase *inputs) GPUInput *input; for (input = inputs->first; input; input = input->next) { - if (input->source == GPU_SOURCE_ATTR) { - input->attr->users--; - } - else if (input->source == GPU_SOURCE_UNIFORM_ATTR) { - input->uniform_attr->users--; - } - else if (ELEM(input->source, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING)) { - input->texture->users--; + switch (input->source) { + case GPU_SOURCE_ATTR: + input->attr->users--; + break; + case GPU_SOURCE_UNIFORM_ATTR: + input->uniform_attr->users--; + break; + case GPU_SOURCE_LAYER_ATTR: + input->layer_attr->users--; + break; + case GPU_SOURCE_TEX: + case GPU_SOURCE_TEX_TILED_MAPPING: + input->texture->users--; + break; + default: + break; } if (input->link) { @@ -826,6 +880,7 @@ void gpu_node_graph_free(GPUNodeGraph *graph) BLI_freelistN(&graph->textures); BLI_freelistN(&graph->attributes); GPU_uniform_attr_list_free(&graph->uniform_attrs); + BLI_freelistN(&graph->layer_attrs); if (graph->used_libraries) { BLI_gset_free(graph->used_libraries, NULL); @@ -908,4 +963,10 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph) uattrs->count--; } } + + LISTBASE_FOREACH_MUTABLE (GPULayerAttr *, attr, &graph->layer_attrs) { + if (attr->users == 0) { + BLI_freelinkN(&graph->layer_attrs, attr); + } + } } diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index 7db22151f86..de0a0687b13 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -31,6 +31,7 @@ typedef enum eGPUDataSource { GPU_SOURCE_UNIFORM, GPU_SOURCE_ATTR, GPU_SOURCE_UNIFORM_ATTR, + GPU_SOURCE_LAYER_ATTR, GPU_SOURCE_STRUCT, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING, @@ -42,6 +43,7 @@ typedef enum { GPU_NODE_LINK_NONE = 0, GPU_NODE_LINK_ATTR, GPU_NODE_LINK_UNIFORM_ATTR, + GPU_NODE_LINK_LAYER_ATTR, GPU_NODE_LINK_COLORBAND, GPU_NODE_LINK_CONSTANT, GPU_NODE_LINK_IMAGE, @@ -95,6 +97,8 @@ struct GPUNodeLink { struct GPUMaterialAttribute *attr; /* GPU_NODE_LINK_UNIFORM_ATTR */ struct GPUUniformAttr *uniform_attr; + /* GPU_NODE_LINK_LAYER_ATTR */ + struct GPULayerAttr *layer_attr; /* GPU_NODE_LINK_IMAGE_BLENDER */ struct GPUMaterialTexture *texture; /* GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN */ @@ -131,6 +135,8 @@ typedef struct GPUInput { struct GPUMaterialAttribute *attr; /* GPU_SOURCE_UNIFORM_ATTR */ struct GPUUniformAttr *uniform_attr; + /* GPU_SOURCE_LAYER_ATTR */ + struct GPULayerAttr *layer_attr; /* GPU_SOURCE_FUNCTION_CALL */ char function_call[64]; }; @@ -171,6 +177,9 @@ typedef struct GPUNodeGraph { /* The list of uniform attributes. */ GPUUniformAttrList uniform_attrs; + /* The list of layer attributes. */ + ListBase layer_attrs; + /** Set of all the GLSL lib code blocks . */ GSet *used_libraries; } GPUNodeGraph; 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 bacf089deb1..8d0016a2206 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl @@ -29,6 +29,31 @@ void node_attribute_uniform(vec4 attr, const float attr_hash, out vec4 out_attr) out_attr = attr_load_uniform(attr, floatBitsToUint(attr_hash)); } +vec4 attr_load_layer(const uint attr_hash) +{ +#ifdef VLATTR_LIB + /* The first record of the buffer stores the length. */ + uint left = 0, right = drw_layer_attrs[0].buffer_length; + + while (left < right) { + uint mid = (left + right) / 2; + uint hash = drw_layer_attrs[mid].hash_code; + + if (hash < attr_hash) { + left = mid + 1; + } + else if (hash > attr_hash) { + right = mid; + } + else { + return drw_layer_attrs[mid].data; + } + } +#endif + + return vec4(0.0); +} + void node_attribute( vec4 attr, out vec4 outcol, out vec3 outvec, out float outf, out float outalpha) { diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 963567133d9..4715543ebaf 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1686,6 +1686,7 @@ enum { SHD_ATTRIBUTE_GEOMETRY = 0, SHD_ATTRIBUTE_OBJECT = 1, SHD_ATTRIBUTE_INSTANCER = 2, + SHD_ATTRIBUTE_VIEW_LAYER = 3, }; /* toon modes */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 2db81693f51..5fa5d4c7787 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1761,6 +1761,8 @@ typedef struct Scene { ID id; /** Animation data (must be immediately after id for utilities to use it). */ struct AnimData *adt; + /* runtime (must be immediately after id for utilities to use it). */ + DrawDataList drawdata; struct Object *camera; struct World *world; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index a0a933c3f90..dde3a3d8d14 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -5242,6 +5242,11 @@ static void def_sh_attribute(StructRNA *srna) "The attribute is associated with the instancer particle system or object, " "falling back to the Object mode if the attribute isn't found, or the object " "is not instanced"}, + {SHD_ATTRIBUTE_VIEW_LAYER, + "VIEW_LAYER", + 0, + "View Layer", + "The attribute is associated with the View Layer, Scene or World that is being rendered"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.cc b/source/blender/nodes/shader/nodes/node_shader_attribute.cc index 77cf6b163d0..4694599f064 100644 --- a/source/blender/nodes/shader/nodes/node_shader_attribute.cc +++ b/source/blender/nodes/shader/nodes/node_shader_attribute.cc @@ -42,6 +42,16 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, if (is_varying) { cd_attr = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->name); + + if (STREQ(attr->name, "color")) { + GPU_link(mat, "node_attribute_color", cd_attr, &cd_attr); + } + else if (STREQ(attr->name, "temperature")) { + GPU_link(mat, "node_attribute_temperature", cd_attr, &cd_attr); + } + } + else if (attr->type == SHD_ATTRIBUTE_VIEW_LAYER) { + cd_attr = GPU_layer_attribute(mat, attr->name); } else { cd_attr = GPU_uniform_attribute(mat, @@ -52,13 +62,6 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, GPU_link(mat, "node_attribute_uniform", cd_attr, GPU_constant(&attr_hash), &cd_attr); } - if (STREQ(attr->name, "color")) { - GPU_link(mat, "node_attribute_color", cd_attr, &cd_attr); - } - else if (STREQ(attr->name, "temperature")) { - GPU_link(mat, "node_attribute_temperature", cd_attr, &cd_attr); - } - GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr); if (is_varying) { |