diff --git a/dive_core/command_hierarchy.cpp b/dive_core/command_hierarchy.cpp index 809b320be..94b1f1e88 100644 --- a/dive_core/command_hierarchy.cpp +++ b/dive_core/command_hierarchy.cpp @@ -361,12 +361,12 @@ uint8_t CommandHierarchy::GetPacketNodeOpcode(uint64_t node_index) const } //-------------------------------------------------------------------------------------------------- -bool CommandHierarchy::GetPacketNodeIsCe(uint64_t node_index) const +uint8_t CommandHierarchy::GetPacketNodeIbLevel(uint64_t node_index) const { DIVE_ASSERT(node_index < m_nodes.m_aux_info.size()); DIVE_ASSERT(m_nodes.m_node_type[node_index] == Dive::NodeType::kPacketNode); const AuxInfo &info = m_nodes.m_aux_info[node_index]; - return info.packet_node.m_is_ce_packet; + return info.packet_node.m_ib_level; } //-------------------------------------------------------------------------------------------------- bool CommandHierarchy::GetRegFieldNodeIsCe(uint64_t node_index) const @@ -480,14 +480,14 @@ CommandHierarchy::AuxInfo CommandHierarchy::AuxInfo::IbNode(uint32_t ib_index, //-------------------------------------------------------------------------------------------------- CommandHierarchy::AuxInfo CommandHierarchy::AuxInfo::PacketNode(uint64_t addr, uint8_t opcode, - bool is_ce_packet) + uint8_t ib_level) { // Addresses should only be 48-bits DIVE_ASSERT(addr == (addr & 0x0000FFFFFFFFFFFF)); AuxInfo info(0); info.packet_node.m_addr = (addr & 0x0000FFFFFFFFFFFF); info.packet_node.m_opcode = opcode; - info.packet_node.m_is_ce_packet = is_ce_packet; + info.packet_node.m_ib_level = ib_level; return info; } @@ -554,9 +554,6 @@ bool CommandHierarchyCreator::CreateTrees(CommandHierarchy *command_hierarchy_p } m_num_events = 0; - m_cur_submit_node_index = UINT64_MAX; - m_dcb_ib_stack.clear(); - m_ccb_ib_stack.clear(); m_flatten_chain_nodes = flatten_chain_nodes; for (uint32_t submit_index = 0; submit_index < capture_data.GetNumSubmits(); ++submit_index) @@ -675,9 +672,6 @@ bool CommandHierarchyCreator::CreateTrees(CommandHierarchy *command_hierarchy_pt } m_num_events = 0; - m_cur_submit_node_index = UINT64_MAX; - m_dcb_ib_stack.clear(); - m_ccb_ib_stack.clear(); m_flatten_chain_nodes = false; uint32_t submit_index = 0; @@ -773,20 +767,20 @@ bool CommandHierarchyCreator::OnIbStart(uint32_t submit_index, !ib_info.m_skip); uint64_t ib_node_index = AddNode(NodeType::kIbNode, ib_string_stream.str(), aux_info); - // Determine parent node and update m_cur_non_chain_#cb_ib_node_index + // Determine parent node uint64_t parent_node_index = m_cur_submit_node_index; - if (!m_dcb_ib_stack.empty()) + if (!m_ib_stack.empty()) { - parent_node_index = m_dcb_ib_stack.back(); + parent_node_index = m_ib_stack.back(); } if (m_flatten_chain_nodes && type == IbType::kChain) { // If flatten enabled, then add to the nearest non-chain node parent // Find first previous non-CHAIN parent - for (size_t i = m_dcb_ib_stack.size() - 1; i != SIZE_MAX; i--) + for (size_t i = m_ib_stack.size() - 1; i != SIZE_MAX; i--) { - uint64_t index = m_dcb_ib_stack[i]; + uint64_t index = m_ib_stack[i]; IbType cur_type = m_command_hierarchy_ptr->GetIbNodeType(index); if (cur_type != IbType::kChain) { @@ -799,8 +793,10 @@ bool CommandHierarchyCreator::OnIbStart(uint32_t submit_index, AddChild(CommandHierarchy::kEngineTopology, parent_node_index, ib_node_index); AddChild(CommandHierarchy::kSubmitTopology, parent_node_index, ib_node_index); - m_dcb_ib_stack.push_back(ib_node_index); - + m_ib_stack.push_back(ib_node_index); + if (m_cur_ib_packet_node_index != UINT64_MAX) + m_cur_shared_node_parent_index = m_cur_ib_packet_node_index; + m_cur_ib_level = ib_info.m_ib_level; m_cmd_begin_packet_node_indices.clear(); m_cmd_begin_event_node_indices.clear(); return true; @@ -811,23 +807,28 @@ bool CommandHierarchyCreator::OnIbEnd(uint32_t submit_index, uint32_t ib_index, const IndirectBufferInfo &ib_info) { - DIVE_ASSERT(!m_dcb_ib_stack.empty()); + DIVE_ASSERT(!m_ib_stack.empty()); // Note: This callback is only called for the last CHAIN of a series of daisy-CHAIN IBs, // because the emulator does not keep track of IBs in an internal stack. So start by // popping all consecutive CHAIN IBs IbType type; - type = m_command_hierarchy_ptr->GetIbNodeType(m_dcb_ib_stack.back()); - while (!m_dcb_ib_stack.empty() && type == IbType::kChain) + type = m_command_hierarchy_ptr->GetIbNodeType(m_ib_stack.back()); + while (!m_ib_stack.empty() && type == IbType::kChain) { - m_dcb_ib_stack.pop_back(); - type = m_command_hierarchy_ptr->GetIbNodeType(m_dcb_ib_stack.back()); + m_ib_stack.pop_back(); + type = m_command_hierarchy_ptr->GetIbNodeType(m_ib_stack.back()); } - m_dcb_ib_stack.pop_back(); + m_ib_stack.pop_back(); OnVulkanMarkerEnd(); m_cmd_begin_packet_node_indices.clear(); m_cmd_begin_event_node_indices.clear(); + m_cur_ib_level = ib_info.m_ib_level; + + // Reset back to submit node being the parent (as opposed to, possibly, the indirect_buffer + // packet) + m_cur_shared_node_parent_index = m_cur_submit_node_index; return true; } @@ -850,12 +851,14 @@ bool CommandHierarchyCreator::OnPacket(const IMemoryManager &mem_manager, false, type, header); - AddSharedChild(CommandHierarchy::kEngineTopology, m_cur_submit_node_index, packet_node_index); - AddSharedChild(CommandHierarchy::kSubmitTopology, m_cur_submit_node_index, packet_node_index); - AddSharedChild(CommandHierarchy::kAllEventTopology, m_cur_submit_node_index, packet_node_index); - AddSharedChild(CommandHierarchy::kRgpTopology, m_cur_submit_node_index, packet_node_index); - AddSharedChild(CommandHierarchy::kEngineTopology, m_dcb_ib_stack.back(), packet_node_index); - AddSharedChild(CommandHierarchy::kSubmitTopology, m_dcb_ib_stack.back(), packet_node_index); + + uint64_t parent_index = m_cur_shared_node_parent_index; + AddSharedChild(CommandHierarchy::kEngineTopology, parent_index, packet_node_index); + AddSharedChild(CommandHierarchy::kSubmitTopology, parent_index, packet_node_index); + AddSharedChild(CommandHierarchy::kAllEventTopology, parent_index, packet_node_index); + AddSharedChild(CommandHierarchy::kRgpTopology, parent_index, packet_node_index); + AddSharedChild(CommandHierarchy::kEngineTopology, m_ib_stack.back(), packet_node_index); + AddSharedChild(CommandHierarchy::kSubmitTopology, m_ib_stack.back(), packet_node_index); uint32_t opcode = UINT32_MAX; if (type == Pm4Type::kType7) @@ -950,6 +953,11 @@ bool CommandHierarchyCreator::OnPacket(const IMemoryManager &mem_manager, AddChild(CommandHierarchy::kRgpTopology, parent_node_index, event_node_index); m_node_parent_info[CommandHierarchy::kRgpTopology][event_node_index] = parent_node_index; } + else if ((opcode == CP_INDIRECT_BUFFER_PFE || opcode == CP_INDIRECT_BUFFER_PFD || + opcode == CP_INDIRECT_BUFFER_CHAIN || opcode == CP_COND_INDIRECT_BUFFER_PFE)) + { + m_cur_ib_packet_node_index = packet_node_index; + } // vulkan call NOP packages. Currently contains call parameters(except parameters in array), // each call is in one NOP packet. else if (opcode == CP_NOP) @@ -1044,7 +1052,10 @@ void CommandHierarchyCreator::OnSubmitStart(uint32_t submit_index, const SubmitI AddChild(CommandHierarchy::kAllEventTopology, Topology::kRootNodeIndex, submit_node_index); AddChild(CommandHierarchy::kRgpTopology, Topology::kRootNodeIndex, submit_node_index); m_cur_submit_node_index = submit_node_index; + m_cur_shared_node_parent_index = m_cur_submit_node_index; m_cur_engine_index = submit_info.GetEngineIndex(); + m_cur_ib_packet_node_index = UINT64_MAX; + m_ib_stack.clear(); } //-------------------------------------------------------------------------------------------------- @@ -1136,9 +1147,6 @@ void CommandHierarchyCreator::OnSubmitEnd(uint32_t submit_index, const SubmitInf AddChild(CommandHierarchy::kRgpTopology, Topology::kRootNodeIndex, present_node_index); } } - m_cur_submit_node_index = UINT64_MAX; - m_ccb_ib_stack.clear(); - m_dcb_ib_stack.clear(); } //-------------------------------------------------------------------------------------------------- @@ -1161,7 +1169,7 @@ uint64_t CommandHierarchyCreator::AddPacketNode(const IMemoryManager &mem_manage CommandHierarchy::AuxInfo aux_info = CommandHierarchy::AuxInfo::PacketNode(va_addr, type7_header .opcode, - is_ce_packet); + m_cur_ib_level); uint64_t packet_node_index = AddNode(NodeType::kPacketNode, packet_string_stream.str(), @@ -1294,7 +1302,7 @@ uint64_t CommandHierarchyCreator::AddPacketNode(const IMemoryManager &mem_manage CommandHierarchy::AuxInfo aux_info = CommandHierarchy::AuxInfo::PacketNode(va_addr, UINT8_MAX, - is_ce_packet); + m_cur_ib_level); uint64_t packet_node_index = AddNode(NodeType::kPacketNode, packet_string_stream.str(), diff --git a/dive_core/command_hierarchy.h b/dive_core/command_hierarchy.h index f76523ef2..6880c22e1 100644 --- a/dive_core/command_hierarchy.h +++ b/dive_core/command_hierarchy.h @@ -216,7 +216,7 @@ class CommandHierarchy uint32_t GetEventNodeId(uint64_t node_index) const; uint64_t GetPacketNodeAddr(uint64_t node_index) const; uint8_t GetPacketNodeOpcode(uint64_t node_index) const; - bool GetPacketNodeIsCe(uint64_t node_index) const; + uint8_t GetPacketNodeIbLevel(uint64_t node_index) const; bool GetRegFieldNodeIsCe(uint64_t node_index) const; SyncType GetSyncNodeSyncType(uint64_t node_index) const; SyncInfo GetSyncNodeSyncInfo(uint64_t node_index) const; @@ -280,8 +280,8 @@ class CommandHierarchy { uint64_t m_addr : 48; uint64_t m_opcode : 8; - uint64_t m_is_ce_packet : 1; - uint64_t m_reserved : 7; + uint64_t m_ib_level : 3; + uint64_t m_reserved : 5; } packet_node; struct @@ -303,7 +303,7 @@ class CommandHierarchy IbType ib_type, uint32_t size_in_dwords, bool fully_captured); - static AuxInfo PacketNode(uint64_t addr, uint8_t opcode, bool is_ce_packet); + static AuxInfo PacketNode(uint64_t addr, uint8_t opcode, uint8_t ib_level); static AuxInfo RegFieldNode(bool is_ce_packet); static AuxInfo EventNode(uint32_t event_id); static AuxInfo MarkerNode(MarkerType type, uint32_t id = 0); @@ -393,6 +393,7 @@ class CommandHierarchyCreator : public IEmulateCallbacks void OnSubmitStart(uint32_t submit_index, const SubmitInfo &submit_info); void OnSubmitEnd(uint32_t submit_index, const SubmitInfo &submit_info); + void PreSubmitReset(); uint64_t AddPacketNode(const IMemoryManager &mem_manager, uint32_t submit_index, uint64_t va_addr, @@ -538,13 +539,16 @@ class CommandHierarchyCreator : public IEmulateCallbacks // VkBeginCommandBuffer. std::vector m_internal_marker_stack; // Current internal marker begin/end stack - std::vector m_dcb_ib_stack; // Tracks current DCB IB stack - std::vector m_ccb_ib_stack; // Tracks current CCB IB stack + std::vector m_ib_stack; // Tracks current IB stack std::vector m_renderpass_stack; // render pass marker begin/end stack - uint32_t m_num_events; // Number of events so far - Packets m_packets; // Packets added since last event - uint64_t m_cur_submit_node_index; // Current submit node being processed + uint32_t m_num_events; // Number of events so far + Packets m_packets; // Packets added since last event + + uint64_t m_cur_shared_node_parent_index; // The current parent of any shared node being added + uint64_t m_cur_submit_node_index; // Current submit node being processed + uint64_t m_cur_ib_packet_node_index; // Current ib packet node being processed + uint8_t m_cur_ib_level; // Flattening is the process of forcing chain ib nodes to only ever be child to non-chain ib // nodes, even when daisy chaining across multiple chain ib nodes. This makes the topology diff --git a/dive_core/common/emulate_pm4.cpp b/dive_core/common/emulate_pm4.cpp index 6e87f8008..ab71732f1 100644 --- a/dive_core/common/emulate_pm4.cpp +++ b/dive_core/common/emulate_pm4.cpp @@ -947,6 +947,7 @@ bool EmulatePM4::AdvanceToQueuedIB(const IMemoryManager &mem_manager, IndirectBufferInfo call_chain_ib_info; call_chain_ib_info.m_va_addr = cur_ib_level->m_cur_va; call_chain_ib_info.m_size_in_dwords = cur_ib_level->m_cur_ib_size_in_dwords; + call_chain_ib_info.m_ib_level = (uint8_t)emu_state->m_top_of_stack; call_chain_ib_info.m_skip = cur_ib_level->m_cur_ib_skip; if (!callbacks.OnIbStart(emu_state->m_submit_index, emu_state->m_ib_index, @@ -993,16 +994,18 @@ bool EmulatePM4::AdvanceOutOfIB(EmulateState *emu_state, IEmulateCallbacks &call { EmulateState::IbStack *cur_ib_level = emu_state->GetCurIb(); + emu_state->m_top_of_stack = (EmulateState::IbLevel)(emu_state->m_top_of_stack - 1); + IndirectBufferInfo ib_info; ib_info.m_va_addr = cur_ib_level->m_cur_va; ib_info.m_size_in_dwords = cur_ib_level->m_cur_ib_size_in_dwords; + ib_info.m_ib_level = (uint8_t)emu_state->m_top_of_stack; ib_info.m_skip = cur_ib_level->m_cur_ib_skip; // End-Ib Callback if (!callbacks.OnIbEnd(emu_state->m_submit_index, emu_state->m_ib_index, ib_info)) return false; - emu_state->m_top_of_stack = (EmulateState::IbLevel)(emu_state->m_top_of_stack - 1); return true; } diff --git a/dive_core/common/emulate_pm4.h b/dive_core/common/emulate_pm4.h index 162b18281..8854645d1 100644 --- a/dive_core/common/emulate_pm4.h +++ b/dive_core/common/emulate_pm4.h @@ -41,6 +41,7 @@ struct IndirectBufferInfo { uint64_t m_va_addr; uint32_t m_size_in_dwords; + uint8_t m_ib_level; // Set to true to avoid emulating this IB, probably because it was not captured bool m_skip; diff --git a/ui/command_buffer_model.cpp b/ui/command_buffer_model.cpp index 0ad7b0ecd..4380b5aeb 100644 --- a/ui/command_buffer_model.cpp +++ b/ui/command_buffer_model.cpp @@ -26,8 +26,8 @@ static_assert(sizeof(void *) == sizeof(uint64_t), "Unable to store a uint64_t into internalPointer()!"); static const char *CommandBufferColumnNames[] = { - "DE Command Buffer", - "CE Command Buffer", + "Command Buffer", + "IB Level", "Address", }; @@ -75,6 +75,14 @@ QVariant CommandBufferModel::data(const QModelIndex &index, int role) const if (!index.isValid()) return QVariant(); + if (role == Qt::TextAlignmentRole) + { + if (index.column() == CommandBufferModel::kColumnIbLevel) + return int(Qt::AlignHCenter | Qt::AlignVCenter); + else + return int(Qt::AlignLeft | Qt::AlignVCenter); + } + if (role != Qt::DisplayRole) return QVariant(); @@ -82,6 +90,7 @@ QVariant CommandBufferModel::data(const QModelIndex &index, int role) const Dive::NodeType node_type = m_command_hierarchy.GetNodeType(node_index); // Column 2: Address (will be swapped via moveSection() to be visually the 0th column) + // This forces the expand/collapse icon to be part of the pm4 column if (index.column() == CommandBufferModel::kColumnAddress) { if (node_type == Dive::NodeType::kPacketNode) @@ -96,27 +105,24 @@ QVariant CommandBufferModel::data(const QModelIndex &index, int role) const return QVariant(); } } - int target_column = 0; - switch (node_type) + else if (index.column() == CommandBufferModel::kColumnIbLevel) { - case Dive::NodeType::kPacketNode: - { - target_column = m_command_hierarchy.GetPacketNodeIsCe(node_index) ? 1 : 0; - break; + if (node_type == Dive::NodeType::kPacketNode) + { + uint64_t ib_level = m_command_hierarchy.GetPacketNodeIbLevel(node_index); + std::ostringstream ib_level_string_stream; + ib_level_string_stream << ib_level; + return QString::fromStdString(ib_level_string_stream.str()); + } + else + { + return QVariant(); + } } - case Dive::NodeType::kRegNode: - case Dive::NodeType::kFieldNode: + else // if (index.column() == CommandBufferModel::kColumnPm4) { - target_column = m_command_hierarchy.GetRegFieldNodeIsCe(node_index) ? 1 : 0; - break; + return QString(m_command_hierarchy.GetNodeDesc(node_index)); } - default: DIVE_ASSERT(false); - }; - - // Column 0 for DE packets, and column 1 is for CE packets - if (index.column() != target_column) - return QVariant(); - return QString(m_command_hierarchy.GetNodeDesc(node_index)); } //-------------------------------------------------------------------------------------------------- @@ -136,6 +142,14 @@ QVariant CommandBufferModel::headerData(int section, Qt::Orientation orientation if (section < CommandBufferModel::kColumnCount) return QVariant(tr(CommandBufferColumnNames[section])); } + else if (role == Qt::TextAlignmentRole) + { + if (section == CommandBufferModel::kColumnPm4) + return int(Qt::AlignHCenter | Qt::AlignVCenter); + else + return int(Qt::AlignLeft | Qt::AlignVCenter); + } + return QVariant(); } @@ -155,7 +169,18 @@ QModelIndex CommandBufferModel::index(int row, int column, const QModelIndex &pa } uint64_t parent_node_index = (uint64_t)(parent.internalPointer()); - uint64_t child_node_index = m_topology_ptr->GetChildNodeIndex(parent_node_index, row); + + // Children order is the "normal" children followed by the "shared" children + uint64_t child_node_index = UINT64_MAX; + if ((uint32_t)row < m_topology_ptr->GetNumChildren(parent_node_index)) + { + child_node_index = m_topology_ptr->GetChildNodeIndex(parent_node_index, row); + } + else if (m_topology_ptr->GetNumSharedChildren(parent_node_index) > 0) + { + uint32_t index = row - m_topology_ptr->GetNumChildren(parent_node_index); + child_node_index = m_topology_ptr->GetSharedChildNodeIndex(parent_node_index, index); + } if (child_node_index != UINT64_MAX) return createIndex(row, column, (void *)child_node_index); else @@ -169,26 +194,9 @@ QModelIndex CommandBufferModel::parent(const QModelIndex &index) const return QModelIndex(); uint64_t child_node_index = (uint64_t)(index.internalPointer()); - - // Root item. No parent. - if (m_command_hierarchy.GetNodeType(child_node_index) == Dive::NodeType::kPacketNode) - return QModelIndex(); - - uint64_t row; - uint64_t parent_node_index = m_topology_ptr->GetParentNodeIndex(child_node_index); - - // Packet nodes serve as root nodes in this model, and packet nodes in particular are "shared" - // nodes with many parents. So use a map to determine which child this packet node with respect - // to the selected node. - if (m_command_hierarchy.GetNodeType(parent_node_index) != Dive::NodeType::kPacketNode) - row = m_topology_ptr->GetChildIndex(parent_node_index); - else - { - auto it = m_node_index_to_row_map.find(parent_node_index); - DIVE_ASSERT(it != m_node_index_to_row_map.end()); - row = it->second; - } - return createIndex(row, 0, (void *)parent_node_index); + auto it = m_node_index_to_parent_map.find(child_node_index); + DIVE_ASSERT(it != m_node_index_to_parent_map.end()); + return it->second; } //-------------------------------------------------------------------------------------------------- @@ -206,8 +214,12 @@ int CommandBufferModel::rowCount(const QModelIndex &parent) const return num_children; } + // Return sum of shared children + normal children + // Normal Children: The packet fields + // Shared Children: Additional packets (e.g. for packets from INDIRECT_BUFFERS packet) uint64_t parent_node_index = (uint64_t)(parent.internalPointer()); - uint64_t num_children = m_topology_ptr->GetNumChildren(parent_node_index); + uint64_t num_children = m_topology_ptr->GetNumChildren(parent_node_index) + + m_topology_ptr->GetNumSharedChildren(parent_node_index); return num_children; } @@ -220,17 +232,7 @@ void CommandBufferModel::OnSelectionChanged(const QModelIndex &index) emit beginResetModel(); m_selected_node_index = selected_node_index; - - // Keep track of the child-index for each packet node; - uint64_t num_children = m_topology_ptr->GetNumSharedChildren(m_selected_node_index); - for (uint64_t child = 0; child < num_children; ++child) - { - uint64_t child_node_index = m_topology_ptr->GetSharedChildNodeIndex(m_selected_node_index, - child); - DIVE_ASSERT(m_command_hierarchy.GetNodeType(child_node_index) == - Dive::NodeType::kPacketNode); - m_node_index_to_row_map[child_node_index] = child; - } + CreateNodeToParentMap(UINT64_MAX, selected_node_index); emit endResetModel(); } @@ -265,3 +267,43 @@ QList CommandBufferModel::search(const QModelIndex &start, const QV return result; } + +//-------------------------------------------------------------------------------------------------- +void CommandBufferModel::CreateNodeToParentMap(uint64_t parent_row, uint64_t parent_node_index) +{ + // Because shared (i.e. packet) nodes can have multiple parents, a map is created to match + // those packets to the parent as seen during a specific traversal + + // Recursive function to traverse through all shared nodes in the tree + uint64_t num_children = m_topology_ptr->GetNumSharedChildren(parent_node_index); + for (uint64_t child = 0; child < num_children; ++child) + { + uint64_t child_node_index = m_topology_ptr->GetSharedChildNodeIndex(parent_node_index, + child); + QModelIndex model_index = QModelIndex(); + if (parent_row != UINT64_MAX) + model_index = createIndex(parent_row, 0, (void *)parent_node_index); + m_node_index_to_parent_map[child_node_index] = model_index; + + CreateNodeToParentMap(child, child_node_index); + } + + // To keep things simple, also include non-shared nodes in this mapping + // This way the parent() function will be a simple map lookup regardless of packet type + // Also, check parent_row against UINT64_MAX, since only the shared children of the root node + // should be considered + if (parent_row != UINT64_MAX) + { + num_children = m_topology_ptr->GetNumChildren(parent_node_index); + for (uint64_t child = 0; child < num_children; ++child) + { + uint64_t child_node_index = m_topology_ptr->GetChildNodeIndex(parent_node_index, child); + QModelIndex model_index = QModelIndex(); + if (parent_row != UINT64_MAX) + model_index = createIndex(parent_row, 0, (void *)parent_node_index); + m_node_index_to_parent_map[child_node_index] = model_index; + + CreateNodeToParentMap(child, child_node_index); + } + } +} diff --git a/ui/command_buffer_model.h b/ui/command_buffer_model.h index d89211c47..29ca4e3f4 100644 --- a/ui/command_buffer_model.h +++ b/ui/command_buffer_model.h @@ -33,8 +33,8 @@ class CommandBufferModel : public QAbstractItemModel public: enum ColumnType : int { - kColumnDE, - kColumnCE, + kColumnPm4, + kColumnIbLevel, // Swapped to second column in code. kColumnAddress, // Swapped to first column in code. kColumnCount }; @@ -65,10 +65,9 @@ public slots: void OnSelectionChanged(const QModelIndex &index); private: - void AddPackets(uint64_t node_index); - void AddMarkerPackets(uint64_t marker_node_index); - uint64_t m_selected_node_index = UINT64_MAX; - std::map m_node_index_to_row_map; - const Dive::CommandHierarchy &m_command_hierarchy; - const Dive::Topology *m_topology_ptr = nullptr; + void CreateNodeToParentMap(uint64_t parent_row, uint64_t parent_node_index); + uint64_t m_selected_node_index = UINT64_MAX; + std::map m_node_index_to_parent_map; + const Dive::CommandHierarchy &m_command_hierarchy; + const Dive::Topology *m_topology_ptr = nullptr; }; diff --git a/ui/command_buffer_view.cpp b/ui/command_buffer_view.cpp index cb5e99698..4a1aaaec8 100644 --- a/ui/command_buffer_view.cpp +++ b/ui/command_buffer_view.cpp @@ -28,145 +28,44 @@ CommandBufferViewDelegate::CommandBufferViewDelegate( const CommandBufferView *command_buffer_view_ptr) : QStyledItemDelegate(0), m_command_buffer_view_ptr(command_buffer_view_ptr) -{} +{ +} //-------------------------------------------------------------------------------------------------- -void CommandBufferViewDelegate::paint(QPainter * painter, +void CommandBufferViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex & index) const + const QModelIndex &index) const { - // Handle the drawing of the CE column. The CE column is not a tree, but will be rendered with - // indentations to match the look of the DE column. The only difference is that the CE column - // items are not expandable/collapsable, since they are not in reality a tree - const Dive::CommandHierarchy &command_hierarchy = m_command_buffer_view_ptr - ->GetCommandHierarchy(); - QStyleOptionViewItem new_option = option; - if (index.column() == CommandBufferModel::kColumnCE) + // Draw vertical border around a ib-level cell + if (index.column() == CommandBufferModel::kColumnIbLevel) { - bool is_ce_packet = false; - uint64_t node_index = (uint64_t)(index.internalPointer()); - Dive::NodeType node_type = command_hierarchy.GetNodeType(node_index); - switch (node_type) - { - case Dive::NodeType::kPacketNode: - { - is_ce_packet = command_hierarchy.GetPacketNodeIsCe(node_index); - break; - } - case Dive::NodeType::kRegNode: - { - is_ce_packet = false; // No reg nodes in CE column - break; - } - case Dive::NodeType::kFieldNode: - { - is_ce_packet = command_hierarchy.GetRegFieldNodeIsCe(node_index); - break; - } - default: DIVE_ASSERT(false); - }; - - if (is_ce_packet) - { - uint32_t indentation = m_command_buffer_view_ptr->indentation(); - - QRect fake_branch_rect; - - // Handle rendering of the fake "branch" item - { - // Calculate the branch_rect area and adjust rect for the text - if (node_type == Dive::NodeType::kPacketNode) - { - const uint32_t kMargin = 5; - uint32_t center_x = option.rect.x() + indentation / 2; - uint32_t center_y = option.rect.y() + option.rect.height() / 2; - uint32_t dimension = std::min(10, - std::min(option.rect.height() - kMargin * 2, - indentation - kMargin * 2)); - fake_branch_rect = QRect(center_x - dimension / 2, - center_y - dimension / 2, - dimension, - dimension); - new_option.rect.setLeft(option.rect.x() + indentation); - } - else - { - fake_branch_rect = QRect(option.rect.x() + indentation, - option.rect.y(), - indentation, - option.rect.height()); - new_option.rect.setLeft(option.rect.x() + 2 * indentation); - } - - // Fill background if selected (since we are adjusting the rect, we have to deal - // with the selection highlighting now) - { - m_command_buffer_view_ptr->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, - &option, - painter, - m_command_buffer_view_ptr); - } - - // Render "fake" branch item - if (node_type == Dive::NodeType::kPacketNode) - { - // Render the "bullet" for the packet item - painter->fillRect(fake_branch_rect, Qt::lightGray); - } - else - { - // Last element is rendered differently - QModelIndex parent = m_command_buffer_view_ptr->model()->parent(index); - uint32_t row_count = m_command_buffer_view_ptr->model()->rowCount(parent); - QRect branch_rect(option.rect.x() + indentation, - option.rect.y(), - indentation, - option.rect.height()); - DIVE_ASSERT(index.row() >= 0); // Pre-typecast check - if ((uint32_t)index.row() == row_count - 1) - { - painter->drawImage(branch_rect, QImage(":/images/branch-end.png")); - } - else - { - painter->drawImage(branch_rect, QImage(":/images/branch-more.png")); - } - } - } - } + painter->save(); + painter->setPen(QPen(Qt::darkGray, 1)); + painter->drawLine(option.rect.left(), + option.rect.top(), + option.rect.left(), + option.rect.bottom()); + painter->drawLine(option.rect.right(), + option.rect.top(), + option.rect.right(), + option.rect.bottom()); + + painter->restore(); } - QStyledItemDelegate::paint(painter, new_option, index); + QStyledItemDelegate::paint(painter, option, index); } // ================================================================================================= // CommandBufferView // ================================================================================================= CommandBufferView::CommandBufferView(const Dive::CommandHierarchy &command_hierarchy, - QWidget * parent) : + QWidget *parent) : DiveTreeView(command_hierarchy, parent) { setItemDelegate(new CommandBufferViewDelegate(this)); setAccessibleName("DiveCommandBufferView"); } -//-------------------------------------------------------------------------------------------------- -bool CommandBufferView::RenderBranch(const QModelIndex &index) const -{ - uint64_t node_index = (uint64_t)(index.internalPointer()); - - // Do not render branch controls for rows that contain CE info - Dive::NodeType node_type = m_command_hierarchy.GetNodeType(node_index); - switch (node_type) - { - case Dive::NodeType::kPacketNode: return !m_command_hierarchy.GetPacketNodeIsCe(node_index); - case Dive::NodeType::kRegNode: - case Dive::NodeType::kFieldNode: return !m_command_hierarchy.GetRegFieldNodeIsCe(node_index); - default: DIVE_ASSERT(false); - }; - - return true; -} - //-------------------------------------------------------------------------------------------------- void CommandBufferView::setAndScrollToIndex(QModelIndex &idx) { diff --git a/ui/command_buffer_view.h b/ui/command_buffer_view.h index b5fec640a..c46579f26 100644 --- a/ui/command_buffer_view.h +++ b/ui/command_buffer_view.h @@ -33,9 +33,9 @@ class CommandBufferViewDelegate : public QStyledItemDelegate public: CommandBufferViewDelegate(const CommandBufferView *command_buffer_view_ptr); - void paint(QPainter * painter, + void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex & index) const override; + const QModelIndex &index) const override; private: const CommandBufferView *m_command_buffer_view_ptr; @@ -48,8 +48,7 @@ class CommandBufferView : public DiveTreeView public: CommandBufferView(const Dive::CommandHierarchy &command_hierarchy, QWidget *parent = nullptr); - virtual bool RenderBranch(const QModelIndex &index) const override; - void Reset(); + void Reset(); public slots: // Search CommandBufferView by input text diff --git a/ui/command_tab_view.cpp b/ui/command_tab_view.cpp index d6a360e8c..61dd16ae1 100644 --- a/ui/command_tab_view.cpp +++ b/ui/command_tab_view.cpp @@ -37,9 +37,11 @@ CommandTabView::CommandTabView(const Dive::CommandHierarchy &command_hierarchy, m_command_buffer_view = new CommandBufferView(command_hierarchy); m_command_buffer_view->setModel(m_command_buffer_model); - // Put address column (column 3) to the left of the tree. This forces the expand/collapse - // icon to be part of the 2nd column (originally 1st) + // Move the address column to be the 1st column, followed by the IB Level column + // This allows the expand/collapse icon to be part of what was originally the 1st column (i.e. + // the pm4 column) m_command_buffer_view->header()->moveSection(2, 0); + m_command_buffer_view->header()->moveSection(2, 1); m_search_trigger_button = new QPushButton; m_search_trigger_button->setIcon(QIcon(":/images/search.png"));