Skip to content

Record Replay

This example records the DRP2 frame stream from an offscreen view and replays it

Preview

Run And Adapt

Commands below assume a Datoviz source checkout and start at the repository root. Use your configured build environment; Python routes additionally require local bindings.

Route Availability Command or action
C Canonical native source just example-c runtime/record_replay (build and run), or rerun ./build/examples/c/runtime/record_replay
Python No verified adaptation on this page Start from the C source.
Browser Native only DVZR app recording and replay use native runtime capture plumbing

Use this example as capability or integration evidence, not as a minimal copy-paste template. Start from the nearest supported, copy-safe example and add this feature after verifying the linked API reference.

What To Look For

The recorded scene is a five-point visual with explicit position, color, and diameter arrays. The app records the backend-neutral rendering commands produced for the frame, not a video or editable scene file. It writes the DVZR recording plus two PNGs, one captured from the original offscreen view and one captured from the replay view; compare those images to verify that replaying the command stream reproduces the same rendered frame.

This experimental workflow is useful when you need visual regression artifacts or a compact trace for renderer debugging without keeping the original app process alive.

Source

/*
 * Copyright (c) 2021 Cyrille Rossant and contributors. All rights reserved.
 * Licensed under the MIT license. See LICENSE file in the project root for details.
 * SPDX-License-Identifier: MIT
 */

/* record_replay - This example records the DRP2 frame stream from an offscreen view and replays it
 * from a DVZR recording.
 *
 * What to look for: the recorded scene is a five-point visual with explicit position, color, and
 * diameter arrays. The app records the backend-neutral rendering commands produced for the frame,
 * not a video or editable scene file. It writes the DVZR recording plus two PNGs, one captured from
 * the original offscreen view and one captured from the replay view; compare those images to verify
 * that replaying the command stream reproduces the same rendered frame.
 *
 * This experimental workflow is useful when you need visual regression artifacts or a compact trace
 * for renderer debugging without keeping the original app process alive.
 *
 * Scenario: runtime_record_replay
 * Style: runtime, native app
 *
 * Build:  just example-c runtime/record_replay
 * Run:    ./build/examples/c/runtime/record_replay
 */



/*************************************************************************************************/
/*  Includes                                                                                     */
/*************************************************************************************************/

#include <stdint.h>

#include "datoviz/app.h"
#include "datoviz/canvas/enums.h"
#include "datoviz/scene.h"
#include "example_common.h"
#include "example_style.h"



/*************************************************************************************************/
/*  Constants                                                                                    */
/*************************************************************************************************/

#define WIDTH  EXAMPLE_OUTPUT_WIDTH
#define HEIGHT EXAMPLE_OUTPUT_HEIGHT
#define POINT_COUNT 5u



/*************************************************************************************************/
/*  Helpers                                                                                      */
/*************************************************************************************************/

/**
 * Build the retained scene that will be recorded.
 *
 * @param scene target scene
 * @return figure containing the scene, or NULL
 */
static DvzFigure* _record_replay_figure(DvzScene* scene)
{
    if (scene == NULL)
        return NULL;

    DvzFigure* figure = dvz_figure(scene, WIDTH, HEIGHT, 0);
    DvzPanel* panel = figure != NULL ? dvz_panel_full(figure) : NULL;
    DvzVisual* point = dvz_point(scene, 0);
    if (figure == NULL || panel == NULL || point == NULL)
        return NULL;
    example_graphite_cyan_set_panel_background(panel);

    vec3 positions[POINT_COUNT] = {
        {-0.70f, -0.45f, 0.0f}, {-0.35f, +0.20f, 0.0f}, {+0.00f, -0.05f, 0.0f},
        {+0.35f, +0.42f, 0.0f}, {+0.70f, -0.25f, 0.0f},
    };
    DvzColor colors[POINT_COUNT] = {
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_PRIMARY),
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_SECONDARY),
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_WARNING),
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_MINOR_TICK),
    };
    float diameters[POINT_COUNT] = {34.0f, 46.0f, 58.0f, 46.0f, 34.0f};
    DvzVisualDataUpdate updates[] = {
        {.attr_name = "position", .data = positions, .item_count = POINT_COUNT},
        {.attr_name = "color", .data = colors, .item_count = POINT_COUNT},
        {.attr_name = "diameter_px", .data = diameters, .item_count = POINT_COUNT},
    };
    if (dvz_visual_set_data_many(point, updates, 3) != 0)
        return NULL;
    if (dvz_panel_add_visual(panel, point, NULL) != 0)
        return NULL;
    return figure;
}



