Skip to content
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

3D FPGA block select fix, and rr-node display fix for 3D FPGAs #2380

Merged
merged 11 commits into from
Sep 11, 2023
117 changes: 66 additions & 51 deletions vpr/src/draw/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -983,10 +983,66 @@ static void draw_router_expansion_costs(ezgl::renderer* g) {
}
}

/**
* @brief Highlights the block that was clicked on, looking from the top layer downwards for 3D devices (chooses the block on the top visible layer for overlapping blocks)
* It highlights the block green, as well as its fanin and fanout to blue and red respectively by updating the draw_state variables responsible for holding the
* color of the block as well as its fanout and fanin.
* @param x
* @param y
*/
static void highlight_blocks(double x, double y) {
Meet-Patel2580 marked this conversation as resolved.
Show resolved Hide resolved
t_draw_coords* draw_coords = get_draw_coords_vars();
t_draw_state* draw_state = get_draw_state_vars();

char msg[vtr::bufsize];
ClusterBlockId clb_index = get_cluster_block_id_from_xy_loc(x, y);
if (clb_index == EMPTY_BLOCK_ID || clb_index == ClusterBlockId::INVALID()) {
return; /* Nothing was found on any layer*/
}

auto& cluster_ctx = g_vpr_ctx.clustering();
auto& place_ctx = g_vpr_ctx.placement();

VTR_ASSERT(clb_index != EMPTY_BLOCK_ID);

ezgl::rectangle clb_bbox = draw_coords->get_absolute_clb_bbox(clb_index, cluster_ctx.clb_nlist.block_type(clb_index));
// note: this will clear the selected sub-block if show_blk_internal is 0,
// or if it doesn't find anything
ezgl::point2d point_in_clb = ezgl::point2d(x, y) - clb_bbox.bottom_left();
highlight_sub_block(point_in_clb, clb_index,
cluster_ctx.clb_nlist.block_pb(clb_index));

if (get_selected_sub_block_info().has_selection()) {
t_pb* selected_subblock = get_selected_sub_block_info().get_selected_pb();
sprintf(msg, "sub-block %s (a \"%s\") selected",
selected_subblock->name,
selected_subblock->pb_graph_node->pb_type->name);
} else {
/* Highlight block and fan-in/fan-outs. */
draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index),
clb_index);
sprintf(msg, "Block #%zu (%s) at (%d, %d) selected.", size_t(clb_index),
cluster_ctx.clb_nlist.block_name(clb_index).c_str(),
place_ctx.block_locs[clb_index].loc.x,
place_ctx.block_locs[clb_index].loc.y);
}

//If manual moves is activated, then user can select block from the grid.
if (draw_state->manual_moves_state.manual_move_enabled) {
draw_state->manual_moves_state.user_highlighted_block = true;
if (!draw_state->manual_moves_state.manual_move_window_is_open) {
draw_manual_moves_window(std::to_string(size_t(clb_index)));
}
}

application.update_message(msg);
application.refresh_drawing();
return;
}

