Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions vpr/src/analytical_place/ap_draw_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @file
* @author Yulang (Robert) Luo
* @date October 2025
* @brief The definitions of the AP Draw Manager class which is used
* to handle graphics updates during analytical placement.
*/

#include "ap_draw_manager.h"
#include "vpr_types.h"

#ifndef NO_GRAPHICS
#include "draw.h"
#include "draw_global.h"
#include "partial_placement.h"
#endif

APDrawManager::APDrawManager(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
}

APDrawManager::~APDrawManager() {
#ifndef NO_GRAPHICS
// Clear the analytical placement reference in draw state
get_draw_state_vars()->clear_ap_partial_placement_ref();
#endif
}

void APDrawManager::update_graphics(unsigned int iteration, enum APDrawType draw_type) {
#ifndef NO_GRAPHICS
std::string msg;
if (draw_type == APDrawType::Solver) {
msg = "Analytical Placement Solver - Iteration: " + std::to_string(iteration);
} else if (draw_type == APDrawType::Legalizer) {
msg = "Analytical Placement Legalizer - Iteration: " + std::to_string(iteration);
} else {
msg = "Analytical Placement";
}
update_screen(ScreenUpdatePriority::MAJOR, msg.c_str(), e_pic_type::ANALYTICAL_PLACEMENT, nullptr);
#else
(void)iteration;
(void)draw_type;
#endif
}
47 changes: 47 additions & 0 deletions vpr/src/analytical_place/ap_draw_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once
/**
* @file
* @author Yulang (Robert) Luo
* @date October 2025
* @brief The decalarations of the AP Draw Manager class which is used
* to handle graphics updates during analytical placement.
*/

#include <string>

// Forward declarations
class PartialPlacement;

// Types to indicate the type of drawing operation
enum class APDrawType {
Solver,
Legalizer
};

/**
* @class APDrawManager
* @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 APDrawManager {
public:
/**
* @brief Constructor initializes the draw manager with a reference to the
* current partial placement.
*/
explicit APDrawManager(const PartialPlacement& p_placement);

/**
* @brief Destructor cleans up the reference in the draw state.
*/
~APDrawManager();

/**
* @brief Update screen with current analytical placement state
* @param msg A message to display with the update
*/
void update_graphics(unsigned int iteration, enum APDrawType draw_type);
};
11 changes: 11 additions & 0 deletions vpr/src/analytical_place/global_placer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <limits>
#include <memory>
#include <vector>
#include "ap_draw_manager.h"
#include "PreClusterTimingManager.h"
#include "analytical_solver.h"
#include "ap_flow_enums.h"
Expand Down Expand Up @@ -352,6 +353,10 @@ PartialPlacement SimPLGlobalPlacer::place() {
PartialPlacement best_p_placement(ap_netlist_);
double best_ub_hpwl = std::numeric_limits<double>::max();

// Initialize graphics for analytical placement, setting the reference in
// the draw state.
APDrawManager draw_manager(p_placement);

// Run the global placer.
for (size_t i = 0; i < max_num_iterations_; i++) {
float iter_start_time = runtime_timer.elapsed_sec();
Expand All @@ -361,12 +366,18 @@ PartialPlacement SimPLGlobalPlacer::place() {
solver_->solve(i, p_placement);
float solver_end_time = runtime_timer.elapsed_sec();
double lb_hpwl = p_placement.get_hpwl(ap_netlist_);

// Update graphics after analytical solver
draw_manager.update_graphics(i, APDrawType::Solver);

// Run the legalizer.
float legalizer_start_time = runtime_timer.elapsed_sec();
partial_legalizer_->legalize(p_placement);
float legalizer_end_time = runtime_timer.elapsed_sec();
double ub_hpwl = p_placement.get_hpwl(ap_netlist_);

// Update graphics after legalizer
draw_manager.update_graphics(i, APDrawType::Legalizer);

// Perform a timing update
float timing_update_start_time = runtime_timer.elapsed_sec();
Expand Down
1 change: 1 addition & 0 deletions vpr/src/base/vpr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ enum class e_sched_type {
enum class e_pic_type {
NO_PICTURE,
PLACEMENT,
ANALYTICAL_PLACEMENT,
ROUTING
};

Expand Down
134 changes: 91 additions & 43 deletions vpr/src/draw/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
#include "draw.h"

#include "draw_interposer.h"
#include "draw_types.h"
#include "timing_info.h"
#include "physical_types.h"

#include "move_utils.h"
#include "vpr_types.h"

#ifndef NO_GRAPHICS

Expand Down Expand Up @@ -176,65 +178,71 @@ 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 != e_pic_type::ANALYTICAL_PLACEMENT) {
draw_block_pin_util();
drawplace(g);
draw_internal_draw_subblk(g);

draw_interposer_cuts(g);
draw_interposer_cuts(g);

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 == e_pic_type::ROUTING) { // ROUTING on screen
if (draw_state->pic_on_screen == e_pic_type::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

Expand Down Expand Up @@ -288,7 +296,7 @@ void update_screen(ScreenUpdatePriority priority,
* 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)
Expand All @@ -304,9 +312,23 @@ void update_screen(ScreenUpdatePriority priority,

state_change = true;

if (draw_state->show_graphics) {
if (pic_on_screen_val == e_pic_type::ANALYTICAL_PLACEMENT) {
set_initial_world_ap();
} else {
set_initial_world();
}
}

if (draw_state->pic_on_screen == e_pic_type::NO_PICTURE) {
// Only add the canvas the first time we open graphics
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;
Expand Down Expand Up @@ -486,7 +508,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

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();
Expand All @@ -496,14 +529,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. */
Expand Down Expand Up @@ -629,6 +672,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 == e_pic_type::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();
Expand Down
14 changes: 14 additions & 0 deletions vpr/src/draw/draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ void update_screen(ScreenUpdatePriority priority,
*/
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();

/**
* @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. */
Expand Down
Loading