/*************************************************************************************************/
/*  Main                                                                                         */
/*************************************************************************************************/

int main(int argc, char** argv)
{
    (void)argc;

    int ret = 1;
    DvzScene* scene = NULL;
    DvzApp* app = NULL;

    char recording_path[512] = {0};
    char original_png[512] = {0};
    char replay_png[512] = {0};
    example_outpath(argv[0], "record_replay.dvzr", recording_path, sizeof(recording_path));
    example_outpath(argv[0], "record_replay_original.png", original_png, sizeof(original_png));
    example_outpath(argv[0], "record_replay_replay.png", replay_png, sizeof(replay_png));

    scene = dvz_scene();
    EXAMPLE_CHECK(scene != NULL, "dvz_scene() failed");
    DvzFigure* figure = _record_replay_figure(scene);
    EXAMPLE_CHECK(figure != NULL, "failed to build recorded figure");

    app = dvz_app(scene);
    EXAMPLE_CHECK(app != NULL, "dvz_app() failed (no GPU?)");

    DvzView* record_view = dvz_view_offscreen(app, figure, WIDTH, HEIGHT);
    EXAMPLE_CHECK(record_view != NULL, "dvz_view_offscreen(record) failed");
    EXAMPLE_CHECK(
        dvz_view_record_start(record_view, recording_path) == 0, "dvz_view_record_start() failed");
    EXAMPLE_CHECK(
        dvz_view_render_once(record_view) == DVZ_CANVAS_FRAME_READY, "record render failed");
    EXAMPLE_CHECK(dvz_view_record_stop(record_view) == 0, "dvz_view_record_stop() failed");
    EXAMPLE_CHECK(
        dvz_view_capture_png(record_view, original_png) == 0, "failed to capture recorded frame");

    DvzFigure* replay_figure = dvz_figure(scene, WIDTH, HEIGHT, 0);
    EXAMPLE_CHECK(replay_figure != NULL, "dvz_figure(replay) failed");
    DvzView* replay_view = dvz_view_offscreen(app, replay_figure, WIDTH, HEIGHT);
    EXAMPLE_CHECK(replay_view != NULL, "dvz_view_offscreen(replay) failed");
    EXAMPLE_CHECK(
        dvz_view_replay_start(replay_view, recording_path) == 0, "dvz_view_replay_start() failed");
    dvz_view_replay_set_paced(replay_view, false);
    EXAMPLE_CHECK(dvz_view_replay_frame_count(replay_view) > 0, "replay has no frames");
    EXAMPLE_CHECK(
        dvz_view_render_once(replay_view) == DVZ_CANVAS_FRAME_READY, "replay render failed");
    EXAMPLE_CHECK(dvz_view_replay_stop(replay_view) == 0, "dvz_view_replay_stop() failed");
    EXAMPLE_CHECK(
        dvz_view_capture_png(replay_view, replay_png) == 0, "failed to capture replay frame");

    dvz_fprintf(stdout, "record_replay: wrote %s\n", recording_path);
    dvz_fprintf(stdout, "record_replay: wrote %s\n", original_png);
    dvz_fprintf(stdout, "record_replay: wrote %s\n", replay_png);
    ret = 0;

cleanup:
    if (app != NULL)
        dvz_app_destroy(app);
    if (scene != NULL)
        dvz_scene_destroy(scene);
    return ret;
}
Example details
  • ID: runtime_record_replay
  • Category: runtime
  • Lane: runtime
  • Status: experimental
  • Source: examples/c/runtime/record_replay.c
  • Approved adaptation starter: no
  • Browser support: Native only
  • Browser note: DVZR app recording and replay use native runtime capture plumbing
  • Browser capability tags: native-capture
  • Validation: smoke+capture

Data

Field Value
kind synthetic