[Preview] OpenROAD web server as new GUI#9753
[Preview] OpenROAD web server as new GUI#9753maliberty merged 129 commits intoThe-OpenROAD-Project:masterfrom
Conversation
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Don't draw right/top highlight borders when the instance extends beyond the tile, which was causing yellow lines at every tile seam. Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Add a menu bar (File, View, Tools, Windows, Help) matching the GUI's menu structure. File > Open DB opens a server-side file browser dialog (LIST_DIR WebSocket request) instead of a bare text input. File > Save DB uses the same browser. Menu items are dynamically enabled/disabled based on whether a design is loaded. Allow the web server to start without a loaded design by removing the WEB-0099 error and adding null-chip/null-block guards throughout TileGenerator, Search, and WebSocketSession. The client detects empty bounds and skips map setup, letting the user load a design via the menu. After read_db, the client reloads to run the full init flow. Add shapes_ready to the BOUNDS response so the client can skip the loading overlay on browser reload when shapes are already built. Add keyboard shortcuts for zoom in (z) and zoom out (Shift+Z), with an input field guard to avoid triggering shortcuts while typing. Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant new feature: a web-based GUI for OpenROAD, intended as a modern replacement for the Qt-based GUI. The changes are extensive and well-structured, primarily consisting of two major parts: a substantial refactoring of the gui module to decouple it from Qt, and the implementation of a new web module that provides the server backend and frontend assets.
The refactoring of the gui module is impressive, introducing patterns like a DescriptorRegistry and a factory system for HeatMapDataSource which greatly improve modularity and enable the new web viewer to reuse core visualization logic. The new web module itself is well-architected, using standard and robust technologies like Boost.Asio/Beast for the C++ backend and Leaflet/GoldenLayout for the JavaScript frontend.
My feedback focuses on improving the robustness of the server's request handling and enhancing configuration flexibility for better portability and deployment options. Overall, this is an excellent preview of a major new capability for OpenROAD.
src/pad/test/rdl_route_45.tcl
Outdated
| set def_file [make_result_file "rdl_route_45.def"] | ||
| write_def $def_file | ||
| diff_files $def_file "rdl_route_45.defok" | ||
| web_server -dir /workspace/w6/tools/OpenROAD/src/web/src |
There was a problem hiding this comment.
The path /workspace/w6/tools/OpenROAD/src/web/src is hardcoded. This will likely cause the test to fail on machines with different directory structures. It would be more portable to use a path relative to the test file or the project root, or to use an environment variable. This also applies to src/pad/test/rdl_route_bump_to_bump_only.tcl.
References
- Define tunable parameters as named constants instead of using hardcoded magic numbers. This principle extends to hardcoded paths which should be configurable or relative for portability.
| #include <vector> | ||
|
|
||
| #include "clock_tree_report.h" | ||
| #include "color.h" | ||
| #include "gui/descriptor_registry.h" | ||
| #include "gui/gui.h" | ||
| #include "gui/heatMap.h" | ||
| #include "hierarchy_report.h" | ||
| #include "json_builder.h" | ||
| #include "odb/db.h" | ||
| #include "odb/geom.h" | ||
| #include "tile_generator.h" | ||
| #include "timing_report.h" | ||
| #include "utl/Logger.h" | ||
|
|
||
| namespace web { | ||
|
|
||
| //------------------------------------------------------------------------------ | ||
| // ShapeCollector — a gui::Painter that collects rectangles from | ||
| // descriptor->highlight() calls for use in tile rendering. | ||
| //------------------------------------------------------------------------------ | ||
|
|
||
| class ShapeCollector : public gui::Painter | ||
| { | ||
| public: | ||
| ShapeCollector() : Painter(nullptr, odb::Rect(), 1.0) {} | ||
|
|
||
| std::vector<odb::Rect> rects; | ||
| std::vector<odb::Polygon> polys; | ||
|
|
||
| void drawRect(const odb::Rect& rect, int, int) override | ||
| { | ||
| rects.push_back(rect); | ||
| } |
There was a problem hiding this comment.
The extract_string function is a hand-rolled JSON string parser. It handles common escape sequences but misses some from the JSON standard, such as \b (backspace) and \f (form feed). The default case for an unknown escape sequence is also incorrect, as it just appends the character following the backslash.
While this may work for the current client implementation, it's not fully compliant and could lead to parsing errors with other clients or future changes. Consider using a lightweight JSON library for more robust and maintainable JSON parsing. This would also simplify the request parsing logic in web.cpp.
| try { | ||
| fs::path dir_path | ||
| = req.dir_path.empty() ? fs::current_path() : fs::path(req.dir_path); | ||
| dir_path = fs::canonical(dir_path); | ||
|
|
||
| struct Entry | ||
| { | ||
| std::string name; | ||
| bool is_dir; | ||
| std::uintmax_t size; | ||
| }; | ||
| std::vector<Entry> entries; | ||
|
|
||
| for (const auto& entry : fs::directory_iterator( | ||
| dir_path, fs::directory_options::skip_permission_denied)) { | ||
| const auto& name = entry.path().filename().string(); | ||
| // Skip hidden files/directories. | ||
| if (!name.empty() && name[0] == '.') { | ||
| continue; | ||
| } | ||
| bool is_dir = entry.is_directory(); | ||
| std::uintmax_t size = 0; | ||
| if (!is_dir) { | ||
| std::error_code ec; | ||
| size = entry.file_size(ec); | ||
| if (ec) { | ||
| size = 0; | ||
| } | ||
| } | ||
| entries.push_back({name, is_dir, size}); | ||
| } | ||
|
|
||
| // Sort: directories first, then alphabetical within each group. | ||
| std::ranges::sort(entries, [](const Entry& a, const Entry& b) { | ||
| if (a.is_dir != b.is_dir) { | ||
| return a.is_dir > b.is_dir; | ||
| } | ||
| return a.name < b.name; | ||
| }); | ||
|
|
||
| JsonBuilder builder; | ||
| builder.beginObject(); | ||
| builder.field("path", dir_path.string()); | ||
| builder.field("parent", dir_path.parent_path().string()); | ||
| builder.beginArray("entries"); | ||
| for (const auto& entry : entries) { | ||
| builder.beginObject(); | ||
| builder.field("name", entry.name); | ||
| builder.field("is_dir", entry.is_dir); | ||
| if (!entry.is_dir) { | ||
| builder.field("size", static_cast<int>(entry.size)); | ||
| } | ||
| builder.endObject(); | ||
| } | ||
| builder.endArray(); | ||
| builder.endObject(); | ||
|
|
||
| const std::string& json = builder.str(); | ||
| resp.payload.assign(json.begin(), json.end()); | ||
| } catch (const std::exception& e) { | ||
| resp.type = 2; | ||
| std::string err = std::string("list_dir error: ") + e.what(); | ||
| resp.payload.assign(err.begin(), err.end()); | ||
| } | ||
| return resp; | ||
| } |
There was a problem hiding this comment.
The list_dir handler allows browsing the server's filesystem starting from the current working directory. While this is convenient for a local desktop tool, it could become a security concern if OpenROAD is ever run as a shared or remote service, as it might expose more of the filesystem than intended. For future hardening, you might consider adding an option to restrict file browsing to a specific root directory or a set of allowed directories.
| auto const address = net::ip::make_address("127.0.0.1"); | ||
| uint16_t const port = 8080; | ||
| int const num_threads = 32; |
There was a problem hiding this comment.
The server address, port, and number of threads are hardcoded. It would be beneficial to make these configurable, for example, through arguments to the web_server Tcl command or environment variables. This would improve flexibility, allowing users to avoid port conflicts or bind to different interfaces (e.g., 0.0.0.0 to allow remote access).
References
- Define tunable parameters as named constants instead of using hardcoded magic numbers. Server address, port, and number of threads are tunable parameters that should not be hardcoded.
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
|
I'm going to merge this to keep this PR from getting bigger but the module remains not feature complete. I'm glad to have people try it and give feedback, issues, or PRs. |
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
07be495
into
The-OpenROAD-Project:master
…t-staging/web [Preview] OpenROAD web server as new GUI
This is initial work toward replacing the Qt gui with OpenROAD acting as a web server and using a standard browser as the display. It is known to be incomplete but is far enough along for feedback on the general approach.
Especially I'd like feedback on
To run it you load a design as usual and then