diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index 82902e4..ee216ef 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -288,7 +288,7 @@ Known local toolchain state: backend-owned resource creation, explicit texture usage flags, command order, render-pass color/depth/stencil clear intent, scissor state, depth state, blend state, texture-slot binding, sampler-state binding, texture-upload byte - counts, texture mip-level counts, mipmap-generation commands, + counts, texture mip-level counts, resource debug labels, mipmap-generation commands, shader-uniform writes, explicit draw descriptor ranges, texture-copy regions, readback bounds, frame-capture sources, destination buffer sizes, and render-target blit regions, records @@ -300,8 +300,8 @@ Known local toolchain state: automation, including render-pass/depth-clear counts, scissor/depth/blend/ shader-uniform/texture-bind/sampler-bind/upload/texture-copy/readback/ frame-capture/blit command and byte totals, trace marker/scope counts, - backend resource creation counts, plus draw descriptor vertex/index totals, - and is covered by + labeled descriptor counts, backend resource creation counts, plus draw + descriptor vertex/index totals, and is covered by `pano_cli_record_render_smoke` plus `pano_cli_record_render_rejects_oversized_target`. - `pano_cli simulate-document-history` exposes `pp_document::DocumentHistory` diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index aeeeb90..cd2448c 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -417,7 +417,8 @@ Status: started. `pp_renderer_api` exists as a headless renderer-neutral target with explicit texture usage flags, texture descriptor, byte-size, viewport, mesh, readback bounds, command context, render device, shader program descriptor, mesh, render target, readback byte-size helpers, -texture mip-level validation, texture-upload/readback command validation, +texture mip-level validation, resource debug-label validation, +texture-upload/readback command validation, mipmap-generation command validation, frame-capture byte-size helpers, frame-capture command validation, render-target blit validation, texture-slot binding validation, blend-state validation, scissor-state validation, @@ -723,10 +724,10 @@ Results: plus malformed payload rejection at the export boundary. - `pp_renderer_api_tests` passed, including shader descriptor validation, PanoPainter shader catalog validation, explicit texture usage validation, - texture mip-level validation, readback byte-size and command-order - validation, texture-upload byte-count validation, mipmap-generation command - validation, trace marker/scope validation, frame-capture byte-size and - command-order validation, + texture mip-level validation, resource debug-label validation, readback + byte-size and command-order validation, texture-upload byte-count validation, + mipmap-generation command validation, trace marker/scope validation, + frame-capture byte-size and command-order validation, render-target blit validation, texture-slot binding validation, blend-state validation, scissor-state validation, render-pass color/depth/stencil clear validation, shader-uniform write validation, draw descriptor/range @@ -834,8 +835,8 @@ Results: texture-usage/texture-bind/sampler-bind/shader-uniform/texture-upload/ mipmap-generation/readback/frame-capture/blit validation plus explicit draw descriptor and texture-copy validation; it creates validated textures, - render targets, shaders, meshes, and readback buffers, then records commands, - trace markers/scopes, render-pass + render targets, shaders, meshes, and readback buffers with validated debug + labels, then records commands, trace markers/scopes, render-pass color/depth/stencil clear intent, scissor state, depth state, blend state, shader uniform writes, texture/sampler binds, draw mesh inputs, explicit draw ranges, texture uploads/mipmap generations/copies/readbacks, frame captures, @@ -843,7 +844,8 @@ Results: does not require a window or GL context. - `pano_cli record-render` exercises that headless recording renderer and emits JSON command counts, resource creation counts, target dimensions, backend - name, trace marker/scope and draw summary, render-pass/depth-clear counts, and draw + name, trace marker/scope and draw summary, labeled descriptor counts, + render-pass/depth-clear counts, and draw descriptor vertex/index totals, scissor/depth/blend-state plus shader-uniform/texture/sampler-bind/upload/texture-copy/readback/ frame-capture/blit command/byte totals for agent automation, with an diff --git a/src/renderer_api/renderer_api.cpp b/src/renderer_api/renderer_api.cpp index c89588c..97ba887 100644 --- a/src/renderer_api/renderer_api.cpp +++ b/src/renderer_api/renderer_api.cpp @@ -131,6 +131,19 @@ pp::foundation::Status validate_texture_usage(TextureUsage usage) noexcept return pp::foundation::Status::success(); } +pp::foundation::Status validate_resource_label(const char* label) noexcept +{ + if (label == nullptr) { + return pp::foundation::Status::invalid_argument("resource label must not be null"); + } + + if (bounded_c_string_length(label, max_resource_label_bytes) > max_resource_label_bytes) { + return pp::foundation::Status::out_of_range("resource label exceeds the configured limit"); + } + + return pp::foundation::Status::success(); +} + pp::foundation::Status validate_texture_desc(TextureDesc desc) noexcept { const auto extent_status = validate_extent(desc.extent); @@ -150,7 +163,12 @@ pp::foundation::Status validate_texture_desc(TextureDesc desc) noexcept return pp::foundation::Status::out_of_range("texture mip level count exceeds the texture extent"); } - return validate_texture_usage(desc.usage); + const auto usage_status = validate_texture_usage(desc.usage); + if (!usage_status.ok()) { + return usage_status; + } + + return validate_resource_label(desc.debug_name); } pp::foundation::Result texture_byte_size(TextureDesc desc) noexcept @@ -417,6 +435,11 @@ pp::foundation::Status validate_sampler_desc(SamplerDesc desc) noexcept pp::foundation::Status validate_mesh_desc(MeshDesc desc) noexcept { + const auto label_status = validate_resource_label(desc.debug_name); + if (!label_status.ok()) { + return label_status; + } + if (desc.vertex_count == 0) { return pp::foundation::Status::invalid_argument("mesh must contain at least one vertex"); } diff --git a/src/renderer_api/renderer_api.h b/src/renderer_api/renderer_api.h index a66fee6..fb81e9e 100644 --- a/src/renderer_api/renderer_api.h +++ b/src/renderer_api/renderer_api.h @@ -17,6 +17,7 @@ constexpr std::uint64_t max_texture_bytes = 1024ULL * 1024ULL * 1024ULL; constexpr std::size_t max_shader_source_bytes = 4ULL * 1024ULL * 1024ULL; constexpr std::size_t max_shader_uniform_bytes = 64ULL * 1024ULL; constexpr std::size_t max_trace_label_bytes = 256; +constexpr std::size_t max_resource_label_bytes = 256; enum class TextureFormat : std::uint8_t { rgba8, @@ -66,6 +67,7 @@ struct TextureDesc { | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination; + const char* debug_name = ""; }; struct ReadbackRegion { @@ -190,6 +192,7 @@ struct MeshDesc { std::uint32_t vertex_count = 0; std::uint32_t index_count = 0; PrimitiveTopology topology = PrimitiveTopology::triangles; + const char* debug_name = ""; }; struct DrawDesc { @@ -322,6 +325,7 @@ public: [[nodiscard]] bool has_texture_usage(TextureUsage usage, TextureUsage required) noexcept; [[nodiscard]] pp::foundation::Status validate_extent(Extent2D extent) noexcept; [[nodiscard]] pp::foundation::Status validate_texture_usage(TextureUsage usage) noexcept; +[[nodiscard]] pp::foundation::Status validate_resource_label(const char* label) noexcept; [[nodiscard]] pp::foundation::Status validate_texture_desc(TextureDesc desc) noexcept; [[nodiscard]] pp::foundation::Status validate_viewport(Viewport viewport, Extent2D target_extent) noexcept; [[nodiscard]] pp::foundation::Status validate_scissor(ScissorRect scissor, Extent2D target_extent) noexcept; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d85bd52..4de1208 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -365,7 +365,7 @@ if(TARGET pano_cli) COMMAND pano_cli record-render --width 32 --height 16) set_tests_properties(pano_cli_record_render_smoke PROPERTIES LABELS "renderer;integration;desktop-fast" - PASS_REGULAR_EXPRESSION "\"backend\":\"recording\".*\"width\":32.*\"height\":16.*\"createdResources\":6.*\"commands\":20.*\"renderPasses\":1.*\"depthClears\":1.*\"stencilClears\":0.*\"drawCommands\":1.*\"drawVertices\":3.*\"drawIndices\":3.*\"scissorCommands\":1.*\"blendCommands\":1.*\"depthCommands\":1.*\"uniformCommands\":1.*\"uniformBytes\":64.*\"bindTextureCommands\":1.*\"bindSamplerCommands\":1.*\"boundTextureBytes\":2048.*\"uploadCommands\":1.*\"uploadBytes\":4.*\"copyCommands\":1.*\"copySourceBytes\":2048.*\"copyDestinationBytes\":2048.*\"readbackCommands\":1.*\"readbackBytes\":2048.*\"captureCommands\":1.*\"captureBytes\":2048.*\"blitCommands\":1.*\"blitSourceBytes\":2048.*\"blitDestinationBytes\":2048.*\"traceMarkers\":1.*\"traceBeginScopes\":1.*\"traceEndScopes\":1") + PASS_REGULAR_EXPRESSION "\"backend\":\"recording\".*\"width\":32.*\"height\":16.*\"createdResources\":6.*\"labeledCommandDescriptors\":10.*\"commands\":20.*\"renderPasses\":1.*\"depthClears\":1.*\"stencilClears\":0.*\"drawCommands\":1.*\"drawVertices\":3.*\"drawIndices\":3.*\"scissorCommands\":1.*\"blendCommands\":1.*\"depthCommands\":1.*\"uniformCommands\":1.*\"uniformBytes\":64.*\"bindTextureCommands\":1.*\"bindSamplerCommands\":1.*\"boundTextureBytes\":2048.*\"uploadCommands\":1.*\"uploadBytes\":4.*\"copyCommands\":1.*\"copySourceBytes\":2048.*\"copyDestinationBytes\":2048.*\"readbackCommands\":1.*\"readbackBytes\":2048.*\"captureCommands\":1.*\"captureBytes\":2048.*\"blitCommands\":1.*\"blitSourceBytes\":2048.*\"blitDestinationBytes\":2048.*\"traceMarkers\":1.*\"traceBeginScopes\":1.*\"traceEndScopes\":1") add_test(NAME pano_cli_record_render_rejects_oversized_target COMMAND "${CMAKE_COMMAND}" diff --git a/tests/renderer_api/renderer_api_tests.cpp b/tests/renderer_api/renderer_api_tests.cpp index 9e6fee9..5170c80 100644 --- a/tests/renderer_api/renderer_api_tests.cpp +++ b/tests/renderer_api/renderer_api_tests.cpp @@ -59,6 +59,7 @@ using pp::renderer::Viewport; using pp::renderer::max_shader_source_bytes; using pp::renderer::max_shader_uniform_bytes; using pp::renderer::max_mip_levels_for_extent; +using pp::renderer::max_resource_label_bytes; using pp::renderer::max_texture_dimension; using pp::renderer::max_texture_slots; using pp::renderer::max_trace_label_bytes; @@ -82,6 +83,7 @@ using pp::renderer::validate_mesh_desc; using pp::renderer::validate_mipmap_generation_desc; using pp::renderer::validate_readback_region; using pp::renderer::validate_render_pass_desc; +using pp::renderer::validate_resource_label; using pp::renderer::validate_sampler_address_mode; using pp::renderer::validate_sampler_desc; using pp::renderer::validate_sampler_filter; @@ -744,6 +746,50 @@ void validates_texture_usage_contract(pp::tests::Harness& h) PP_EXPECT(h, unknown_format.code == StatusCode::invalid_argument); } +void validates_resource_labels(pp::tests::Harness& h) +{ + std::array oversized_label {}; + oversized_label.fill('r'); + oversized_label[max_resource_label_bytes + 1U] = '\0'; + + PP_EXPECT(h, validate_resource_label("").ok()); + PP_EXPECT(h, validate_resource_label("stroke-target").ok()); + PP_EXPECT(h, validate_texture_desc(TextureDesc { + .extent = Extent2D { .width = 4, .height = 4 }, + .format = TextureFormat::rgba8, + .debug_name = "paint-texture", + }) + .ok()); + PP_EXPECT(h, validate_mesh_desc(MeshDesc { + .vertex_count = 3, + .topology = PrimitiveTopology::triangles, + .debug_name = "brush-quad", + }) + .ok()); + + const auto null_label = validate_resource_label(nullptr); + const auto oversized = validate_resource_label(oversized_label.data()); + const auto null_texture_label = validate_texture_desc(TextureDesc { + .extent = Extent2D { .width = 4, .height = 4 }, + .format = TextureFormat::rgba8, + .debug_name = nullptr, + }); + const auto oversized_mesh_label = validate_mesh_desc(MeshDesc { + .vertex_count = 3, + .topology = PrimitiveTopology::triangles, + .debug_name = oversized_label.data(), + }); + + PP_EXPECT(h, !null_label.ok()); + PP_EXPECT(h, null_label.code == StatusCode::invalid_argument); + PP_EXPECT(h, !oversized.ok()); + PP_EXPECT(h, oversized.code == StatusCode::out_of_range); + PP_EXPECT(h, !null_texture_label.ok()); + PP_EXPECT(h, null_texture_label.code == StatusCode::invalid_argument); + PP_EXPECT(h, !oversized_mesh_label.ok()); + PP_EXPECT(h, oversized_mesh_label.code == StatusCode::out_of_range); +} + void validates_mipmap_generation_contract(pp::tests::Harness& h) { const TextureDesc mipmapped_desc { @@ -1469,11 +1515,13 @@ void render_devices_create_validated_resources(pp::tests::Harness& h) .extent = Extent2D { .width = 8, .height = 4 }, .format = TextureFormat::rgba8, .usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination, + .debug_name = "factory-texture", }); const auto target = device.create_render_target(TextureDesc { .extent = Extent2D { .width = 8, .height = 4 }, .format = TextureFormat::rgba8, .usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination, + .debug_name = "factory-target", }); const auto shader = device.create_shader_program(ShaderProgramDesc { .debug_name = "factory-shader", @@ -1484,18 +1532,22 @@ void render_devices_create_validated_resources(pp::tests::Harness& h) .vertex_count = 6, .index_count = 6, .topology = PrimitiveTopology::triangles, + .debug_name = "factory-mesh", }); const auto readback = device.create_readback_buffer(8U * 4U * 4U); PP_EXPECT(h, texture.ok()); PP_EXPECT(h, texture.value()->desc().extent.width == 8U); PP_EXPECT(h, !has_texture_usage(texture.value()->desc().usage, TextureUsage::render_target)); + PP_EXPECT(h, texture.value()->desc().debug_name == std::string_view("factory-texture")); PP_EXPECT(h, target.ok()); PP_EXPECT(h, has_texture_usage(target.value()->color_desc().usage, TextureUsage::render_target)); + PP_EXPECT(h, target.value()->color_desc().debug_name == std::string_view("factory-target")); PP_EXPECT(h, shader.ok()); PP_EXPECT(h, shader.value()->debug_name() == std::string_view("factory-shader")); PP_EXPECT(h, mesh.ok()); PP_EXPECT(h, mesh.value()->desc().index_count == 6U); + PP_EXPECT(h, mesh.value()->desc().debug_name == std::string_view("factory-mesh")); PP_EXPECT(h, readback.ok()); PP_EXPECT(h, readback.value()->size_bytes() == 128U); @@ -1620,6 +1672,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) .extent = Extent2D { .width = 64, .height = 32 }, .format = TextureFormat::rgba8, .usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination, + .debug_name = "recorded-texture", }); RecordingReadbackBuffer readback_buffer(64U * 32U * 4U); const std::array upload_bytes {}; @@ -1627,14 +1680,21 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) .extent = Extent2D { .width = 64, .height = 32 }, .format = TextureFormat::rgba8, .usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination, + .debug_name = "recorded-target", }); RecordingRenderTarget blit_target(TextureDesc { .extent = Extent2D { .width = 64, .height = 32 }, .format = TextureFormat::rgba8, .usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination, + .debug_name = "recorded-blit-target", }); RecordingShaderProgram shader("recorded-shader"); - RecordingMesh mesh(MeshDesc { .vertex_count = 3, .index_count = 3, .topology = PrimitiveTopology::triangles }); + RecordingMesh mesh(MeshDesc { + .vertex_count = 3, + .index_count = 3, + .topology = PrimitiveTopology::triangles, + .debug_name = "recorded-mesh", + }); PP_EXPECT(h, device.backend_name() == std::string_view("recording")); PP_EXPECT(h, device.trace()->begin_scope("renderer", "recorded-frame").ok()); @@ -1693,6 +1753,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) PP_EXPECT(h, recorded_render_command_kind_name(commands[2].kind) == std::string_view("trace_end_scope")); PP_EXPECT(h, commands[3].kind == RecordedRenderCommandKind::begin_render_pass); PP_EXPECT(h, commands[3].target_desc.extent.width == 64U); + PP_EXPECT(h, commands[3].target_desc.debug_name == std::string_view("recorded-target")); PP_EXPECT(h, commands[3].clear_color_enabled); PP_EXPECT(h, commands[3].clear_color.a == 1.0F); PP_EXPECT(h, commands[3].clear_depth_enabled); @@ -1720,6 +1781,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) PP_EXPECT(h, commands[9].kind == RecordedRenderCommandKind::bind_texture); PP_EXPECT(h, commands[9].texture_slot == 1U); PP_EXPECT(h, commands[9].texture_desc.extent.height == 32U); + PP_EXPECT(h, commands[9].texture_desc.debug_name == std::string_view("recorded-texture")); PP_EXPECT(h, recorded_render_command_kind_name(commands[9].kind) == std::string_view("bind_texture")); PP_EXPECT(h, commands[10].kind == RecordedRenderCommandKind::bind_sampler); PP_EXPECT(h, commands[10].sampler_slot == 1U); @@ -1729,6 +1791,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h) PP_EXPECT(h, commands[11].kind == RecordedRenderCommandKind::bind_mesh); PP_EXPECT(h, commands[11].mesh_desc.vertex_count == 3U); PP_EXPECT(h, commands[11].mesh_desc.index_count == 3U); + PP_EXPECT(h, commands[11].mesh_desc.debug_name == std::string_view("recorded-mesh")); PP_EXPECT(h, commands[12].kind == RecordedRenderCommandKind::draw); PP_EXPECT(h, commands[12].mesh_desc.vertex_count == 3U); PP_EXPECT(h, commands[12].mesh_desc.index_count == 3U); @@ -2225,6 +2288,7 @@ int main() pp::tests::Harness harness; harness.run("computes_texture_sizes", computes_texture_sizes); harness.run("validates_texture_usage_contract", validates_texture_usage_contract); + harness.run("validates_resource_labels", validates_resource_labels); harness.run("validates_mipmap_generation_contract", validates_mipmap_generation_contract); harness.run("rejects_invalid_or_excessive_extents", rejects_invalid_or_excessive_extents); harness.run("validates_readback_bounds", validates_readback_bounds); diff --git a/tools/pano_cli/main.cpp b/tools/pano_cli/main.cpp index 9cbb5dc..a9c0352 100644 --- a/tools/pano_cli/main.cpp +++ b/tools/pano_cli/main.cpp @@ -1643,6 +1643,7 @@ pp::foundation::Status parse_simulate_document_edits_args( .extent = pp::renderer::Extent2D { .width = args.width, .height = args.height }, .format = pp::renderer::TextureFormat::rgba8, .usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination, + .debug_name = "record-render-texture", }); if (!render_target_size) { return render_target_size.status(); @@ -2215,11 +2216,13 @@ int record_render(int argc, char** argv) .extent = pp::renderer::Extent2D { .width = args.width, .height = args.height }, .format = pp::renderer::TextureFormat::rgba8, .usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination, + .debug_name = "record-render-target", }); const auto target = device.create_render_target(pp::renderer::TextureDesc { .extent = pp::renderer::Extent2D { .width = args.width, .height = args.height }, .format = pp::renderer::TextureFormat::rgba8, .usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination, + .debug_name = "record-render-blit-target", }); const auto blit_target = device.create_render_target(pp::renderer::TextureDesc { .extent = pp::renderer::Extent2D { .width = args.width, .height = args.height }, @@ -2251,6 +2254,7 @@ int record_render(int argc, char** argv) .vertex_count = 3, .index_count = 3, .topology = pp::renderer::PrimitiveTopology::triangles, + .debug_name = "record-render-mesh", }); if (!texture.ok()) { @@ -2495,10 +2499,17 @@ int record_render(int argc, char** argv) std::uint64_t capture_bytes = 0; std::uint64_t blit_source_bytes = 0; std::uint64_t blit_destination_bytes = 0; + std::size_t labeled_command_descriptors = 0; + const auto count_label = [&labeled_command_descriptors](const char* label) { + if (label != nullptr && label[0] != '\0') { + ++labeled_command_descriptors; + } + }; const auto commands = device.commands(); for (const auto& command : commands) { if (command.kind == pp::renderer::RecordedRenderCommandKind::begin_render_pass) { ++render_passes; + count_label(command.target_desc.debug_name); if (command.clear_depth_enabled) { ++depth_clears; } @@ -2507,6 +2518,7 @@ int record_render(int argc, char** argv) } } else if (command.kind == pp::renderer::RecordedRenderCommandKind::draw) { ++draw_commands; + count_label(command.mesh_desc.debug_name); draw_vertices += command.draw_desc.vertex_count; draw_indices += command.draw_desc.index_count; } else if (command.kind == pp::renderer::RecordedRenderCommandKind::set_scissor) { @@ -2520,27 +2532,39 @@ int record_render(int argc, char** argv) uniform_bytes += command.uniform_bytes; } else if (command.kind == pp::renderer::RecordedRenderCommandKind::bind_texture) { ++bind_texture_commands; + count_label(command.texture_desc.debug_name); const auto bound_bytes = pp::renderer::texture_byte_size(command.texture_desc); if (bound_bytes.ok()) { bound_texture_bytes += bound_bytes.value(); } } else if (command.kind == pp::renderer::RecordedRenderCommandKind::bind_sampler) { ++bind_sampler_commands; + } else if (command.kind == pp::renderer::RecordedRenderCommandKind::bind_mesh) { + count_label(command.mesh_desc.debug_name); + } else if (command.kind == pp::renderer::RecordedRenderCommandKind::generate_mipmaps) { + count_label(command.texture_desc.debug_name); } else if (command.kind == pp::renderer::RecordedRenderCommandKind::upload_texture) { ++upload_commands; + count_label(command.texture_desc.debug_name); upload_bytes += command.upload_bytes; } else if (command.kind == pp::renderer::RecordedRenderCommandKind::copy_texture) { ++copy_commands; + count_label(command.source_desc.debug_name); + count_label(command.destination_desc.debug_name); copy_source_bytes += command.copy_source_bytes; copy_destination_bytes += command.copy_destination_bytes; } else if (command.kind == pp::renderer::RecordedRenderCommandKind::read_texture) { ++readback_commands; + count_label(command.texture_desc.debug_name); readback_bytes += command.readback_bytes; } else if (command.kind == pp::renderer::RecordedRenderCommandKind::capture_frame) { ++capture_commands; + count_label(command.target_desc.debug_name); capture_bytes += command.capture_bytes; } else if (command.kind == pp::renderer::RecordedRenderCommandKind::blit_render_target) { ++blit_commands; + count_label(command.source_desc.debug_name); + count_label(command.destination_desc.debug_name); blit_source_bytes += command.blit_source_bytes; blit_destination_bytes += command.blit_destination_bytes; } else if (command.kind == pp::renderer::RecordedRenderCommandKind::trace_marker) { @@ -2558,6 +2582,7 @@ int record_render(int argc, char** argv) << ",\"height\":" << args.height << ",\"format\":\"rgba8\"}" << ",\"createdResources\":" << created_resources + << ",\"labeledCommandDescriptors\":" << labeled_command_descriptors << ",\"commands\":" << commands.size() << ",\"renderPasses\":" << render_passes << ",\"depthClears\":" << depth_clears