-
Notifications
You must be signed in to change notification settings - Fork 428
Feature ap draw #3285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Feature ap draw #3285
Changes from all commits
5319888
dc6e76a
7f6933a
3c0381b
5b2a7c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/** | ||
* @file | ||
* @author Yulang (Robert) Luo | ||
* @date October 2025 | ||
* @brief The definitions of the Analytical Draw Manager class which is used | ||
* to handle graphics updates during analytical placement. | ||
*/ | ||
|
||
#include "analytical_draw_manager.h" | ||
#include "vpr_types.h" | ||
|
||
#ifndef NO_GRAPHICS | ||
#include "draw.h" | ||
#include "draw_global.h" | ||
#include "partial_placement.h" | ||
#endif | ||
|
||
AnalyticalDrawManager::AnalyticalDrawManager(const PartialPlacement& p_placement) { | ||
#ifndef NO_GRAPHICS | ||
// Set the analytical placement reference in draw state | ||
get_draw_state_vars()->set_ap_partial_placement_ref(p_placement); | ||
#else | ||
(void)p_placement; | ||
#endif | ||
} | ||
|
||
AnalyticalDrawManager::~AnalyticalDrawManager() { | ||
#ifndef NO_GRAPHICS | ||
// Clear the analytical placement reference in draw state | ||
get_draw_state_vars()->clear_ap_partial_placement_ref(); | ||
#endif | ||
} | ||
|
||
void AnalyticalDrawManager::update_graphics(const std::string& msg) { | ||
#ifndef NO_GRAPHICS | ||
update_screen(ScreenUpdatePriority::MAJOR, msg.c_str(), ANALYTICAL_PLACEMENT, nullptr); | ||
#else | ||
(void)msg; | ||
#endif | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#pragma once | ||
/** | ||
* @file | ||
* @author Yulang (Robert) Luo | ||
* @date October 2025 | ||
* @brief The decalarations of the Analytical Draw Manager class which is used | ||
* to handle graphics updates during analytical placement. | ||
*/ | ||
|
||
#include <string> | ||
|
||
// Forward declarations | ||
class PartialPlacement; | ||
|
||
/** | ||
* @class AnalyticalDrawManager | ||
* @brief Manages graphics updates during analytical placement operations. | ||
* | ||
* This class provides a clean interface for updating the screen during | ||
* analytical placement without requiring the placement code to be littered | ||
* with NO_GRAPHICS conditional compilation directives. | ||
*/ | ||
class AnalyticalDrawManager { | ||
public: | ||
/** | ||
* @brief Constructor initializes the draw manager with a reference to the | ||
* current partial placement. | ||
*/ | ||
explicit AnalyticalDrawManager(const PartialPlacement& p_placement); | ||
|
||
/** | ||
* @brief Destructor cleans up the reference in the draw state. | ||
*/ | ||
~AnalyticalDrawManager(); | ||
|
||
/** | ||
* @brief Update screen with current analytical placement state | ||
* @param msg A message to display with the update | ||
*/ | ||
void update_graphics(const std::string& msg); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,10 +16,12 @@ | |
#include <cstring> | ||
#include <cmath> | ||
#include "draw.h" | ||
#include "draw_types.h" | ||
#include "timing_info.h" | ||
#include "physical_types.h" | ||
|
||
#include "move_utils.h" | ||
#include "vpr_types.h" | ||
|
||
#ifndef NO_GRAPHICS | ||
|
||
|
@@ -174,63 +176,65 @@ static void draw_main_canvas(ezgl::renderer* g) { | |
t_draw_state* draw_state = get_draw_state_vars(); | ||
|
||
g->set_font_size(14); | ||
if (draw_state->pic_on_screen != ANALYTICAL_PLACEMENT) { | ||
draw_block_pin_util(); | ||
drawplace(g); | ||
draw_internal_draw_subblk(g); | ||
|
||
draw_block_pin_util(); | ||
drawplace(g); | ||
draw_internal_draw_subblk(g); | ||
if (draw_state->pic_on_screen == ROUTING) { // ROUTING on screen | ||
|
||
if (draw_state->pic_on_screen == ROUTING) { // ROUTING on screen | ||
draw_rr(g); | ||
|
||
draw_rr(g); | ||
if (draw_state->show_nets && draw_state->draw_nets == DRAW_ROUTED_NETS) { | ||
draw_route(ALL_NETS, g); | ||
|
||
if (draw_state->show_nets && draw_state->draw_nets == DRAW_ROUTED_NETS) { | ||
draw_route(ALL_NETS, g); | ||
|
||
if (draw_state->highlight_fan_in_fan_out) { | ||
draw_route(HIGHLIGHTED, g); | ||
if (draw_state->highlight_fan_in_fan_out) { | ||
draw_route(HIGHLIGHTED, g); | ||
} | ||
} | ||
} | ||
|
||
draw_congestion(g); | ||
draw_congestion(g); | ||
|
||
draw_routing_costs(g); | ||
draw_routing_costs(g); | ||
|
||
draw_router_expansion_costs(g); | ||
draw_router_expansion_costs(g); | ||
|
||
draw_routing_util(g); | ||
draw_routing_util(g); | ||
|
||
draw_routing_bb(g); | ||
} | ||
draw_routing_bb(g); | ||
} | ||
|
||
draw_placement_macros(g); | ||
draw_placement_macros(g); | ||
|
||
#ifndef NO_SERVER | ||
if (g_vpr_ctx.server().gate_io.is_running()) { | ||
const ServerContext& server_ctx = g_vpr_ctx.server(); // shortcut | ||
draw_crit_path_elements(server_ctx.crit_paths, server_ctx.crit_path_element_indexes, server_ctx.draw_crit_path_contour, g); | ||
} else { | ||
draw_crit_path(g); | ||
} | ||
if (g_vpr_ctx.server().gate_io.is_running()) { | ||
const ServerContext& server_ctx = g_vpr_ctx.server(); // shortcut | ||
draw_crit_path_elements(server_ctx.crit_paths, server_ctx.crit_path_element_indexes, server_ctx.draw_crit_path_contour, g); | ||
} else { | ||
draw_crit_path(g); | ||
} | ||
#else | ||
draw_crit_path(g); | ||
draw_crit_path(g); | ||
#endif /* NO_SERVER */ | ||
|
||
draw_logical_connections(g); | ||
draw_logical_connections(g); | ||
|
||
draw_selected_pb_flylines(g); | ||
draw_selected_pb_flylines(g); | ||
|
||
draw_noc(g); | ||
draw_noc(g); | ||
|
||
if (draw_state->draw_partitions) { | ||
highlight_all_regions(g); | ||
draw_constrained_atoms(g); | ||
} | ||
if (draw_state->draw_partitions) { | ||
highlight_all_regions(g); | ||
draw_constrained_atoms(g); | ||
} | ||
|
||
if (draw_state->color_map) { | ||
draw_color_map_legend(*draw_state->color_map, g); | ||
draw_state->color_map.reset(); //Free color map in preparation for next redraw | ||
if (draw_state->color_map) { | ||
draw_color_map_legend(*draw_state->color_map, g); | ||
draw_state->color_map.reset(); //Free color map in preparation for next redraw | ||
} | ||
} else { | ||
draw_analytical_place(g); | ||
} | ||
|
||
if (draw_state->auto_proceed) { | ||
//Automatically exit the event loop, so user's don't need to manually click proceed | ||
|
||
|
@@ -281,7 +285,7 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type | |
* value controls whether or not the Proceed button must be clicked to * | ||
* continue. Saves the pic_on_screen_val to allow pan and zoom redraws. */ | ||
t_draw_state* draw_state = get_draw_state_vars(); | ||
|
||
strcpy(draw_state->default_message, msg); | ||
|
||
if (!draw_state->show_graphics) | ||
|
@@ -297,10 +301,23 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type | |
|
||
state_change = true; | ||
|
||
if (draw_state->show_graphics) { | ||
if (pic_on_screen_val == ANALYTICAL_PLACEMENT) { | ||
set_initial_world_ap(); | ||
} else { | ||
set_initial_world(); | ||
} | ||
} | ||
|
||
if (draw_state->pic_on_screen == NO_PICTURE) { | ||
// Only add the canvas the first time we open graphics | ||
application.add_canvas("MainCanvas", draw_main_canvas, | ||
initial_world); | ||
application.add_canvas("MainCanvas", draw_main_canvas, initial_world); | ||
} else { | ||
// TODO: will this ever be null? | ||
auto canvas = application.get_canvas(application.get_main_canvas_id()); | ||
if (canvas != nullptr) { | ||
canvas->get_camera().set_world(initial_world); | ||
} | ||
} | ||
|
||
draw_state->setup_timing_info = setup_timing_info; | ||
|
@@ -482,7 +499,18 @@ void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry) { | |
//Margin beyond edge of the drawn device to extend the visible world | ||
//Setting this to > 0.0 means 'Zoom Fit' leave some fraction of white | ||
//space around the device edges | ||
#else | ||
(void)clb_width; | ||
(void)blk_loc_registry; | ||
#endif /* NO_GRAPHICS */ | ||
} | ||
|
||
#ifndef NO_GRAPHICS | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would be careful with this ifdef. You are not defining these functions when graphics is disabled. However, they are still available in the header file... I would put the ifdef inside of the method and have the method do nothing when graphics is not enabled. |
||
|
||
void set_initial_world() { | ||
constexpr float VISIBLE_MARGIN = 0.01; | ||
t_draw_coords* draw_coords = get_draw_coords_vars(); | ||
const DeviceContext& device_ctx = g_vpr_ctx.device(); | ||
|
||
float draw_width = draw_coords->tile_x[device_ctx.grid.width() - 1] | ||
+ draw_coords->get_tile_width(); | ||
|
@@ -492,14 +520,24 @@ void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry) { | |
initial_world = ezgl::rectangle( | ||
{-VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height}, | ||
{(1. + VISIBLE_MARGIN) * draw_width, (1. + VISIBLE_MARGIN) | ||
* draw_height}); | ||
#else | ||
(void)clb_width; | ||
(void)blk_loc_registry; | ||
#endif /* NO_GRAPHICS */ | ||
* draw_height}); | ||
} | ||
|
||
#ifndef NO_GRAPHICS | ||
void set_initial_world_ap() { | ||
constexpr float VISIBLE_MARGIN = 0.01f; | ||
const DeviceContext& device_ctx = g_vpr_ctx.device(); | ||
|
||
const size_t grid_w = device_ctx.grid.width(); | ||
const size_t grid_h = device_ctx.grid.height(); | ||
|
||
|
||
float draw_width = static_cast<float>(grid_w); | ||
float draw_height = static_cast<float>(grid_h); | ||
|
||
initial_world = ezgl::rectangle( | ||
{-VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height}, | ||
{(1.f + VISIBLE_MARGIN) * draw_width, (1.f + VISIBLE_MARGIN) * draw_height}); | ||
} | ||
|
||
int get_track_num(int inode, const vtr::OffsetMatrix<int>& chanx_track, const vtr::OffsetMatrix<int>& chany_track) { | ||
/* Returns the track number of this routing resource node. */ | ||
|
@@ -625,6 +663,11 @@ void act_on_mouse_press(ezgl::application* app, GdkEventButton* event, double x, | |
* fanins and fanouts are highlighted when you click on a block * | ||
* attached to them. */ | ||
|
||
if (get_draw_state_vars()->pic_on_screen == ANALYTICAL_PLACEMENT) { | ||
// No selection in analytical placement mode yet | ||
return; | ||
} | ||
|
||
/* Control + mouse click to select multiple nets. */ | ||
if (!(event->state & GDK_CONTROL_MASK)) | ||
deselect_all(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,6 +52,20 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type | |
*/ | ||
void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry); | ||
|
||
/** | ||
* @brief Set the intial_world ezgl::rectangle for analytical placement | ||
* | ||
* This function sets graphic initial dimensions so there are no gaps between blocks | ||
*/ | ||
void set_initial_world_ap(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These new methods need comments. Also see my prior comments on their definitions. |
||
|
||
/** | ||
* @brief Set the intial_world ezgl::rectangle for default | ||
* | ||
* This function sets graphic initial dimensions so there are gaps between blocks | ||
*/ | ||
void set_initial_world(); | ||
|
||
/* Sets the static show_graphics and gr_automode variables to the * | ||
* desired values. They control if graphics are enabled and, if so, * | ||
* how often the user is prompted for input. */ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to keep the drawing code pretty isolated from the AP code as much as possible. In the future, we may decide to make another global placer as well, and I would like to avoid duplicate code.
I suggest that you create a new class in the
analytical_place
directory for drawing. Something like APDrawManager or something. This class would then have methods for drawing the pre and post legalized placements. This would remove the global accesses from this method. The global placer can then take this as an argument, which it can use to draw whenever it needs.