diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index f2e1dcb5876..d4e22cd3c95 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -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) { 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(); @@ -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) { @@ -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) { @@ -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 */ } diff --git a/vpr/src/draw/draw.h b/vpr/src/draw/draw.h index 7e799eb8a97..1c39f12f49b 100644 --- a/vpr/src/draw/draw.h +++ b/vpr/src/draw/draw.h @@ -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 world 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 it + * returns the clusterBlockId of a clb on a higher layer during instances of overlap between clb blocks. + * @param x + * @param y + * @return returns the ClusterBlockId of the clb at the specified (x,y) location (in world coordinates) 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 */ diff --git a/vpr/src/draw/draw_basic.cpp b/vpr/src/draw/draw_basic.cpp index c1b8715c1c7..e35ebcef0a6 100644 --- a/vpr/src/draw/draw_basic.cpp +++ b/vpr/src/draw/draw_basic.cpp @@ -653,25 +653,31 @@ void draw_partial_route(const std::vector& 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 { @@ -684,8 +690,9 @@ void draw_partial_route(const std::vector& 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); @@ -713,9 +720,10 @@ void draw_partial_route(const std::vector& 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, @@ -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), @@ -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, diff --git a/vpr/src/draw/draw_rr.cpp b/vpr/src/draw/draw_rr.cpp index ad58bd40604..fa04c388cfe 100644 --- a/vpr/src/draw/draw_rr.cpp +++ b/vpr/src/draw/draw_rr.cpp @@ -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) */ @@ -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});