ClusterBlockId get_cluster_block_id_from_xy_loc(double x, double y) {
t_draw_coords* draw_coords = get_draw_coords_vars();
t_draw_state* draw_state = get_draw_state_vars();
ClusterBlockId clb_index = EMPTY_BLOCK_ID;
auto& device_ctx = g_vpr_ctx.device();
auto& cluster_ctx = g_vpr_ctx.clustering();
Expand All @@ -995,8 +1051,11 @@ static void highlight_blocks(double x, double y) {
/// determine block ///
ezgl::rectangle clb_bbox;

//iterate over grid z (layers) first, so we draw from bottom to top die. This makes partial transparency of layers draw properly.
for (int layer_num = 0; layer_num < device_ctx.grid.get_num_layers(); layer_num++) {
//iterate over grid z (layers) first. Start search of the block at the top layer to prioritize highlighting of blocks at higher levels during overlapping of layers.
for (int layer_num = device_ctx.grid.get_num_layers() - 1; layer_num >= 0; layer_num--) {
if (!draw_state->draw_layer_display[layer_num].visible) {
continue; /* Don't check for blocks on non-visible layers*/
}
// iterate over grid x
for (int i = 0; i < (int)device_ctx.grid.width(); ++i) {
if (draw_coords->tile_x[i] > x) {
Expand All @@ -1015,61 +1074,17 @@ static void highlight_blocks(double x, double y) {
clb_bbox = draw_coords->get_absolute_clb_bbox(clb_index,
cluster_ctx.clb_nlist.block_type(clb_index));
if (clb_bbox.contains({x, y})) {
break;
return clb_index; // we've found the clb
} else {
clb_index = EMPTY_BLOCK_ID;
}
}
}
if (clb_index != EMPTY_BLOCK_ID) {
break; // we've found something
}
}
if (clb_index != EMPTY_BLOCK_ID) {
break; // we've found something
}
}

if (clb_index == EMPTY_BLOCK_ID || clb_index == ClusterBlockId::INVALID()) {
//Nothing found
return;
}

VTR_ASSERT(clb_index != EMPTY_BLOCK_ID);

// note: this will clear the selected sub-block if show_blk_internal is 0,
// or if it doesn't find anything
ezgl::point2d point_in_clb = ezgl::point2d(x, y) - clb_bbox.bottom_left();
highlight_sub_block(point_in_clb, clb_index,
cluster_ctx.clb_nlist.block_pb(clb_index));

if (get_selected_sub_block_info().has_selection()) {
t_pb* selected_subblock = get_selected_sub_block_info().get_selected_pb();
sprintf(msg, "sub-block %s (a \"%s\") selected",
selected_subblock->name,
selected_subblock->pb_graph_node->pb_type->name);
} else {
/* Highlight block and fan-in/fan-outs. */
draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index),
clb_index);
sprintf(msg, "Block #%zu (%s) at (%d, %d) selected.", size_t(clb_index),
cluster_ctx.clb_nlist.block_name(clb_index).c_str(),
place_ctx.block_locs[clb_index].loc.x,
place_ctx.block_locs[clb_index].loc.y);
}

//If manual moves is activated, then user can select block from the grid.
t_draw_state* draw_state = get_draw_state_vars();
if (draw_state->manual_moves_state.manual_move_enabled) {
draw_state->manual_moves_state.user_highlighted_block = true;
if (!draw_state->manual_moves_state.manual_move_window_is_open) {
draw_manual_moves_window(std::to_string(size_t(clb_index)));
}
}

application.update_message(msg);
application.refresh_drawing();
}
// Searched all layers and found no clb at specified location, returning clb_index = EMPTY_BLOCK_ID.
return clb_index;
}

