Draw: Use unique handles where possible

Use `unique_handle` where possible.
Add `unique_handle_for_sculpt`.

This also updates `ObjectRef` to make all its properties either
immutable or private.

Pull Request: https://projects.blender.org/blender/blender/pulls/139852
This commit is contained in:
Miguel Pozo
2025-06-16 13:39:21 +02:00
parent ef9187c2c0
commit 60c74cfa20
19 changed files with 51 additions and 75 deletions

View File

@@ -178,7 +178,7 @@ bool SyncModule::sync_sculpt(Object *ob, ObjectHandle &ob_handle, const ObjectRe
return false;
}
ResourceHandle res_handle = inst_.manager->unique_handle(ob_ref);
ResourceHandle res_handle = inst_.manager->unique_handle_for_sculpt(ob_ref);
bool has_motion = false;
MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion);
@@ -235,13 +235,6 @@ bool SyncModule::sync_sculpt(Object *ob, ObjectHandle &ob_handle, const ObjectRe
inst_.volume.object_sync(ob_handle);
}
/* Use a valid bounding box. The pbvh::Tree module already does its own culling, but a valid */
/* bounding box is still needed for directional shadow tile-map bounds computation. */
const Bounds<float3> bounds = bke::pbvh::bounds_get(*bke::object::pbvh_get(*ob_ref.object));
const float3 center = math::midpoint(bounds.min, bounds.max);
const float3 half_extent = bounds.max - center + inflate_bounds;
inst_.manager->update_handle_bounds(res_handle, center, half_extent);
inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);

View File

@@ -123,7 +123,7 @@ class Prepass {
void sculpt_sync(Manager &manager, const ObjectRef &ob_ref)
{
ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
ResourceHandle handle = manager.unique_handle_for_sculpt(ob_ref);
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, SCULPT_BATCH_DEFAULT)) {
mesh_ps_->draw(batch.batch, handle);

View File

@@ -147,7 +147,7 @@ class AttributeViewer : Overlay {
gpu::Batch *batch = DRW_cache_curve_edge_wire_get(&object);
auto &sub = *instance_sub_;
sub.push_constant("ucolor", float4(color));
ResourceHandle res_handle = manager.resource_handle(object.object_to_world());
ResourceHandle res_handle = manager.unique_handle(ob_ref);
sub.draw(batch, res_handle);
break;
}
@@ -214,7 +214,7 @@ class AttributeViewer : Overlay {
gpu::Batch *batch = DRW_cache_curve_edge_wire_viewer_attribute_get(&object);
auto &sub = *curve_sub_;
sub.push_constant("opacity", opacity);
ResourceHandle res_handle = manager.resource_handle(object.object_to_world());
ResourceHandle res_handle = manager.unique_handle(ob_ref);
sub.draw(batch, res_handle);
}
}

View File

