Skip to content

Commit 6a9ea2d

Browse files
Merge pull request #3285 from robluo/feature-ap-draw
Feature ap draw
2 parents 07e292e + 84622b8 commit 6a9ea2d

File tree

9 files changed

+284
-45
lines changed

9 files changed

+284
-45
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* @file
3+
* @author Yulang (Robert) Luo
4+
* @date October 2025
5+
* @brief The definitions of the AP Draw Manager class which is used
6+
* to handle graphics updates during analytical placement.
7+
*/
8+
9+
#include "ap_draw_manager.h"
10+
#include "vpr_types.h"
11+
12+
#ifndef NO_GRAPHICS
13+
#include "draw.h"
14+
#include "draw_global.h"
15+
#include "partial_placement.h"
16+
#endif
17+
18+
APDrawManager::APDrawManager(const PartialPlacement& p_placement) {
19+
#ifndef NO_GRAPHICS
20+
// Set the analytical placement reference in draw state
21+
get_draw_state_vars()->set_ap_partial_placement_ref(p_placement);
22+
#else
23+
(void)p_placement;
24+
#endif
25+
}
26+
27+
APDrawManager::~APDrawManager() {
28+
#ifndef NO_GRAPHICS
29+
// Clear the analytical placement reference in draw state
30+
get_draw_state_vars()->clear_ap_partial_placement_ref();
31+
#endif
32+
}
33+
34+
void APDrawManager::update_graphics(unsigned int iteration, enum APDrawType draw_type) {
35+
#ifndef NO_GRAPHICS
36+
std::string msg;
37+
if (draw_type == APDrawType::Solver) {
38+
msg = "Analytical Placement Solver - Iteration: " + std::to_string(iteration);
39+
} else if (draw_type == APDrawType::Legalizer) {
40+
msg = "Analytical Placement Legalizer - Iteration: " + std::to_string(iteration);
41+
} else {
42+
msg = "Analytical Placement";
43+
}
44+
update_screen(ScreenUpdatePriority::MAJOR, msg.c_str(), e_pic_type::ANALYTICAL_PLACEMENT, nullptr);
45+
#else
46+
(void)iteration;
47+
(void)draw_type;
48+
#endif
49+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#pragma once
2+
/**
3+
* @file
4+
* @author Yulang (Robert) Luo
5+
* @date October 2025
6+
* @brief The decalarations of the AP Draw Manager class which is used
7+
* to handle graphics updates during analytical placement.
8+
*/
9+
10+
#include <string>
11+
12+
// Forward declarations
13+
class PartialPlacement;
14+
15+
// Types to indicate the type of drawing operation
16+
enum class APDrawType {
17+
Solver,
18+
Legalizer
19+
};
20+
21+
/**
22+
* @class APDrawManager
23+
* @brief Manages graphics updates during analytical placement operations.
24+
*
25+
* This class provides a clean interface for updating the screen during
26+
* analytical placement without requiring the placement code to be littered
27+
* with NO_GRAPHICS conditional compilation directives.
28+
*/
29+
class APDrawManager {
30+
public:
31+
/**
32+
* @brief Constructor initializes the draw manager with a reference to the
33+
* current partial placement.
34+
*/
35+
explicit APDrawManager(const PartialPlacement& p_placement);
36+
37+
/**
38+
* @brief Destructor cleans up the reference in the draw state.
39+
*/
40+
~APDrawManager();
41+
42+
/**
43+
* @brief Update screen with current analytical placement state
44+
* @param msg A message to display with the update
45+
*/
46+
void update_graphics(unsigned int iteration, enum APDrawType draw_type);
47+
};

vpr/src/analytical_place/global_placer.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <limits>
1212
#include <memory>
1313
#include <vector>
14+
#include "ap_draw_manager.h"
1415
#include "PreClusterTimingManager.h"
1516
#include "analytical_solver.h"
1617
#include "ap_flow_enums.h"
@@ -352,6 +353,10 @@ PartialPlacement SimPLGlobalPlacer::place() {
352353
PartialPlacement best_p_placement(ap_netlist_);
353354
double best_ub_hpwl = std::numeric_limits<double>::max();
354355

356+
// Initialize graphics for analytical placement, setting the reference in
357+
// the draw state.
358+
APDrawManager draw_manager(p_placement);
359+
355360
// Run the global placer.
356361
for (size_t i = 0; i < max_num_iterations_; i++) {
357362
float iter_start_time = runtime_timer.elapsed_sec();
@@ -361,12 +366,18 @@ PartialPlacement SimPLGlobalPlacer::place() {
361366
solver_->solve(i, p_placement);
362367
float solver_end_time = runtime_timer.elapsed_sec();
363368
double lb_hpwl = p_placement.get_hpwl(ap_netlist_);
369+
370+
// Update graphics after analytical solver
371+
draw_manager.update_graphics(i, APDrawType::Solver);
364372

365373
// Run the legalizer.
366374
float legalizer_start_time = runtime_timer.elapsed_sec();
367375
partial_legalizer_->legalize(p_placement);
368376
float legalizer_end_time = runtime_timer.elapsed_sec();
369377
double ub_hpwl = p_placement.get_hpwl(ap_netlist_);
378+
379+
// Update graphics after legalizer
380+
draw_manager.update_graphics(i, APDrawType::Legalizer);
370381

371382
// Perform a timing update
372383
float timing_update_start_time = runtime_timer.elapsed_sec();

vpr/src/base/vpr_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ enum class e_sched_type {
387387
enum class e_pic_type {
388388
NO_PICTURE,
389389
PLACEMENT,
390+
ANALYTICAL_PLACEMENT,
390391
ROUTING
391392
};
392393

vpr/src/draw/draw.cpp

Lines changed: 91 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
#include "draw.h"
1919

2020
#include "draw_interposer.h"
21+
#include "draw_types.h"
2122
#include "timing_info.h"
2223
#include "physical_types.h"
2324

2425
#include "move_utils.h"
26+
#include "vpr_types.h"
2527

2628
#ifndef NO_GRAPHICS
2729

@@ -176,65 +178,71 @@ static void draw_main_canvas(ezgl::renderer* g) {
176178
t_draw_state* draw_state = get_draw_state_vars();
177179

178180
g->set_font_size(14);
181+
if (draw_state->pic_on_screen != e_pic_type::ANALYTICAL_PLACEMENT) {
182+
draw_block_pin_util();
183+
drawplace(g);
184+
draw_internal_draw_subblk(g);
179185

180-
draw_interposer_cuts(g);
186+
draw_interposer_cuts(g);
181187

182-
draw_block_pin_util();
183-
drawplace(g);
184-
draw_internal_draw_subblk(g);
188+
draw_block_pin_util();
189+
drawplace(g);
190+
draw_internal_draw_subblk(g);
185191

186-
if (draw_state->pic_on_screen == e_pic_type::ROUTING) { // ROUTING on screen
192+
if (draw_state->pic_on_screen == e_pic_type::ROUTING) { // ROUTING on screen
187193

188-
draw_rr(g);
194+
draw_rr(g);
189195

190-
if (draw_state->show_nets && draw_state->draw_nets == DRAW_ROUTED_NETS) {
191-
draw_route(ALL_NETS, g);
196+
if (draw_state->show_nets && draw_state->draw_nets == DRAW_ROUTED_NETS) {
197+
draw_route(ALL_NETS, g);
192198

193-
if (draw_state->highlight_fan_in_fan_out) {
194-
draw_route(HIGHLIGHTED, g);
199+
if (draw_state->highlight_fan_in_fan_out) {
200+
draw_route(HIGHLIGHTED, g);
201+
}
195202
}
196-
}
197203

198-
draw_congestion(g);
204+
draw_congestion(g);
199205

200-
draw_routing_costs(g);
206+
draw_routing_costs(g);
201207

202-
draw_router_expansion_costs(g);
208+
draw_router_expansion_costs(g);
203209

204-
draw_routing_util(g);
210+
draw_routing_util(g);
205211

206-
draw_routing_bb(g);
207-
}
212+
draw_routing_bb(g);
213+
}
208214

209-
draw_placement_macros(g);
215+
draw_placement_macros(g);
210216

211217
#ifndef NO_SERVER
212-
if (g_vpr_ctx.server().gate_io.is_running()) {
213-
const ServerContext& server_ctx = g_vpr_ctx.server(); // shortcut
214-
draw_crit_path_elements(server_ctx.crit_paths, server_ctx.crit_path_element_indexes, server_ctx.draw_crit_path_contour, g);
215-
} else {
216-
draw_crit_path(g);
217-
}
218+
if (g_vpr_ctx.server().gate_io.is_running()) {
219+
const ServerContext& server_ctx = g_vpr_ctx.server(); // shortcut
220+
draw_crit_path_elements(server_ctx.crit_paths, server_ctx.crit_path_element_indexes, server_ctx.draw_crit_path_contour, g);
221+
} else {
222+
draw_crit_path(g);
223+
}
218224
#else
219-
draw_crit_path(g);
225+
draw_crit_path(g);
220226
#endif /* NO_SERVER */
221227

222-
draw_logical_connections(g);
228+
draw_logical_connections(g);
223229

224-
draw_selected_pb_flylines(g);
230+
draw_selected_pb_flylines(g);
225231

226-
draw_noc(g);
232+
draw_noc(g);
227233

228-
if (draw_state->draw_partitions) {
229-
highlight_all_regions(g);
230-
draw_constrained_atoms(g);
231-
}
234+
if (draw_state->draw_partitions) {
235+
highlight_all_regions(g);
236+
draw_constrained_atoms(g);
237+
}
232238

233-
if (draw_state->color_map) {
234-
draw_color_map_legend(*draw_state->color_map, g);
235-
draw_state->color_map.reset(); //Free color map in preparation for next redraw
239+
if (draw_state->color_map) {
240+
draw_color_map_legend(*draw_state->color_map, g);
241+
draw_state->color_map.reset(); //Free color map in preparation for next redraw
242+
}
243+
} else {
244+
draw_analytical_place(g);
236245
}
237-
238246
if (draw_state->auto_proceed) {
239247
//Automatically exit the event loop, so user's don't need to manually click proceed
240248

@@ -290,7 +298,7 @@ void update_screen(ScreenUpdatePriority priority,
290298
* value controls whether or not the Proceed button must be clicked to *
291299
* continue. Saves the pic_on_screen_val to allow pan and zoom redraws. */
292300
t_draw_state* draw_state = get_draw_state_vars();
293-
301+
294302
strcpy(draw_state->default_message, msg);
295303

296304
if (!draw_state->show_graphics)
@@ -306,9 +314,23 @@ void update_screen(ScreenUpdatePriority priority,
306314

307315
state_change = true;
308316

317+
if (draw_state->show_graphics) {
318+
if (pic_on_screen_val == e_pic_type::ANALYTICAL_PLACEMENT) {
319+
set_initial_world_ap();
320+
} else {
321+
set_initial_world();
322+
}
323+
}
324+
309325
if (draw_state->pic_on_screen == e_pic_type::NO_PICTURE) {
310326
// Only add the canvas the first time we open graphics
311327
application.add_canvas("MainCanvas", draw_main_canvas, initial_world);
328+
} else {
329+
// TODO: will this ever be null?
330+
auto canvas = application.get_canvas(application.get_main_canvas_id());
331+
if (canvas != nullptr) {
332+
canvas->get_camera().set_world(initial_world);
333+
}
312334
}
313335

314336
draw_state->setup_timing_info = setup_timing_info;
@@ -488,22 +510,43 @@ void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry) {
488510
//Margin beyond edge of the drawn device to extend the visible world
489511
//Setting this to > 0.0 means 'Zoom Fit' leave some fraction of white
490512
//space around the device edges
513+
#else
514+
(void)clb_width;
515+
(void)blk_loc_registry;
516+
#endif /* NO_GRAPHICS */
517+
}
518+
519+
#ifndef NO_GRAPHICS
520+
521+
void set_initial_world() {
491522
constexpr float VISIBLE_MARGIN = 0.01;
523+
t_draw_coords* draw_coords = get_draw_coords_vars();
524+
const DeviceContext& device_ctx = g_vpr_ctx.device();
492525

493526
float draw_width = draw_coords->tile_x[grid.width() - 1] + draw_coords->get_tile_width();
494527
float draw_height = draw_coords->tile_y[grid.height() - 1] + draw_coords->get_tile_width();
495528

496529
initial_world = ezgl::rectangle(
497530
{-VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height},
498531
{(1. + VISIBLE_MARGIN) * draw_width, (1. + VISIBLE_MARGIN)
499-
* draw_height});
500-
#else
501-
(void)clb_width;
502-
(void)blk_loc_registry;
503-
#endif /* NO_GRAPHICS */
532+
* draw_height});
504533
}
505534

506-
#ifndef NO_GRAPHICS
535+
void set_initial_world_ap() {
536+
constexpr float VISIBLE_MARGIN = 0.01f;
537+
const DeviceContext& device_ctx = g_vpr_ctx.device();
538+
539+
const size_t grid_w = device_ctx.grid.width();
540+
const size_t grid_h = device_ctx.grid.height();
541+
542+
543+
float draw_width = static_cast<float>(grid_w);
544+
float draw_height = static_cast<float>(grid_h);
545+
546+
initial_world = ezgl::rectangle(
547+
{-VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height},
548+
{(1.f + VISIBLE_MARGIN) * draw_width, (1.f + VISIBLE_MARGIN) * draw_height});
549+
}
507550

508551
int get_track_num(int inode, const vtr::OffsetMatrix<int>& chanx_track, const vtr::OffsetMatrix<int>& chany_track) {
509552
/* Returns the track number of this routing resource node. */
@@ -629,6 +672,11 @@ void act_on_mouse_press(ezgl::application* app, GdkEventButton* event, double x,
629672
* fanins and fanouts are highlighted when you click on a block *
630673
* attached to them. */
631674

675+
if (get_draw_state_vars()->pic_on_screen == e_pic_type::ANALYTICAL_PLACEMENT) {
676+
// No selection in analytical placement mode yet
677+
return;
678+
}
679+
632680
/* Control + mouse click to select multiple nets. */
633681
if (!(event->state & GDK_CONTROL_MASK))
634682
deselect_all();

vpr/src/draw/draw.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ void update_screen(ScreenUpdatePriority priority,
5555
*/
5656
void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry);
5757

58+
/**
59+
* @brief Set the intial_world ezgl::rectangle for analytical placement
60+
*
61+
* This function sets graphic initial dimensions so there are no gaps between blocks
62+
*/
63+
void set_initial_world_ap();
64+
65+
/**
66+
* @brief Set the intial_world ezgl::rectangle for default
67+
*
68+
* This function sets graphic initial dimensions so there are gaps between blocks
69+
*/
70+
void set_initial_world();
71+
5872
/* Sets the static show_graphics and gr_automode variables to the *
5973
* desired values. They control if graphics are enabled and, if so, *
6074
* how often the user is prompted for input. */

0 commit comments

Comments
 (0)