Expose recording renderer through pano cli

This commit is contained in:
2026-06-02 09:47:09 +02:00
parent 1d44036933
commit b82cc1e4bd
5 changed files with 138 additions and 0 deletions

View File

@@ -7,6 +7,7 @@
#include "foundation/result.h"
#include "paint/stroke.h"
#include "paint/stroke_script.h"
#include "renderer_api/recording_renderer.h"
#include "ui_core/layout_xml.h"
#include <cstdint>
@@ -52,6 +53,11 @@ struct SimulateStrokeScriptArgs {
std::string path;
};
struct RecordRenderArgs {
std::uint32_t width = 64;
std::uint32_t height = 32;
};
void print_error(std::string_view command, std::string_view message)
{
std::cout << "{\"ok\":false,\"command\":\"" << command
@@ -109,6 +115,7 @@ void print_help()
<< " inspect-project --path FILE\n"
<< " load-project --path FILE\n"
<< " parse-layout --path FILE\n"
<< " record-render [--width N] [--height N]\n"
<< " simulate-stroke --x1 N --y1 N --x2 N --y2 N [--spacing N]\n"
<< " simulate-stroke-script --path FILE\n"
<< " --help\n";
@@ -624,6 +631,121 @@ int simulate_stroke_script(int argc, char** argv)
return 0;
}
pp::foundation::Status parse_record_render_args(int argc, char** argv, RecordRenderArgs& args)
{
for (int i = 2; i < argc; ++i) {
const std::string_view key(argv[i]);
if (key == "--width" || key == "--height") {
if (i + 1 >= argc) {
return pp::foundation::Status::invalid_argument("missing value for option");
}
const auto value = pp::foundation::parse_u32(argv[++i]);
if (!value) {
return value.status();
}
if (key == "--width") {
args.width = value.value();
} else {
args.height = value.value();
}
} else {
return pp::foundation::Status::invalid_argument("unknown option");
}
}
if (args.width == 0 || args.height == 0) {
return pp::foundation::Status::invalid_argument("width and height must be greater than zero");
}
return pp::foundation::Status::success();
}
int record_render(int argc, char** argv)
{
RecordRenderArgs args;
const auto status = parse_record_render_args(argc, argv, args);
if (!status.ok()) {
print_error("record-render", status.message);
return 2;
}
pp::renderer::RecordingRenderDevice device;
pp::renderer::RecordingRenderTarget target(pp::renderer::TextureDesc {
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
.format = pp::renderer::TextureFormat::rgba8,
.render_target = true,
});
pp::renderer::RecordingShaderProgram shader("pano-cli-record-render");
pp::renderer::RecordingMesh mesh(pp::renderer::MeshDesc {
.vertex_count = 3,
.index_count = 0,
.topology = pp::renderer::PrimitiveTopology::triangles,
});
device.trace()->marker("renderer", "pano_cli_record_render");
auto& context = device.immediate_context();
const auto begin_status = context.begin_render_pass(
target,
pp::renderer::ClearColor { .r = 0.0F, .g = 0.0F, .b = 0.0F, .a = 1.0F });
if (!begin_status.ok()) {
print_error("record-render", begin_status.message);
return 2;
}
const auto viewport_status = context.set_viewport(
pp::renderer::Viewport { .x = 0, .y = 0, .width = args.width, .height = args.height });
if (!viewport_status.ok()) {
print_error("record-render", viewport_status.message);
return 2;
}
const auto shader_status = context.bind_shader(shader);
const auto mesh_status = context.bind_mesh(mesh);
const auto draw_status = context.draw();
context.end_render_pass();
if (!shader_status.ok()) {
print_error("record-render", shader_status.message);
return 2;
}
if (!mesh_status.ok()) {
print_error("record-render", mesh_status.message);
return 2;
}
if (!draw_status.ok()) {
print_error("record-render", draw_status.message);
return 2;
}
std::size_t draw_commands = 0;
std::size_t trace_markers = 0;
const auto commands = device.commands();
for (const auto& command : commands) {
if (command.kind == pp::renderer::RecordedRenderCommandKind::draw) {
++draw_commands;
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::trace_marker) {
++trace_markers;
}
}
std::cout << "{\"ok\":true,\"command\":\"record-render\""
<< ",\"backend\":\"" << device.backend_name() << "\""
<< ",\"target\":{\"width\":" << args.width
<< ",\"height\":" << args.height
<< ",\"format\":\"rgba8\"}"
<< ",\"commands\":" << commands.size()
<< ",\"drawCommands\":" << draw_commands
<< ",\"traceMarkers\":" << trace_markers
<< ",\"first\":\""
<< pp::renderer::recorded_render_command_kind_name(commands.front().kind)
<< "\",\"last\":\""
<< pp::renderer::recorded_render_command_kind_name(commands.back().kind)
<< "\"}\n";
return 0;
}
pp::foundation::Status parse_layout_args(int argc, char** argv, ParseLayoutArgs& args)
{
for (int i = 2; i < argc; ++i) {
@@ -721,6 +843,10 @@ int main(int argc, char** argv)
return parse_layout(argc, argv);
}
if (command == "record-render") {
return record_render(argc, argv);
}
print_error(command, "unknown command");
return 2;
}