@@ -75,7 +75,7 @@ class Facing : Overlay {
!state.is_image_render;
if (use_sculpt_pbvh) {
ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
ResourceHandle handle = manager.unique_handle_for_sculpt(ob_ref);
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, SCULPT_BATCH_DEFAULT)) {
ps_.draw(batch.batch, handle);

View File

@@ -97,7 +97,7 @@ class Fade : Overlay {
!state.is_image_render;
if (use_sculpt_pbvh) {
ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
ResourceHandle handle = manager.unique_handle_for_sculpt(ob_ref);
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, SCULPT_BATCH_DEFAULT)) {
sub.draw(batch.batch, handle);

View File

@@ -87,7 +87,7 @@ class ModeTransfer : Overlay {
const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob_ref.object, state.rv3d) &&
!state.is_image_render;
if (use_sculpt_pbvh) {
ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
ResourceHandle handle = manager.unique_handle_for_sculpt(ob_ref);
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, SCULPT_BATCH_DEFAULT)) {
ps_.draw(batch.batch, handle);

View File

@@ -168,7 +168,7 @@ class Prepass : Overlay {
void sculpt_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res)
{
ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
ResourceHandle handle = manager.unique_handle_for_sculpt(ob_ref);
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, SCULPT_BATCH_DEFAULT)) {
select::ID select_id = use_material_slot_selection_ ?

View File

@@ -210,7 +210,7 @@ class Sculpts : Overlay {
const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob_ref.object, state.rv3d);
if (use_pbvh) {
ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
ResourceHandle handle = manager.unique_handle_for_sculpt(ob_ref);
SculptBatchFeature sculpt_batch_features_ = (show_face_set_ ? SCULPT_BATCH_FACE_SET :
SCULPT_BATCH_DEFAULT) |

View File

@@ -340,14 +340,14 @@ struct Instance : public DrawEngine {
blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(
DRW_object_get_data_for_drawing<Mesh>(*ob));
depth_occlude->draw(geom_faces, manager.resource_handle(ob_ref));
depth_occlude->draw(geom_faces, manager.unique_handle(ob_ref));
return;
}
/* Only sync selectable object once.
* This can happen in retopology mode where there is two sync loop. */
sel_ctx.elem_ranges.lookup_or_add_cb(ob, [&]() {
ResourceHandle res_handle = manager.resource_handle(ob_ref);
ResourceHandle res_handle = manager.unique_handle(ob_ref);
ElemIndexRanges elem_ranges = object_sync(
draw_ctx->v3d, ob, res_handle, sel_ctx.select_mode, sel_ctx.max_index_drawn_len);
sel_ctx.max_index_drawn_len = elem_ranges.total.one_after_last();

View File

@@ -182,16 +182,12 @@ class Instance : public DrawEngine {
if (is_object_data_visible) {
if (object_state.sculpt_pbvh) {
const Bounds<float3> bounds = bke::pbvh::bounds_get(
*bke::object::pbvh_get(*ob_ref.object));
const float3 center = math::midpoint(bounds.min, bounds.max);
const float3 half_extent = bounds.max - center;
ResourceHandle handle = manager.resource_handle(ob_ref, nullptr, &center, &half_extent);
ResourceHandle handle = manager.unique_handle_for_sculpt(ob_ref);
this->sculpt_sync(ob_ref, handle, object_state);
emitter_handle = handle;
}
else if (ob->type == OB_MESH) {
ResourceHandle handle = manager.resource_handle(ob_ref);
ResourceHandle handle = manager.unique_handle(ob_ref);
this->mesh_sync(ob_ref, handle, object_state);
emitter_handle = handle;
}
@@ -381,7 +377,7 @@ class Instance : public DrawEngine {
void pointcloud_sync(Manager &manager, ObjectRef &ob_ref, const ObjectState &object_state)
{
ResourceHandle handle = manager.resource_handle(ob_ref);
ResourceHandle handle = manager.unique_handle(ob_ref);
Material mat = this->get_material(ob_ref, object_state.color_type);
resources_.material_buf.append(mat);
@@ -402,8 +398,8 @@ class Instance : public DrawEngine {
ParticleSystem *psys,
ModifierData *md)
{
/* Skip frustum culling. */
ResourceHandle handle = manager.resource_handle(ob_ref.object->object_to_world());
ResourceHandle handle = manager.resource_handle_for_psys(ob_ref,
ob_ref.object->object_to_world());
Material mat = this->get_material(ob_ref, object_state.color_type, psys->part->omat - 1);
MaterialTexture texture;
@@ -424,8 +420,7 @@ class Instance : public DrawEngine {
void curves_sync(Manager &manager, ObjectRef &ob_ref, const ObjectState &object_state)
{
/* Skip frustum culling. */
ResourceHandle handle = manager.resource_handle(ob_ref.object->object_to_world());
ResourceHandle handle = manager.unique_handle(ob_ref);
Material mat = this->get_material(ob_ref, object_state.color_type);
resources_.material_buf.append(mat);

View File

@@ -220,7 +220,7 @@ void VolumePass::draw_slice_ps(Manager &manager,
ps.push_constant("slice_axis", axis);
ps.push_constant("step_length", step_length);
ps.draw(resources.volume_cube_batch, manager.resource_handle(ob_ref));
ps.draw(resources.volume_cube_batch, manager.unique_handle(ob_ref));
}
void VolumePass::draw_volume_ps(Manager &manager,
@@ -242,7 +242,7 @@ void VolumePass::draw_volume_ps(Manager &manager,
ps.push_constant("step_length", step_length);
ps.push_constant("noise_ofs", float(noise_offset));
ps.draw(resources.volume_cube_batch, manager.resource_handle(ob_ref));
ps.draw(resources.volume_cube_batch, manager.unique_handle(ob_ref));
}
} // namespace blender::workbench

View File

@@ -55,7 +55,7 @@ struct GSet;
struct GPUViewport;
namespace blender::draw {
class TextureFromPool;
struct ObjectRef;
class ObjectRef;
class Manager;
} // namespace blender::draw

View File

@@ -39,7 +39,7 @@ enum eMeshBatchDirtyMode : int8_t;
namespace blender::draw {
struct ObjectRef;
class ObjectRef;
/* -------------------------------------------------------------------- */
/** \name Expose via BKE callbacks

View File

@@ -28,7 +28,7 @@ class Manager;
struct CurvesModule;
struct PointCloudModule;
struct VolumeModule;
struct ObjectRef;
class ObjectRef;
} // namespace blender::draw
/* draw_hair.cc */

View File

@@ -674,22 +674,13 @@ void DupliCacheManager::extract_all(ExtractionGraph &extraction)
namespace blender::draw {
ObjectRef::ObjectRef(DEGObjectIterData &iter_data, Object *ob)
: dupli_object_(iter_data.dupli_object_current),
dupli_parent_(iter_data.dupli_parent),
object(ob)
{
this->dupli_parent_ = iter_data.dupli_parent;
this->dupli_object_ = iter_data.dupli_object_current;
this->object = ob;
/* Set by the first draw-call. */
this->handle = ResourceHandle(0);
}
ObjectRef::ObjectRef(Object *ob)
{
this->dupli_parent_ = nullptr;
this->dupli_object_ = nullptr;
this->object = ob;
/* Set by the first draw-call. */
this->handle = ResourceHandle(0);
}
ObjectRef::ObjectRef(Object *ob) : object(ob) {}
} // namespace blender::draw

View File

@@ -96,22 +96,24 @@ struct ResourceHandleRange {
};
/* TODO(fclem): Move to somewhere more appropriated after cleaning up the header dependencies. */
struct ObjectRef {
class ObjectRef {
friend class Manager;
friend class ObjectKey;
friend DupliCacheManager;
private:
/** Duplicated object that corresponds to the current object. */
DupliObject *dupli_object_;
DupliObject *const dupli_object_ = nullptr;
/** Object that created the dupli-list the current object is part of. */
Object *dupli_parent_;
Object *const dupli_parent_ = nullptr;
/** Unique handle per object ref. */
ResourceHandleRange handle_ = {0, 0};
ResourceHandleRange sculpt_handle_ = {0, 0};
public:
Object *object;
/** Unique handle per object ref. */
ResourceHandleRange handle;
Object *const object;
ObjectRef() = default;
ObjectRef(DEGObjectIterData &iter_data, Object *ob);
ObjectRef(Object *ob);

View File

@@ -172,14 +172,19 @@ uint64_t Manager::fingerprint_get()
return sync_counter_ | (uint64_t(resource_len_) << 32);
}
ResourceHandleRange Manager::resource_handle_for_sculpt(const ObjectRef &ref)
ResourceHandleRange Manager::unique_handle_for_sculpt(const ObjectRef &ref)
{
/* TODO(fclem): Deduplicate with other engine. */
if (ref.sculpt_handle_.handle_first.raw != 0) {
return ref.sculpt_handle_;
}
const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(*ref.object);
const blender::Bounds<float3> bounds = bke::pbvh::bounds_get(pbvh);
const float3 center = math::midpoint(bounds.min, bounds.max);
const float3 half_extent = bounds.max - center;
return resource_handle(ref, nullptr, &center, &half_extent);
/* WORKAROUND: Instead of breaking const correctness everywhere, we only break it for this. */
const_cast<ObjectRef &>(ref).sculpt_handle_ = resource_handle(
ref, nullptr, &center, &half_extent);
return ref.sculpt_handle_;
}
void Manager::compute_visibility(View &view)

View File

@@ -123,11 +123,14 @@ class Manager {
* Create a unique resource handle for the given object.
* Returns the existing handle if it exists.
*/
/* WORKAROUND: Instead of breaking const correctness everywhere, we only break it for this. */
ResourceHandleRange unique_handle(const ObjectRef &ref);
ResourceHandleRange unique_handle_for_sculpt(const ObjectRef &ref);
/**
* Create a new resource handle for the given object.
*/
/* WORKAROUND: Instead of breaking const correctness everywhere, we only break it for this. */
ResourceHandleRange resource_handle(const ObjectRef &ref, float inflate_bounds = 0.0f);
/**
* Create a new resource handle for the given object, but optionally override model matrix and
@@ -156,16 +159,10 @@ class Manager {
*/
ResourceHandle resource_handle_for_psys(const ObjectRef &ref, const float4x4 &model_matrix);
ResourceHandleRange resource_handle_for_sculpt(const ObjectRef &ref);
/** Update the bounds of an already created handle. */
void update_handle_bounds(ResourceHandle handle,
const ObjectRef &ref,
float inflate_bounds = 0.0f);
/** Update the bounds of an already created handle. */
void update_handle_bounds(ResourceHandle handle,
const float3 &bounds_center,
const float3 &bounds_half_extent);
/**
* Populate additional per resource data on demand.
@@ -317,11 +314,11 @@ class Manager {
inline ResourceHandleRange Manager::unique_handle(const ObjectRef &ref)
{
if (ref.handle.handle_first.raw == 0) {
if (ref.handle_.handle_first.raw == 0) {
/* WORKAROUND: Instead of breaking const correctness everywhere, we only break it for this. */
const_cast<ObjectRef &>(ref).handle = resource_handle(ref);
const_cast<ObjectRef &>(ref).handle_ = resource_handle(ref);
}
return ref.handle;
return ref.handle_;
}
inline ResourceHandleRange Manager::resource_handle(const ObjectRef &ref, float inflate_bounds)
@@ -388,13 +385,6 @@ inline void Manager::update_handle_bounds(ResourceHandle handle,
bounds_buf.current()[handle.resource_index()].sync(*ref.object, inflate_bounds);
}
inline void Manager::update_handle_bounds(ResourceHandle handle,
const float3 &bounds_center,
const float3 &bounds_half_extent)
{
bounds_buf.current()[handle.resource_index()].sync(bounds_center, bounds_half_extent);
}
inline void Manager::extract_object_attributes(ResourceHandle handle,
const ObjectRef &ref,
const GPUMaterial *material)

View File

@@ -38,7 +38,7 @@ struct GPULayerAttr;
namespace blender::draw {
struct ObjectRef;
class ObjectRef;
} // namespace blender::draw