diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index 91e5fe007da..695484dd080 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -118,6 +118,9 @@ class CurvesGeometryRuntime { /** Normal direction vectors for each evaluated point. */ mutable SharedCache> evaluated_normal_cache; + /** The maximum of the "material_index" attribute. */ + mutable SharedCache> max_material_index_cache; + /** Stores weak references to material data blocks. */ std::unique_ptr bake_materials; @@ -305,6 +308,9 @@ class CurvesGeometry : public ::CurvesGeometry { void count_memory(MemoryCounter &memory) const; + /** Get the largest material index used by the curves or nullopt if there are none. */ + std::optional material_index_max() const; + private: /* -------------------------------------------------------------------- * Evaluation. @@ -399,6 +405,8 @@ class CurvesGeometry : public ::CurvesGeometry { * this in #finish() calls. */ void tag_radii_changed(); + /** Call after changing the "material_index" attribute. */ + void tag_material_index_changed(); void translate(const float3 &translation); void transform(const float4x4 &matrix); diff --git a/source/blender/blenkernel/BKE_material.hh b/source/blender/blenkernel/BKE_material.hh index 34be7392e74..91a46754338 100644 --- a/source/blender/blenkernel/BKE_material.hh +++ b/source/blender/blenkernel/BKE_material.hh @@ -9,6 +9,8 @@ * \brief General operations, lookup, etc. for materials. */ +#include + struct ID; struct Main; struct Material; @@ -155,11 +157,25 @@ Material *BKE_object_material_get_eval(Object *ob, short act); * This is the maximum of the number of material slots on the object and geometry. */ int BKE_object_material_count_eval(const Object *ob); + /** - * Same as #BKE_object_material_count_eval, but returns at least one. This is commonly used in - * rendering code which has to use a fallback material if there is none. + * Returns the maximum material index used by the geometry. This returns zero if the geometry is + * empty or if all material indices are negative. */ -int BKE_object_material_count_with_fallback_eval(const Object *ob); +std::optional BKE_id_material_index_max_eval(const ID &id); + +/** + * Gets the number of material slots used by the geometry. The corresponding material for each slot + * can be retrieved with #BKE_object_material_get_eval. + * + * These two functions give the same result when the mesh is provided itself, or an object that + * uses the mesh. + * + * NOTE: This may be higher or lower than the number of material slots on the object or + * object-data. However, it is always at least 1 (the fallback). + */ +int BKE_id_material_used_with_fallback_eval(const ID &id); +int BKE_object_material_used_with_fallback_eval(const Object &ob); void BKE_id_material_eval_assign(ID *id, int slot, Material *material); /** diff --git a/source/blender/blenkernel/BKE_mesh_types.hh b/source/blender/blenkernel/BKE_mesh_types.hh index afe0ee1b5b4..69bb406aa3c 100644 --- a/source/blender/blenkernel/BKE_mesh_types.hh +++ b/source/blender/blenkernel/BKE_mesh_types.hh @@ -169,6 +169,8 @@ struct MeshRuntime { SharedCache> bvh_cache_loose_edges; SharedCache> bvh_cache_loose_edges_no_hidden; + SharedCache> max_material_index; + /** Needed in case we need to lazily initialize the mesh. */ CustomData_MeshMasks cd_mask_extra = {}; diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index a2c166527c8..9db924995b9 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -5485,6 +5485,18 @@ void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], cons } } +std::optional Curve::material_index_max() const +{ + if (BLI_listbase_is_empty(&this->nurb)) { + return std::nullopt; + } + int max_index = 0; + LISTBASE_FOREACH (const Nurb *, nurb, &this->nurb) { + max_index = std::max(max_index, nurb->mat_nr); + } + return max_index; +} + /* **** Depsgraph evaluation **** */ void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve) diff --git a/source/blender/blenkernel/intern/curves_attributes.cc b/source/blender/blenkernel/intern/curves_attributes.cc index 2b6c361805b..bd05b97661a 100644 --- a/source/blender/blenkernel/intern/curves_attributes.cc +++ b/source/blender/blenkernel/intern/curves_attributes.cc @@ -46,6 +46,12 @@ static void tag_component_normals_changed(void *owner) curves.tag_normals_changed(); } +static void tag_component_material_index_changed(void *owner) +{ + CurvesGeometry &curves = *static_cast(owner); + curves.tag_material_index_changed(); +} + /** * This provider makes vertex groups available as float attributes. */ @@ -348,7 +354,7 @@ static GeometryAttributeProviders create_attribute_providers_for_curve() CD_PROP_INT32, BuiltinAttributeProvider::Deletable, curve_access, - nullptr, + tag_component_material_index_changed, AttributeValidator{&material_index_clamp}); static CurvesVertexGroupsAttributeProvider vertex_groups; diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 93f0cf1e751..9a514df2b27 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -117,6 +117,7 @@ CurvesGeometry::CurvesGeometry(const CurvesGeometry &other) other.runtime->evaluated_length_cache, other.runtime->evaluated_tangent_cache, other.runtime->evaluated_normal_cache, + other.runtime->max_material_index_cache, {}, true}); @@ -1082,6 +1083,7 @@ void CurvesGeometry::tag_topology_changed() this->tag_positions_changed(); this->runtime->evaluated_offsets_cache.tag_dirty(); this->runtime->nurbs_basis_cache.tag_dirty(); + this->runtime->max_material_index_cache.tag_dirty(); this->runtime->check_type_counts = true; } void CurvesGeometry::tag_normals_changed() @@ -1089,6 +1091,10 @@ void CurvesGeometry::tag_normals_changed() this->runtime->evaluated_normal_cache.tag_dirty(); } void CurvesGeometry::tag_radii_changed() {} +void CurvesGeometry::tag_material_index_changed() +{ + this->runtime->max_material_index_cache.tag_dirty(); +} static void translate_positions(MutableSpan positions, const float3 &translation) { @@ -1204,6 +1210,17 @@ std::optional> CurvesGeometry::bounds_min_max() const return this->runtime->bounds_cache.data(); } +std::optional CurvesGeometry::material_index_max() const +{ + this->runtime->max_material_index_cache.ensure([&](std::optional &r_max_material_index) { + r_max_material_index = blender::bounds::max( + this->attributes() + .lookup_or_default("material_index", blender::bke::AttrDomain::Curve, 0) + .varray); + }); + return this->runtime->max_material_index_cache.data(); +} + void CurvesGeometry::count_memory(MemoryCounter &memory) const { memory.add_shared(this->runtime->curve_offsets_sharing_info, this->offsets().size_in_bytes()); diff --git a/source/blender/blenkernel/intern/grease_pencil.cc b/source/blender/blenkernel/intern/grease_pencil.cc index bd1d369ee5e..f09c5406154 100644 --- a/source/blender/blenkernel/intern/grease_pencil.cc +++ b/source/blender/blenkernel/intern/grease_pencil.cc @@ -3222,6 +3222,28 @@ void GreasePencil::count_memory(blender::MemoryCounter &memory) const } } +std::optional GreasePencil::material_index_max_eval() const +{ + using namespace blender; + using namespace blender::bke; + std::optional max_index; + for (const greasepencil::Layer *layer : this->layers()) { + if (const greasepencil::Drawing *drawing = this->get_eval_drawing(*layer)) { + const bke::CurvesGeometry &curves = drawing->strokes(); + const std::optional max_index_on_layer = curves.material_index_max(); + if (max_index) { + if (max_index_on_layer) { + max_index = std::max(*max_index, *max_index_on_layer); + } + } + else { + max_index = max_index_on_layer; + } + } + } + return max_index; +} + blender::Span GreasePencil::layers() const { BLI_assert(this->runtime != nullptr); diff --git a/source/blender/blenkernel/intern/material.cc b/source/blender/blenkernel/intern/material.cc index 295f8bcf7ea..8df48c6d65d 100644 --- a/source/blender/blenkernel/intern/material.cc +++ b/source/blender/blenkernel/intern/material.cc @@ -49,6 +49,7 @@ #include "BKE_attribute.hh" #include "BKE_brush.hh" #include "BKE_curve.hh" +#include "BKE_curves.hh" #include "BKE_displist.h" #include "BKE_editmesh.hh" #include "BKE_gpencil_legacy.h" @@ -732,7 +733,7 @@ Material *BKE_object_material_get(Object *ob, short act) return ma_p ? *ma_p : nullptr; } -static const ID *get_evaluated_object_data_with_materials(Object *ob) +static const ID *get_evaluated_object_data_with_materials(const Object *ob) { const ID *data = static_cast(ob->data); /* Meshes in edit mode need special handling. */ @@ -799,10 +800,43 @@ int BKE_object_material_count_eval(const Object *ob) return std::max(ob->totcol, len_p ? *len_p : 0); } -int BKE_object_material_count_with_fallback_eval(const Object *ob) +std::optional BKE_id_material_index_max_eval(const ID &id) { - const int actual_count = BKE_object_material_count_eval(ob); - return std::max(1, actual_count); + switch (GS(id.name)) { + case ID_ME: + return reinterpret_cast(id).material_index_max(); + case ID_CU_LEGACY: + return reinterpret_cast(id).material_index_max(); + case ID_CV: + return reinterpret_cast(id).geometry.wrap().material_index_max(); + case ID_PT: + return reinterpret_cast(id).material_index_max(); + case ID_GP: + return reinterpret_cast(id).material_index_max_eval(); + case ID_VO: + case ID_MB: + /* Always use the first material. */ + return 0; + case ID_GD_LEGACY: + /* Is not rendered anymore. */ + BLI_assert_unreachable(); + return 0; + default: + break; + } + return 0; +} + +int BKE_id_material_used_with_fallback_eval(const ID &id) +{ + const int max_material_index = std::max(0, BKE_id_material_index_max_eval(id).value_or(0)); + return max_material_index + 1; +} + +int BKE_object_material_used_with_fallback_eval(const Object &ob) +{ + const ID *data = get_evaluated_object_data_with_materials(&ob); + return BKE_id_material_used_with_fallback_eval(*data); } void BKE_id_material_eval_assign(ID *id, int slot, Material *material) diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index ae17286948c..b1dc5ad98b7 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -166,6 +166,7 @@ static void mesh_copy_data(Main *bmain, mesh_dst->runtime->bvh_cache_loose_edges = mesh_src->runtime->bvh_cache_loose_edges; mesh_dst->runtime->bvh_cache_loose_edges_no_hidden = mesh_src->runtime->bvh_cache_loose_edges_no_hidden; + mesh_dst->runtime->max_material_index = mesh_src->runtime->max_material_index; if (mesh_src->runtime->bake_materials) { mesh_dst->runtime->bake_materials = std::make_unique( *mesh_src->runtime->bake_materials); @@ -1352,6 +1353,22 @@ void BKE_mesh_transform(Mesh *mesh, const float mat[4][4], bool do_keys) mesh->tag_positions_changed(); } +std::optional Mesh::material_index_max() const +{ + this->runtime->max_material_index.ensure([&](std::optional &value) { + if (this->faces_num == 0) { + value = std::nullopt; + } + else { + value = blender::bounds::max( + this->attributes() + .lookup_or_default("material_index", blender::bke::AttrDomain::Face, 0) + .varray); + } + }); + return this->runtime->max_material_index.data(); +} + static void translate_positions(MutableSpan positions, const float3 &translation) { using namespace blender; diff --git a/source/blender/blenkernel/intern/mesh_attributes.cc b/source/blender/blenkernel/intern/mesh_attributes.cc index 3ba7d37c6d7..3f0422ba2ef 100644 --- a/source/blender/blenkernel/intern/mesh_attributes.cc +++ b/source/blender/blenkernel/intern/mesh_attributes.cc @@ -724,6 +724,13 @@ static void tag_component_sharpness_changed(void *owner) } } +static void tag_material_index_changed(void *owner) +{ + if (Mesh *mesh = static_cast(owner)) { + mesh->tag_material_index_changed(); + } +} + /** * This provider makes vertex groups available as float attributes. */ @@ -904,7 +911,7 @@ static GeometryAttributeProviders create_attribute_providers_for_mesh() CD_PROP_INT32, BuiltinAttributeProvider::Deletable, face_access, - nullptr, + tag_material_index_changed, AttributeValidator{&material_index_clamp}); static const auto int2_index_clamp = mf::build::SI1_SO( diff --git a/source/blender/blenkernel/intern/mesh_runtime.cc b/source/blender/blenkernel/intern/mesh_runtime.cc index 465e64db9b6..7513fc193c0 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.cc +++ b/source/blender/blenkernel/intern/mesh_runtime.cc @@ -332,6 +332,7 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh) mesh->runtime->corner_tris_cache.data.tag_dirty(); mesh->runtime->corner_tri_faces_cache.tag_dirty(); mesh->runtime->shrinkwrap_boundary_cache.tag_dirty(); + mesh->runtime->max_material_index.tag_dirty(); mesh->runtime->subsurf_face_dot_tags.clear_and_shrink(); mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink(); mesh->flag &= ~ME_NO_OVERLAPPING_TOPOLOGY; @@ -421,6 +422,11 @@ void Mesh::tag_visibility_changed() this->runtime->bvh_cache_loose_edges_no_hidden.tag_dirty(); } +void Mesh::tag_material_index_changed() +{ + this->runtime->max_material_index.tag_dirty(); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 86ae17219e5..526dfb53357 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -279,6 +279,17 @@ std::optional> PointCloud::bounds_min_max() con return this->runtime->bounds_cache.data(); } +std::optional PointCloud::material_index_max() const +{ + if (this->totpoint == 0) { + return std::nullopt; + } + return blender::bounds::max( + this->attributes() + .lookup_or_default("material_index", blender::bke::AttrDomain::Point, 0) + .varray); +} + void PointCloud::count_memory(blender::MemoryCounter &memory) const { CustomData_count_memory(this->pdata, this->totpoint, memory); diff --git a/source/blender/blenlib/BLI_bounds.hh b/source/blender/blenlib/BLI_bounds.hh index c62c7c9f757..96f5c931cee 100644 --- a/source/blender/blenlib/BLI_bounds.hh +++ b/source/blender/blenlib/BLI_bounds.hh @@ -16,6 +16,7 @@ #include "BLI_index_mask.hh" #include "BLI_math_vector.hh" #include "BLI_task.hh" +#include "BLI_virtual_array.hh" namespace blender { @@ -150,6 +151,31 @@ template return intersect(*a, *b); } +/** + * Finds the maximum value for elements in the array. + */ +template inline std::optional max(const VArray &values) +{ + if (values.is_empty()) { + return std::nullopt; + } + if (const std::optional value = values.get_if_single()) { + return value; + } + const VArraySpan values_span = values; + return threading::parallel_reduce( + values_span.index_range(), + 2048, + std::numeric_limits::min(), + [&](const IndexRange range, int current_max) { + for (const int value : values_span.slice(range)) { + current_max = std::max(current_max, value); + } + return current_max; + }, + [](const int a, const int b) { return std::max(a, b); }); +} + } // namespace bounds namespace detail { diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc index 074503fa94d..063d7898bad 100644 --- a/source/blender/draw/engines/eevee_next/eevee_material.cc +++ b/source/blender/draw/engines/eevee_next/eevee_material.cc @@ -450,7 +450,7 @@ MaterialArray &MaterialModule::material_array_get(Object *ob, bool has_motion) material_array_.materials.clear(); material_array_.gpu_materials.clear(); - const int materials_len = DRW_cache_object_material_count_get(ob); + const int materials_len = BKE_object_material_used_with_fallback_eval(*ob); for (auto i : IndexRange(materials_len)) { ::Material *blender_mat = material_from_slot(ob, i); diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc b/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc index 73cafeed7a8..b8e9f5fb17e 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc @@ -52,7 +52,7 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, /* Check if any material with holdout flag enabled. */ tgp_ob->do_mat_holdout = false; - const int tot_materials = BKE_object_material_count_eval(ob); + const int tot_materials = BKE_object_material_used_with_fallback_eval(*ob); for (int i = 0; i < tot_materials; i++) { MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, i + 1); if (((gp_style != nullptr) && (gp_style->flag & GP_MATERIAL_IS_STROKE_HOLDOUT)) || diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.cc b/source/blender/draw/engines/gpencil/gpencil_draw_data.cc index 19ba43f27c9..30d619f017c 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.cc +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.cc @@ -165,7 +165,7 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, { GPENCIL_MaterialPool *matpool = pd->last_material_pool; - int mat_len = max_ii(1, BKE_object_material_count_eval(ob)); + int mat_len = BKE_object_material_used_with_fallback_eval(*ob); bool reuse_matpool = matpool && ((matpool->used_count + mat_len) <= GPENCIL_MATERIAL_BUFFER_LEN); diff --git a/source/blender/draw/engines/overlay/overlay_armature.cc b/source/blender/draw/engines/overlay/overlay_armature.cc index eaa7d081091..47e8599960c 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.cc +++ b/source/blender/draw/engines/overlay/overlay_armature.cc @@ -402,7 +402,7 @@ static void drw_shgroup_bone_custom_solid_mesh(const Armatures::DrawContext *ctx using namespace blender::draw; /* TODO(fclem): arg... less than ideal but we never iter on this object * to assure batch cache is valid. */ - DRW_mesh_batch_cache_validate(custom, mesh); + DRW_mesh_batch_cache_validate(mesh); blender::gpu::Batch *surf = DRW_mesh_batch_cache_get_surface(mesh); blender::gpu::Batch *edges = DRW_mesh_batch_cache_get_edge_detection(mesh, nullptr); @@ -447,7 +447,7 @@ static void drw_shgroup_bone_custom_mesh_wire(const Armatures::DrawContext *ctx, using namespace blender::draw; /* TODO(fclem): arg... less than ideal but we never iter on this object * to assure batch cache is valid. */ - DRW_mesh_batch_cache_validate(custom, mesh); + DRW_mesh_batch_cache_validate(mesh); blender::gpu::Batch *geom = DRW_mesh_batch_cache_get_all_edges(mesh); if (geom) { diff --git a/source/blender/draw/engines/overlay/overlay_next_instance.cc b/source/blender/draw/engines/overlay/overlay_next_instance.cc index 9df8dc56c01..4a2261fc095 100644 --- a/source/blender/draw/engines/overlay/overlay_next_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_next_instance.cc @@ -758,7 +758,7 @@ bool Instance::object_is_rendered_transparent(const Object *object, const State if (shading.color_type == V3D_SHADING_MATERIAL_COLOR) { if (object->type == OB_MESH) { - const int materials_num = BKE_object_material_count_eval(object); + const int materials_num = BKE_object_material_used_with_fallback_eval(*object); for (int i = 0; i < materials_num; i++) { Material *mat = BKE_object_material_get_eval(const_cast(object), i + 1); if (mat && mat->a < 1.0f) { diff --git a/source/blender/draw/engines/overlay/overlay_next_prepass.hh b/source/blender/draw/engines/overlay/overlay_next_prepass.hh index 24d43689397..05ba36a0803 100644 --- a/source/blender/draw/engines/overlay/overlay_next_prepass.hh +++ b/source/blender/draw/engines/overlay/overlay_next_prepass.hh @@ -216,7 +216,7 @@ class Prepass : Overlay { case OB_MESH: if (use_material_slot_selection_) { /* TODO(fclem): Improve the API. */ - const int materials_len = DRW_cache_object_material_count_get(ob_ref.object); + const int materials_len = BKE_object_material_used_with_fallback_eval(*ob_ref.object); Array materials(materials_len, nullptr); geom_list = DRW_cache_mesh_surface_shaded_get(ob_ref.object, materials); } diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index 56350f0909c..cb420c6a418 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -259,7 +259,7 @@ class Instance { bool has_transparent_material = false; if (object_state.use_per_material_batches) { - const int material_count = DRW_cache_object_material_count_get(ob_ref.object); + const int material_count = BKE_object_material_used_with_fallback_eval(*ob_ref.object); Span batches; if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) { diff --git a/source/blender/draw/intern/draw_cache.cc b/source/blender/draw/intern/draw_cache.cc index cea7a7d2922..00c5c529564 100644 --- a/source/blender/draw/intern/draw_cache.cc +++ b/source/blender/draw/intern/draw_cache.cc @@ -935,11 +935,6 @@ blender::gpu::VertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob) } } -int DRW_cache_object_material_count_get(const Object *ob) -{ - return BKE_object_material_count_with_fallback_eval(ob); -} - Span DRW_cache_object_surface_material_get( Object *ob, const Span materials) { @@ -3293,7 +3288,7 @@ void drw_batch_cache_validate(Object *ob) using namespace blender::draw; switch (ob->type) { case OB_MESH: - DRW_mesh_batch_cache_validate(*ob, *(Mesh *)ob->data); + DRW_mesh_batch_cache_validate(*(Mesh *)ob->data); break; case OB_CURVES_LEGACY: case OB_FONT: @@ -3307,7 +3302,7 @@ void drw_batch_cache_validate(Object *ob) DRW_curves_batch_cache_validate((Curves *)ob->data); break; case OB_POINTCLOUD: - DRW_pointcloud_batch_cache_validate(*ob, (PointCloud *)ob->data); + DRW_pointcloud_batch_cache_validate((PointCloud *)ob->data); break; case OB_VOLUME: DRW_volume_batch_cache_validate((Volume *)ob->data); diff --git a/source/blender/draw/intern/draw_cache.hh b/source/blender/draw/intern/draw_cache.hh index cbea353bb9a..5d93cf7e445 100644 --- a/source/blender/draw/intern/draw_cache.hh +++ b/source/blender/draw/intern/draw_cache.hh @@ -72,7 +72,6 @@ blender::gpu::Batch *DRW_cache_object_loose_edges_get(Object *ob); blender::Span DRW_cache_object_surface_material_get( Object *ob, blender::Span materials); blender::gpu::Batch *DRW_cache_object_face_wireframe_get(const Scene *scene, Object *ob); -int DRW_cache_object_material_count_get(const Object *ob); /** * Returns the vertbuf used by shaded surface batch. diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc index 78902d1c211..e8ce4cc63c7 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc @@ -533,7 +533,7 @@ std::unique_ptr mesh_render_data_create(Object &object, { std::unique_ptr mr = std::make_unique(); mr->toolsettings = ts; - mr->materials_num = BKE_object_material_count_with_fallback_eval(&object); + mr->materials_num = BKE_object_material_used_with_fallback_eval(object); mr->object_to_world = object_to_world; diff --git a/source/blender/draw/intern/draw_cache_impl.hh b/source/blender/draw/intern/draw_cache_impl.hh index b13323c6da8..51078105138 100644 --- a/source/blender/draw/intern/draw_cache_impl.hh +++ b/source/blender/draw/intern/draw_cache_impl.hh @@ -46,7 +46,7 @@ void DRW_curve_batch_cache_validate(Curve *cu); void DRW_curve_batch_cache_free(Curve *cu); void DRW_mesh_batch_cache_dirty_tag(Mesh *mesh, eMeshBatchDirtyMode mode); -void DRW_mesh_batch_cache_validate(Object &object, Mesh &mesh); +void DRW_mesh_batch_cache_validate(Mesh &mesh); void DRW_mesh_batch_cache_free(void *batch_cache); void DRW_lattice_batch_cache_dirty_tag(Lattice *lt, int mode); @@ -61,7 +61,7 @@ void DRW_curves_batch_cache_validate(Curves *curves); void DRW_curves_batch_cache_free(Curves *curves); void DRW_pointcloud_batch_cache_dirty_tag(PointCloud *pointcloud, int mode); -void DRW_pointcloud_batch_cache_validate(Object &object, PointCloud *pointcloud); +void DRW_pointcloud_batch_cache_validate(PointCloud *pointcloud); void DRW_pointcloud_batch_cache_free(PointCloud *pointcloud); void DRW_volume_batch_cache_dirty_tag(Volume *volume, int mode); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index ddb499b72db..f080e1b7629 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -530,7 +530,7 @@ BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache &cache, DRWBatchFlag /* gpu::Batch cache management. */ -static bool mesh_batch_cache_valid(Object &object, Mesh &mesh) +static bool mesh_batch_cache_valid(Mesh &mesh) { MeshBatchCache *cache = static_cast(mesh.runtime->batch_cache); @@ -548,14 +548,14 @@ static bool mesh_batch_cache_valid(Object &object, Mesh &mesh) return false; } - if (cache->mat_len != BKE_object_material_count_with_fallback_eval(&object)) { + if (cache->mat_len != BKE_id_material_used_with_fallback_eval(mesh.id)) { return false; } return true; } -static void mesh_batch_cache_init(Object &object, Mesh &mesh) +static void mesh_batch_cache_init(Mesh &mesh) { if (!mesh.runtime->batch_cache) { mesh.runtime->batch_cache = MEM_new(__func__); @@ -574,7 +574,7 @@ static void mesh_batch_cache_init(Object &object, Mesh &mesh) // cache->vert_len = mesh_render_verts_len_get(mesh); } - cache->mat_len = BKE_object_material_count_with_fallback_eval(&object); + cache->mat_len = BKE_id_material_used_with_fallback_eval(mesh.id); cache->surface_per_mat = Array(cache->mat_len, nullptr); cache->tris_per_mat = Array(cache->mat_len, nullptr); @@ -585,13 +585,13 @@ static void mesh_batch_cache_init(Object &object, Mesh &mesh) drw_mesh_weight_state_clear(&cache->weight_state); } -void DRW_mesh_batch_cache_validate(Object &object, Mesh &mesh) +void DRW_mesh_batch_cache_validate(Mesh &mesh) { - if (!mesh_batch_cache_valid(object, mesh)) { + if (!mesh_batch_cache_valid(mesh)) { if (mesh.runtime->batch_cache) { mesh_batch_cache_clear(*static_cast(mesh.runtime->batch_cache)); } - mesh_batch_cache_init(object, mesh); + mesh_batch_cache_init(mesh); } } diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.cc b/source/blender/draw/intern/draw_cache_impl_pointcloud.cc index e7106ce81a6..cbfa1108f43 100644 --- a/source/blender/draw/intern/draw_cache_impl_pointcloud.cc +++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.cc @@ -92,20 +92,20 @@ static PointCloudBatchCache *pointcloud_batch_cache_get(PointCloud &pointcloud) return static_cast(pointcloud.batch_cache); } -static bool pointcloud_batch_cache_valid(Object &object, PointCloud &pointcloud) +static bool pointcloud_batch_cache_valid(PointCloud &pointcloud) { PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); if (cache == nullptr) { return false; } - if (cache->eval_cache.mat_len != BKE_object_material_count_with_fallback_eval(&object)) { + if (cache->eval_cache.mat_len != BKE_id_material_used_with_fallback_eval(pointcloud.id)) { return false; } return cache->is_dirty == false; } -static void pointcloud_batch_cache_init(Object &object, PointCloud &pointcloud) +static void pointcloud_batch_cache_init(PointCloud &pointcloud) { PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); @@ -117,7 +117,7 @@ static void pointcloud_batch_cache_init(Object &object, PointCloud &pointcloud) cache->eval_cache = {}; } - cache->eval_cache.mat_len = BKE_object_material_count_with_fallback_eval(&object); + cache->eval_cache.mat_len = BKE_id_material_used_with_fallback_eval(pointcloud.id); cache->eval_cache.surface_per_mat = static_cast( MEM_callocN(sizeof(gpu::Batch *) * cache->eval_cache.mat_len, __func__)); @@ -171,11 +171,11 @@ static void pointcloud_batch_cache_clear(PointCloud &pointcloud) pointcloud_discard_attributes(*cache); } -void DRW_pointcloud_batch_cache_validate(Object &object, PointCloud *pointcloud) +void DRW_pointcloud_batch_cache_validate(PointCloud *pointcloud) { - if (!pointcloud_batch_cache_valid(object, *pointcloud)) { + if (!pointcloud_batch_cache_valid(*pointcloud)) { pointcloud_batch_cache_clear(*pointcloud); - pointcloud_batch_cache_init(object, *pointcloud); + pointcloud_batch_cache_init(*pointcloud); } } diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 445980e3c5e..d6ddf442a34 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -13,6 +13,10 @@ #include "DNA_listBase.h" #include "DNA_vec_types.h" +#ifdef __cplusplus +# include +#endif + /** Used in `readfile.cc` and `editfont.cc`. */ #define MAXTEXTBOX 256 @@ -315,6 +319,11 @@ typedef struct Curve { char _pad3[7]; void *batch_cache; + +#ifdef __cplusplus + /** Get the largest material index used by the curves or nullopt if there are none. */ + std::optional material_index_max() const; +#endif } Curve; #define CURVE_VFONT_ANY(cu) ((cu)->vfont), ((cu)->vfontb), ((cu)->vfonti), ((cu)->vfontbi) diff --git a/source/blender/makesdna/DNA_grease_pencil_types.h b/source/blender/makesdna/DNA_grease_pencil_types.h index 155054dd282..f22e74d1500 100644 --- a/source/blender/makesdna/DNA_grease_pencil_types.h +++ b/source/blender/makesdna/DNA_grease_pencil_types.h @@ -720,6 +720,9 @@ typedef struct GreasePencil { blender::bke::AttributeAccessor attributes() const; blender::bke::MutableAttributeAccessor attributes_for_write(); + /** Get the largest material index used by the evaluated layers or nullopt if they are empty. */ + std::optional material_index_max_eval() const; + void count_memory(blender::MemoryCounter &memory) const; /* For debugging purposes. */ diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index a8b3e210e73..0f1d42fd894 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -309,6 +309,9 @@ typedef struct Mesh { /** Set cached mesh bounds to a known-correct value to avoid their lazy calculation later on. */ void bounds_set_eager(const blender::Bounds &bounds); + /** Get the largest material index used by the mesh or nullopt if it has no faces. */ + std::optional material_index_max() const; + /** * Cached map containing the index of the face using each face corner. */ @@ -429,6 +432,8 @@ typedef struct Mesh { void tag_topology_changed(); /** Call when changing the ".hide_vert", ".hide_edge", or ".hide_poly" attributes. */ void tag_visibility_changed(); + /** Call when changing the "material_index" attribute. */ + void tag_material_index_changed(); #endif } Mesh; diff --git a/source/blender/makesdna/DNA_pointcloud_types.h b/source/blender/makesdna/DNA_pointcloud_types.h index 442ec83a2b8..389f3a407ba 100644 --- a/source/blender/makesdna/DNA_pointcloud_types.h +++ b/source/blender/makesdna/DNA_pointcloud_types.h @@ -66,6 +66,9 @@ typedef struct PointCloud { std::optional> bounds_min_max() const; + /** Get the largest material index used by the pointcloud or nullopt if it is empty. */ + std::optional material_index_max() const; + void count_memory(blender::MemoryCounter &memory) const; #endif