45 std::ostringstream oss;
46 oss << std::fixed << std::setprecision(2);
47 oss <<
"batch_stats{";
85 math::vec3 average_position(0.0f);
88 if (!instance.world_transform_ptr)
94 const auto& transform = *instance.world_transform_ptr;
95 math::vec3 position(transform[3][0], transform[3][1], transform[3][2]);
96 average_position += position;
102 math::vec3 distance_vec = average_position - camera_pos;
125 if (!key.is_valid() || !instance.
is_valid())
130 auto start_time = std::chrono::high_resolution_clock::now();
132 auto&
batch_group = get_or_create_batch_group(key);
135 if (profiling_enabled_)
137 auto end_time = std::chrono::high_resolution_clock::now();
138 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
151 if (batch_groups_.empty())
156 auto start_time = std::chrono::high_resolution_clock::now();
159 prepared_batches_.clear();
160 prepared_batches_.reserve(batch_groups_.size());
163 for (
auto& [key, group] : batch_groups_)
165 if (group.is_valid())
167 prepared_batches_.push_back(&group);
174 split_large_batches(context);
184 sort_batches(context);
191 auto end_time = std::chrono::high_resolution_clock::now();
192 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
199 return prepared_batches_;
204 batch_groups_.clear();
205 prepared_batches_.clear();
216 return batch_groups_.size();
222 for (
const auto& [key, group] : batch_groups_)
224 total += group.instances.size();
231 return !batch_groups_.empty();
236 max_instances_per_batch_ = max_instances;
241 profiling_enabled_ = enabled;
246 std::sort(prepared_batches_.begin(), prepared_batches_.end(),
250 if (a->key.material_ptr.get() != b->key.material_ptr.get())
252 return a->key.material_ptr.get() < b->key.material_ptr.get();
256 if (
a->key.mesh_ptr.get() !=
b->key.mesh_ptr.get())
258 return a->key.mesh_ptr.get() < b->key.mesh_ptr.get();
262 if (
a->key.lod_index !=
b->key.lod_index)
264 return a->key.lod_index < b->key.lod_index;
268 if (
a->key.submesh_index !=
b->key.submesh_index)
270 return a->key.submesh_index < b->key.submesh_index;
276 return a->camera_distance > b->camera_distance;
283void batch_collector::split_large_batches(
const submit_context& context)
285 if (context.max_instances_per_batch == 0)
290 batch_list_t new_batches;
292 for (
auto* batch : prepared_batches_)
294 if (batch->instances.size() <= context.max_instances_per_batch)
296 new_batches.push_back(batch);
301 stats_.split_batches++;
303 size_t instances_processed = 0;
304 const size_t total_instances = batch->instances.size();
306 while (instances_processed < total_instances)
308 size_t instances_in_split = std::min(
309 static_cast<size_t>(context.max_instances_per_batch),
310 total_instances - instances_processed
314 auto split_batch = std::make_unique<batch_group>(batch->key);
315 split_batch->is_split_batch =
true;
316 split_batch->camera_distance = batch->camera_distance;
319 for (
size_t i = 0;
i < instances_in_split; ++
i)
321 split_batch->add_instance(batch->instances[instances_processed + i]);
324 instances_processed += instances_in_split;
329 new_batches.push_back(batch);
334 prepared_batches_ = std::move(new_batches);
337void batch_collector::calculate_camera_distances(
const math::vec3& camera_pos)
339 for (
auto* batch : prepared_batches_)
341 batch->calculate_camera_distance(camera_pos);
345void batch_collector::update_statistics()
347 stats_.total_batches =
static_cast<uint32_t
>(prepared_batches_.size());
348 stats_.total_instances =
static_cast<uint32_t
>(get_instance_count());
351 stats_.instance_buffer_memory_used = 0;
352 for (
const auto* batch : prepared_batches_)
354 stats_.instance_buffer_memory_used += batch->get_gpu_memory_size();
358 stats_.calculate_derived_stats();
361auto batch_collector::get_or_create_batch_group(
const batch_key& key) -> batch_group&
363 auto it = batch_groups_.find(key);
364 if (it != batch_groups_.end())
370 auto [inserted_it, success] = batch_groups_.emplace(key, batch_group(key));
371 return inserted_it->second;
375bool batch_collector::enable_static_mesh_batching_ =
true;
377auto batch_collector::is_static_mesh_batching_enabled() ->
bool
379 return enable_static_mesh_batching_;
382void batch_collector::set_static_mesh_batching_enabled(
bool enabled)
384 enable_static_mesh_batching_ = enabled;
void clear()
Clear all collected data and reset for next frame.
std::vector< batch_group * > batch_list_t
auto get_stats() const -> const batch_stats &
Get current statistics.
batch_collector()
Default constructor.
void set_max_instances_per_batch(uint32_t max_instances)
Set maximum instances per batch.
auto get_batch_count() const -> size_t
Get number of collected batches.
void prepare_batches(const submit_context &context)
Prepare batches for rendering (sort, split, optimize)
void set_profiling_enabled(bool enabled)
Enable or disable performance profiling.
auto has_batches() const -> bool
Check if any batches have been collected.
void collect_renderable(const batch_key &key, const batch_instance &instance)
Collect a renderable object for batching.
auto get_prepared_batches() const -> const batch_list_t &
Get prepared batches for rendering.
auto get_instance_count() const -> size_t
Get total number of instances collected.
auto size() const -> size_t
Get number of instances.
auto empty() const -> bool
Check if collection is empty.
auto get_gpu_memory_size() const -> size_t
Get memory size required for GPU data.
void add_instance(const batch_instance &instance)
Add an instance to the collection.
Hash specialization for batch_key to enable use in std::unordered_map.
A group of instances that can be rendered together.
auto is_valid() const -> bool
Check if this batch is valid for rendering.
auto get_gpu_memory_size() const -> size_t
Get memory size required for GPU data.
void add_instance(const batch_instance &instance)
Add an instance to this batch.
batch_instance_collection instances
Collection of instances in this batch.
void calculate_camera_distance(const math::vec3 &camera_pos)
Calculate distance from camera for sorting.
batch_group()=default
Default constructor.
batch_key key
Key identifying this batch (mesh, material, LOD, submesh)
float camera_distance
Distance from camera (for sorting)
Instance data for a single object in a batch.
auto is_valid() const -> bool
Check if this instance has valid data.
Batch key structure for grouping compatible draw calls.
auto is_valid() const -> bool
Check if this batch key is valid.
Statistics for batch collection and rendering performance.
uint32_t total_instances
Total number of instances across all batches.
uint32_t split_batches
Number of batches that were split due to size limits.
float average_batch_size
Average number of instances per batch.
float batching_efficiency
Batching efficiency (instances / batches)
size_t instance_buffer_memory_used
Memory used for instance buffers (bytes)
float preparation_time_ms
Time spent preparing batches (milliseconds)
auto to_string() const -> std::string
Get string representation for debugging.
void calculate_derived_stats()
Calculate derived statistics (efficiency, averages)
uint32_t draw_calls_saved
Number of draw calls saved by batching (instances - batches)
void reset()
Reset all statistics to zero.
float submission_time_ms
Time spent submitting batches (milliseconds)
uint32_t total_batches
Total number of batches created.
float collection_time_ms
Time spent collecting instances (milliseconds)
Context information for batch submission.
uint32_t max_instances_per_batch
Maximum instances per batch (0 = no limit)
math::vec3 camera_position
Camera position for distance-based sorting.
bool enable_distance_sorting
Enable distance-based sorting for transparency.
bool enable_profiling
Enable performance profiling.