rntviewer/src/rntviewer.cpp

250 lines
5.6 KiB
C++
Raw Normal View History

2024-07-12 07:53:01 +00:00
// ************************************
// *
// * rntviewer
// *
// * A graphical RNTuple visualizer
// *
// * @author silverweed, 2024
// *
// ***********************************
// #include <ROOT/RNTupleReader.hxx>
// #include <ROOT/RNTuple.hxx>
// #include <TFile.h>
2024-07-10 17:38:16 +00:00
#include <cstdio>
#include <cstdint>
2024-07-18 13:32:32 +00:00
#include <byteswap.h>
2024-07-10 17:38:16 +00:00
#include <chrono>
#ifdef DEBUG
#include <sanitizer/asan_interface.h>
#endif
#include <imgui/imgui.h>
#include <imgui/backends/imgui_impl_glfw.h>
#include <imgui/backends/imgui_impl_opengl3.h>
#include <imgui_club/imgui_memory_editor.h>
2024-07-10 17:38:16 +00:00
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
2024-07-12 09:58:55 +00:00
#include "root/root_inc.h"
2024-07-12 07:53:01 +00:00
#include "root/RMicroFileReader.hxx"
2024-07-11 14:29:44 +00:00
2024-07-10 17:38:16 +00:00
#include "types.h"
#include "defer.hpp"
2024-07-16 15:28:17 +00:00
#include "prof.hpp"
2024-07-10 17:38:16 +00:00
#include "mem.h"
2024-07-11 12:00:43 +00:00
#include "str.h"
#include "rntuple.h"
#include "window.h"
2024-07-11 12:27:19 +00:00
#include "render.h"
2024-07-10 18:11:42 +00:00
#include "app_state.h"
2024-07-10 17:38:16 +00:00
2024-07-11 12:00:43 +00:00
// @Platform
#include "platform_linux.h"
2024-07-10 17:38:16 +00:00
namespace chr = std::chrono;
#include "mem.cpp"
2024-07-11 12:00:43 +00:00
#include "str.cpp"
#include "rntuple.cpp"
2024-07-10 17:38:16 +00:00
#include "render.cpp"
#include "mainloop.cpp"
2024-07-10 19:47:37 +00:00
internal
b8 init_imgui(GLFWwindow* window) {
2024-07-10 17:38:16 +00:00
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void) io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(window, true);
2024-07-11 06:49:20 +00:00
ImGui_ImplOpenGL3_Init("#version 400");
2024-07-10 17:38:16 +00:00
return true;
}
2024-07-11 12:00:43 +00:00
internal
void app_cleanup(App_State &app)
{
os_stop_file_watch(app);
2024-07-16 12:34:51 +00:00
os_unmap_file(app.inspected_file.mem, app.inspected_file.size);
if (app.inspected_file.stream) fclose(app.inspected_file.stream);
2024-07-11 12:00:43 +00:00
}
2024-07-25 15:01:08 +00:00
internal
void print_help(const char *argv0)
{
fprintf(stderr,
"Usage: %s [-t] [-s START] [-l LEN] [-w WIDTH] <ntuple_name> <ntuple_file.root>"
"\n"
"\n\t-t: no graphics, output to terminal"
"\n\t-s: set first displayed byte to START"
"\n\t-l: display LEN bytes (only in terminal mode)"
"\n\t-w: display WIDTH bytes per column"
"\n"
, argv0);
}
struct Cmdline_Args {
b8 print_to_terminal;
b8 show_help_and_exit;
u64 start_addr;
u64 nbytes_displayed;
u16 n_cols;
String8 ntpl_name;
String8 file_name;
};
struct Conv_Res {
u64 num;
b8 error;
};
internal
Conv_Res str_to_u64(String8 s)
{
Conv_Res res {};
for (u64 i = 0; i < s.size; ++i) {
u8 c = s.str[i];
if (c >= '0' && c <= '9') {
res.num *= 10;
res.num += c - '0';
} else {
res.error = true;
break;
}
}
return res;
}
internal
void parse_int_arg(i32 &cur_arg_idx, i32 argc, char **argv, u64 &out)
{
const char *arg = argv[cur_arg_idx];
if (cur_arg_idx < argc - 1) {
String8 nxt_arg = str8_from_c(argv[++cur_arg_idx]);
Conv_Res res = str_to_u64(nxt_arg);
if (res.error)
fprintf(stderr, "Invalid integer after %s flag.\n", arg);
else
out = res.num;
} else {
fprintf(stderr, "Argument required after %s flag.\n", arg);
}
}
internal
Cmdline_Args parse_args(i32 argc, char **argv)
{
Cmdline_Args args {};
if (argc < 3) {
args.show_help_and_exit = true;
return args;
}
// TODO: refactor this probably
for (i32 i = 1; i < argc; ++i) {
String8 arg = str8_from_c(argv[i]);
if (arg.str[0] == '-') {
if (arg.size == 2) {
if (arg.str[1] == 't')
args.print_to_terminal = true;
else if (arg.str[1] == 's')
parse_int_arg(i, argc, argv, args.start_addr);
else if (arg.str[1] == 'l')
parse_int_arg(i, argc, argv, args.nbytes_displayed);
else if (arg.str[1] == 'w') {
u64 n_cols = 0;
parse_int_arg(i, argc, argv, n_cols);
args.n_cols = (u16)n_cols;
}
else
args.show_help_and_exit = true;
} else {
args.show_help_and_exit = true;
}
} else if (args.ntpl_name.size) {
if (args.file_name.size)
args.show_help_and_exit = true;
else
args.file_name = arg;
} else {
args.ntpl_name = arg;
}
}
return args;
}
2024-07-10 17:38:16 +00:00
int main(int argc, char **argv)
{
Thread_Ctx tctx;
tctx_init(tctx);
defer { tctx_release(); };
2024-07-25 15:01:08 +00:00
// Parse cmdline
Cmdline_Args args = parse_args(argc, argv);
if (args.show_help_and_exit || !args.ntpl_name.size || !args.file_name.size) {
print_help(argv[0]);
2024-07-10 17:38:16 +00:00
return 1;
}
// Allocate program memory
Arena *arena = arena_alloc();
if (!arena) {
fprintf(stderr, "Failed to allocate memory\n");
return 1;
}
defer { arena_release(arena); };
// Init imgui and GLFW
GLFWwindow *window = init_glfw(800, 600);
if (!window) {
fprintf(stderr, "Failed to init GLFW\n");
return 1;
}
defer { glfwTerminate(); };
if (!init_imgui(window)) {
fprintf(stderr, "Failed to init Imgui\n");
return 1;
}
2024-07-11 12:00:43 +00:00
App_State app {};
defer { app_cleanup(app); };
// Open and map the file
2024-07-25 15:01:08 +00:00
if (args.file_name.size) {
if (!os_open_and_map_file(args.file_name, app))
return 1;
2024-07-11 12:00:43 +00:00
// Watch file for changes (to adapt the displayed file size - otherwise
// we may try to access invalid memory when the file gets shrunk)
2024-07-25 15:01:08 +00:00
os_start_file_watch(args.file_name, app);
2024-07-10 17:38:16 +00:00
}
2024-07-25 15:01:08 +00:00
app.ntpl_name = args.ntpl_name;
2024-07-18 13:32:32 +00:00
app.tfile_data = get_tfile_data(app.inspected_file);
app.rndata = get_rntuple_data(arena, app.inspected_file, app.ntpl_name);
2024-07-25 15:01:08 +00:00
make_viewer(app, args.n_cols);
app.viewer.base_display_addr = args.start_addr;
if (args.print_to_terminal) {
u64 nbytes_displayed = args.nbytes_displayed;
if (!nbytes_displayed)
nbytes_displayed = 1000;
String8 rendered = render_range_to_string(arena, app, nbytes_displayed, args.n_cols);
printf("%s\n", rendered.c());
return 0;
}
2024-07-10 18:11:42 +00:00
2024-07-11 12:00:43 +00:00
// Start main loop
2024-07-10 18:11:42 +00:00
run_main_loop(window, arena, app);
2024-07-10 17:38:16 +00:00
return 0;
}