109 auto vk_buffer = std::dynamic_pointer_cast<VKBuffer>(
buffer);
112 "NetworkGeometryProcessor requires VKBuffer");
117 if (!binding.network || !binding.network->is_enabled()) {
119 "Network '{}' disabled, skipping upload",
name);
123 const auto*
chain = binding.network->get_operator_chain().get();
124 const bool has_chain =
chain && !
chain->empty();
128 binding.network->get_operator());
130 if (primary_op && primary_op->supports_incremental_upload()) {
132 const size_t total =
static_cast<size_t>(primary_op->get_vertex_count())
142 if (gpu_data.vertex_data.empty() || gpu_data.vertex_count == 0) {
143 if (vk_buffer->is_host_visible())
146 vk_buffer->set_vertex_layout(*gpu_data.layout);
150 size_t total = gpu_data.vertex_data.size();
152 if (
total > vk_buffer->get_size_bytes()) {
153 vk_buffer->resize(
static_cast<size_t>(
static_cast<float>(
total) * 1.5F),
false);
160 vk_buffer->set_vertex_layout(*gpu_data.layout);
162 if (
auto ngb = std::dynamic_pointer_cast<NetworkGeometryBuffer>(
buffer);
164 ngb->update_render_runs(primary_op->topology_runs());
167 binding.last_total_bytes =
total;
170 "Uploaded {} vertices from network '{}' ({} bytes)",
176 std::span<const uint8_t> bytes;
177 size_t vertex_count {};
178 std::optional<Kakshya::VertexLayout> layout;
182 std::vector<SliceData> slices;
183 slices.reserve(1 +
chain->size());
186 slices.push_back({ .bytes = primary.vertex_data,
187 .vertex_count = primary.vertex_count,
188 .layout = primary.layout,
190 binding.network->get_operator()) });
192 for (
const auto& op :
chain->operators()) {
195 slices.push_back({ .bytes = {}, .vertex_count = 0, .layout = std::nullopt, .op =
nullptr });
199 if (!gfx->participates_in_rendering())
202 slices.push_back({ .bytes = gfx->get_vertex_data(),
203 .vertex_count = gfx->get_vertex_count(),
204 .layout = gfx->get_vertex_layout(),
208 size_t total_bytes = 0;
209 for (
const auto& s : slices)
210 total_bytes += s.bytes.size();
212 if (total_bytes == 0) {
213 if (vk_buffer->is_host_visible())
216 vk_buffer->set_vertex_layout(*primary.layout);
220 bool chain_gfx_dirty =
false;
221 bool needs_full_restore =
false;
222 for (
const auto& op :
chain->operators()) {
223 if (op && op->demands_full_vertex_restore())
224 needs_full_restore =
true;
227 if (gfx && gfx->participates_in_rendering() && gfx->is_vertex_data_dirty())
228 chain_gfx_dirty =
true;
231 if (!needs_full_restore && !chain_gfx_dirty && primary.layout.has_value()
234 primary.layout->stride_bytes, binding, vk_buffer, total_bytes,
name)) {
238 if (total_bytes > vk_buffer->get_size_bytes()) {
239 vk_buffer->resize(
static_cast<size_t>(
static_cast<float>(total_bytes) * 1.5F),
false);
243 size_t byte_offset = 0;
244 for (
const auto& s : slices) {
245 if (!s.bytes.empty())
247 byte_offset += s.bytes.size();
253 size_t aggregate_vertices = 0;
254 for (
const auto& s : slices)
255 aggregate_vertices += s.vertex_count;
257 for (
auto& slice : std::views::reverse(slices)) {
259 auto aggregate = *slice.layout;
260 aggregate.vertex_count =
static_cast<uint32_t
>(aggregate_vertices);
261 vk_buffer->set_vertex_layout(aggregate);
266 auto ngb = std::dynamic_pointer_cast<NetworkGeometryBuffer>(
buffer);
269 for (
size_t i = 0; i < slices.size(); ++i) {
270 const auto& s = slices[i];
271 const uint32_t stride = s.layout ? s.layout->stride_bytes
272 : (slices[0].layout ? slices[0].layout->stride_bytes : 0);
273 const uint32_t vert_offset = stride > 0
274 ?
static_cast<uint32_t
>(byte_offset / stride)
277 std::vector<Portal::Graphics::DrawRun> runs;
279 for (
auto run : s.op->topology_runs()) {
280 if (
run.vertex_count == 0)
282 run.vertex_offset += vert_offset;
287 ngb->update_chain_render_range(i, vert_offset,
288 static_cast<uint32_t
>(s.vertex_count), s.layout, std::move(runs));
290 byte_offset += s.bytes.size();
294 binding.last_total_bytes = total_bytes;
297 "Uploaded {} bytes ({} slices) from network '{}'",
298 total_bytes, slices.size(),
name);