Fix #132099: crash when using same geometry on objects with different material counts
The core issue was that the geometry batch cache (e.g. `MeshBatchCache` or `PointCloudBatchCache`) was dependent on the object. This is problematic when the the same geometry is used with multiple different objects because the cache can't be consistent with all of them. Fortunately, the only thing that was retrieved from the object was the number of material slots, so if that can be avoided we should be fine. We can't just use the number of material slots stored on the geometry because that may have no material slots but still has material indices which are overridden on the object level. The solution is to take make the number of materials for a geometry only dependent on the actual `material_index` attribute and not on the number of available slots. More specifically, we find the maximal referenced material index and handle that many materials. This number does not depend on how many material slots there are on the object, but it still allows the object to override materials slots that the mesh references. A downside is that the maximum material index has to be computed which often requires an iteration over the mesh. Fortunately, we can cache that quite easily and the computation can be done in parallel. Also we are probably able to eagerly update the material index in many cases when it's set instead of computing it lazily. That is not implemented in this patch though. The largest part of the patch is making the maximal material index easily available on all the geometry types. Besides that, the material API is slightly replaced and the drawing code now makes use of the updated API. Pull Request: https://projects.blender.org/blender/blender/pulls/133498
This commit is contained in:
@@ -118,6 +118,9 @@ class CurvesGeometryRuntime {
|
||||
/** Normal direction vectors for each evaluated point. */
|
||||
mutable SharedCache<Vector<float3>> evaluated_normal_cache;
|
||||
|
||||
/** The maximum of the "material_index" attribute. */
|
||||
mutable SharedCache<std::optional<int>> max_material_index_cache;
|
||||
|
||||
/** Stores weak references to material data blocks. */
|
||||
std::unique_ptr<bake::BakeMaterialsList> 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<int> 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);
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
* \brief General operations, lookup, etc. for materials.
|
||||
*/
|
||||
|
||||
#include <optional>
|
||||
|
||||
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<int> 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);
|
||||
/**
|
||||
|
||||
@@ -169,6 +169,8 @@ struct MeshRuntime {
|
||||
SharedCache<std::unique_ptr<BVHTree, BVHTreeDeleter>> bvh_cache_loose_edges;
|
||||
SharedCache<std::unique_ptr<BVHTree, BVHTreeDeleter>> bvh_cache_loose_edges_no_hidden;
|
||||
|
||||
SharedCache<std::optional<int>> max_material_index;
|
||||
|
||||
/** Needed in case we need to lazily initialize the mesh. */
|
||||
CustomData_MeshMasks cd_mask_extra = {};
|
||||
|
||||
|
||||
@@ -5485,6 +5485,18 @@ void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], cons
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<int> 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<int>(max_index, nurb->mat_nr);
|
||||
}
|
||||
return max_index;
|
||||
}
|
||||
|
||||
/* **** Depsgraph evaluation **** */
|
||||
|
||||
void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve)
|
||||
|
||||
@@ -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<CurvesGeometry *>(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;
|
||||
|
||||
@@ -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<float3> positions, const float3 &translation)
|
||||
{
|
||||
@@ -1204,6 +1210,17 @@ std::optional<Bounds<float3>> CurvesGeometry::bounds_min_max() const
|
||||
return this->runtime->bounds_cache.data();
|
||||
}
|
||||
|
||||
std::optional<int> CurvesGeometry::material_index_max() const
|
||||
{
|
||||
this->runtime->max_material_index_cache.ensure([&](std::optional<int> &r_max_material_index) {
|
||||
r_max_material_index = blender::bounds::max<int>(
|
||||
this->attributes()
|
||||
.lookup_or_default<int>("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());
|
||||
|
||||
@@ -3222,6 +3222,28 @@ void GreasePencil::count_memory(blender::MemoryCounter &memory) const
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<int> GreasePencil::material_index_max_eval() const
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
std::optional<int> 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<int> 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<const blender::bke::greasepencil::Layer *> GreasePencil::layers() const
|
||||
{
|
||||
BLI_assert(this->runtime != nullptr);
|
||||
|
||||
@@ -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<ID *>(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<int> 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<const Mesh &>(id).material_index_max();
|
||||
case ID_CU_LEGACY:
|
||||
return reinterpret_cast<const Curve &>(id).material_index_max();
|
||||
case ID_CV:
|
||||
return reinterpret_cast<const Curves &>(id).geometry.wrap().material_index_max();
|
||||
case ID_PT:
|
||||
return reinterpret_cast<const PointCloud &>(id).material_index_max();
|
||||
case ID_GP:
|
||||
return reinterpret_cast<const GreasePencil &>(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)
|
||||
|
||||
@@ -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<blender::bke::bake::BakeMaterialsList>(
|
||||
*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<int> Mesh::material_index_max() const
|
||||
{
|
||||
this->runtime->max_material_index.ensure([&](std::optional<int> &value) {
|
||||
if (this->faces_num == 0) {
|
||||
value = std::nullopt;
|
||||
}
|
||||
else {
|
||||
value = blender::bounds::max<int>(
|
||||
this->attributes()
|
||||
.lookup_or_default<int>("material_index", blender::bke::AttrDomain::Face, 0)
|
||||
.varray);
|
||||
}
|
||||
});
|
||||
return this->runtime->max_material_index.data();
|
||||
}
|
||||
|
||||
static void translate_positions(MutableSpan<float3> positions, const float3 &translation)
|
||||
{
|
||||
using namespace blender;
|
||||
|
||||
@@ -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<Mesh *>(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<int2, int2>(
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
@@ -279,6 +279,17 @@ std::optional<blender::Bounds<blender::float3>> PointCloud::bounds_min_max() con
|
||||
return this->runtime->bounds_cache.data();
|
||||
}
|
||||
|
||||
std::optional<int> PointCloud::material_index_max() const
|
||||
{
|
||||
if (this->totpoint == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return blender::bounds::max<int>(
|
||||
this->attributes()
|
||||
.lookup_or_default<int>("material_index", blender::bke::AttrDomain::Point, 0)
|
||||
.varray);
|
||||
}
|
||||
|
||||
void PointCloud::count_memory(blender::MemoryCounter &memory) const
|
||||
{
|
||||
CustomData_count_memory(this->pdata, this->totpoint, memory);
|
||||
|
||||
@@ -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<typename T>
|
||||
return intersect(*a, *b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the maximum value for elements in the array.
|
||||
*/
|
||||
template<typename T> inline std::optional<T> max(const VArray<T> &values)
|
||||
{
|
||||
if (values.is_empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (const std::optional<T> value = values.get_if_single()) {
|
||||
return value;
|
||||
}
|
||||
const VArraySpan<int> values_span = values;
|
||||
return threading::parallel_reduce(
|
||||
values_span.index_range(),
|
||||
2048,
|
||||
std::numeric_limits<T>::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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)) ||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 *>(object), i + 1);
|
||||
if (mat && mat->a < 1.0f) {
|
||||
|
||||
@@ -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<GPUMaterial *> materials(materials_len, nullptr);
|
||||
geom_list = DRW_cache_mesh_surface_shaded_get(ob_ref.object, materials);
|
||||
}
|
||||
|
||||
@@ -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<gpu::Batch *> batches;
|
||||
if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) {
|
||||
|
||||
@@ -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<blender::gpu::Batch *> DRW_cache_object_surface_material_get(
|
||||
Object *ob, const Span<const GPUMaterial *> 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);
|
||||
|
||||
@@ -72,7 +72,6 @@ blender::gpu::Batch *DRW_cache_object_loose_edges_get(Object *ob);
|
||||
blender::Span<blender::gpu::Batch *> DRW_cache_object_surface_material_get(
|
||||
Object *ob, blender::Span<const GPUMaterial *> 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.
|
||||
|
||||
@@ -533,7 +533,7 @@ std::unique_ptr<MeshRenderData> mesh_render_data_create(Object &object,
|
||||
{
|
||||
std::unique_ptr<MeshRenderData> mr = std::make_unique<MeshRenderData>();
|
||||
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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<MeshBatchCache *>(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<MeshBatchCache>(__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<gpu::Batch *>(cache->mat_len, nullptr);
|
||||
cache->tris_per_mat = Array<gpu::IndexBuf *>(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<MeshBatchCache *>(mesh.runtime->batch_cache));
|
||||
}
|
||||
mesh_batch_cache_init(object, mesh);
|
||||
mesh_batch_cache_init(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,20 +92,20 @@ static PointCloudBatchCache *pointcloud_batch_cache_get(PointCloud &pointcloud)
|
||||
return static_cast<PointCloudBatchCache *>(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<gpu::Batch **>(
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_vec_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include <optional>
|
||||
#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<int> material_index_max() const;
|
||||
#endif
|
||||
} Curve;
|
||||
|
||||
#define CURVE_VFONT_ANY(cu) ((cu)->vfont), ((cu)->vfontb), ((cu)->vfonti), ((cu)->vfontbi)
|
||||
|
||||
@@ -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<int> material_index_max_eval() const;
|
||||
|
||||
void count_memory(blender::MemoryCounter &memory) const;
|
||||
|
||||
/* For debugging purposes. */
|
||||
|
||||
@@ -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<blender::float3> &bounds);
|
||||
|
||||
/** Get the largest material index used by the mesh or nullopt if it has no faces. */
|
||||
std::optional<int> 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;
|
||||
|
||||
|
||||
@@ -66,6 +66,9 @@ typedef struct PointCloud {
|
||||
|
||||
std::optional<blender::Bounds<blender::float3>> bounds_min_max() const;
|
||||
|
||||
/** Get the largest material index used by the pointcloud or nullopt if it is empty. */
|
||||
std::optional<int> material_index_max() const;
|
||||
|
||||
void count_memory(blender::MemoryCounter &memory) const;
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user