static void setup_default_ezgl_callbacks(ezgl::application* app) {
Expand Down Expand Up @@ -1450,8 +1465,8 @@ t_draw_layer_display get_element_visibility_and_transparency(int src_layer, int
element_visibility.visible = true;
bool cross_layer_enabled = draw_state->cross_layer_display.visible;

//To only show primitive nets that are connected to currently active layers on the screen
if (!draw_state->draw_layer_display[sink_layer].visible || (!cross_layer_enabled && src_layer != sink_layer)) {
//To only show elements (net flylines,noc links,etc...) that are connected to currently active layers on the screen
if (!draw_state->draw_layer_display[sink_layer].visible || !draw_state->draw_layer_display[src_layer].visible || (!cross_layer_enabled && src_layer != sink_layer)) {
element_visibility.visible = false; /* Don't Draw */
}

Expand Down
11 changes: 11 additions & 0 deletions vpr/src/draw/draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,17 @@ bool rgb_is_same(ezgl::color color1, ezgl::color color2);
*/
t_draw_layer_display get_element_visibility_and_transparency(int src_layer, int sink_layer);

/**
* @brief takes in the x and y coordinates of where the user clicked on the screen and returns the corresponding clusterBlockId that represents
* the clb clicked upon by the user on a currently visible FPGA layer. Search for the clb begins from the top layer to ensure to
Meet-Patel2580 marked this conversation as resolved.
Show resolved Hide resolved
* return the clusterBlockId of a clb on a higher layer during instances of overlap between clb blocks.
* @param x
Meet-Patel2580 marked this conversation as resolved.
Show resolved Hide resolved
* @param y
* @return returns the ClusterBlockId of the clb at the specified (x,y) location as seen by looking downwards from the top of a 3D FPGA.
* Chooses the clb on the top visible layer if there are overlapping blocks. Returns EMPTY_BLOCK_ID (-1) otherwise,if clb is not found on any visible layer.
*/
ClusterBlockId get_cluster_block_id_from_xy_loc(double x, double y);

#endif /* NO_GRAPHICS */

#endif /* DRAW_H */
36 changes: 23 additions & 13 deletions vpr/src/draw/draw_basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,25 +653,31 @@ void draw_partial_route(const std::vector<RRNodeId>& rr_nodes_to_draw, ezgl::ren
auto rr_type = rr_graph.node_type(inode);

RRNodeId prev_node = rr_nodes_to_draw[i - 1];
RRNodeId prev_rr_node = prev_node;
auto prev_type = rr_graph.node_type(RRNodeId(prev_node));

auto iedge = find_edge(prev_node, inode);
auto switch_type = rr_graph.edge_switch(RRNodeId(prev_node), iedge);

int current_node_layer = rr_graph.node_layer(inode);
int prev_node_layer = rr_graph.node_layer(prev_node);
t_draw_layer_display edge_visibility = get_element_visibility_and_transparency(prev_node_layer, current_node_layer);

//Don't draw node if the layer of the node is not set to visible on screen
if (!draw_state->draw_layer_display[rr_graph.node_layer(inode)].visible) {
if (!draw_state->draw_layer_display[current_node_layer].visible) {
continue;
}

ezgl::color color = draw_state->draw_rr_node[inode].color;

switch (rr_type) {
case OPIN: {
draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g);
draw_rr_pin(inode, color, g);
break;
}
case IPIN: {
draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g);
if (is_edge_valid_to_draw(inode, prev_rr_node)) {
draw_rr_pin(inode, color, g);
if (edge_visibility.visible) {
g->set_color(color, edge_visibility.alpha);
if (rr_graph.node_type(prev_node) == OPIN) {
draw_pin_to_pin(prev_node, inode, g);
} else {
Expand All @@ -684,8 +690,9 @@ void draw_partial_route(const std::vector<RRNodeId>& rr_nodes_to_draw, ezgl::ren
if (draw_state->draw_route_type == GLOBAL)
chanx_track[rr_graph.node_xlow(inode)][rr_graph.node_ylow(inode)]++;

draw_rr_chan(inode, draw_state->draw_rr_node[inode].color, g);
if (is_edge_valid_to_draw(inode, prev_rr_node)) {
draw_rr_chan(inode, color, g);
if (edge_visibility.visible) {
g->set_color(color, edge_visibility.alpha);
switch (prev_type) {
case CHANX: {
draw_chanx_to_chanx_edge(prev_node, inode, switch_type, g);
Expand Down Expand Up @@ -713,9 +720,10 @@ void draw_partial_route(const std::vector<RRNodeId>& rr_nodes_to_draw, ezgl::ren
if (draw_state->draw_route_type == GLOBAL)
chany_track[rr_graph.node_xlow(inode)][rr_graph.node_ylow(inode)]++;

draw_rr_chan(inode, draw_state->draw_rr_node[inode].color, g);
draw_rr_chan(inode, color, g);

if (is_edge_valid_to_draw(inode, prev_rr_node)) {
if (edge_visibility.visible) {
g->set_color(color, edge_visibility.alpha);
switch (prev_type) {
case CHANX: {
draw_chanx_to_chany_edge(prev_node, inode,
Expand Down Expand Up @@ -1049,12 +1057,14 @@ void draw_crit_path(ezgl::renderer* g) {
int src_block_layer = get_timing_path_node_layer_num(node);
int sink_block_layer = get_timing_path_node_layer_num(prev_node);

t_draw_layer_display flyline_visibility = get_element_visibility_and_transparency(src_block_layer, sink_block_layer);

if (draw_state->show_crit_path == DRAW_CRIT_PATH_FLYLINES
|| draw_state->show_crit_path
== DRAW_CRIT_PATH_FLYLINES_DELAYS) {
// FLylines for critical path are drawn based on the layer visibility of the source and sink
if (is_flyline_valid_to_draw(src_block_layer, sink_block_layer)) {
g->set_color(color);
if (flyline_visibility.visible) {
g->set_color(color, flyline_visibility.alpha);
g->set_line_dash(ezgl::line_dash::none);
g->set_line_width(4);
draw_flyline_timing_edge(tnode_draw_coord(prev_node),
Expand All @@ -1070,10 +1080,10 @@ void draw_crit_path(ezgl::renderer* g) {
draw_routed_timing_edge_connection(prev_node, node, color, g);

// FLylines for critical path are drawn based on the layer visibility of the source and sink
if (is_flyline_valid_to_draw(src_block_layer, sink_block_layer)) {
if (flyline_visibility.visible) {
g->set_line_dash(ezgl::line_dash::asymmetric_5_3);
g->set_line_width(3);
g->set_color(color);
g->set_color(color, flyline_visibility.alpha);

draw_flyline_timing_edge((ezgl::point2d)tnode_draw_coord(prev_node),
(ezgl::point2d)tnode_draw_coord(node), (float)delay,
Expand Down
11 changes: 9 additions & 2 deletions vpr/src/draw/draw_rr.cpp
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

highlighting of RR nodes has just been changed to ensure that only nodes on currently visible layers are checked to determine whether they should be highlighted or not. This fixes the bug of the user clicking on a node, but not seeing it highlight due to the code mistakenly changing the highlight setting for a node on an invisible layer.

Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,10 @@ void draw_expand_non_configurable_rr_nodes_recurr(RRNodeId from_node,

/* This is a helper function for highlight_rr_nodes(). It determines whether
* a routing resource has been clicked on by computing a bounding box for that
* and checking if the mouse click hit inside its bounding box.
* and checking if the mouse click hit inside its bounding box. The function does not check
* routing resources that are on currently invisible layers (layer view is toggled off) to ensure that
* only resources on visible layers are set to be highlighted. There is no priority based on FPGA layer
* for highlighting routing resources (Does not iterate through nodes by order of layer a node is located on).
*
* It returns the hit RR node's ID (or OPEN if no hit)
*/
Expand All @@ -691,16 +694,20 @@ RRNodeId draw_check_rr_node_hit(float click_x, float click_y) {
ezgl::rectangle bound_box;

t_draw_coords* draw_coords = get_draw_coords_vars();
t_draw_state* draw_state = get_draw_state_vars();
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;

for (const RRNodeId& inode : device_ctx.rr_graph.nodes()) {
int layer_num = rr_graph.node_layer(inode);
if (!draw_state->draw_layer_display[layer_num].visible) {
continue; /* Don't check RR nodes on currently invisible layers*/
}
switch (rr_graph.node_type(inode)) {
case IPIN:
case OPIN: {
int i = rr_graph.node_xlow(inode);
int j = rr_graph.node_ylow(inode);
int layer_num = rr_graph.node_layer(inode);
t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({i, j, layer_num});
int width_offset = device_ctx.grid.get_width_offset({i, j, layer_num});
int height_offset = device_ctx.grid.get_height_offset({i, j, layer_num});
Expand Down