diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 6fc098c21..9d766df69 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -37,7 +37,6 @@ include_directories( ${THIRDPARTY_DIRECTORY}/Vulkan-Headers/include ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} - ${LibArchive_INCLUDE_DIRS} ) add_definitions(-DLITTLEENDIAN_CPU) diff --git a/dive_core/CMakeLists.txt b/dive_core/CMakeLists.txt index 6ea2b2a7c..49150572e 100644 --- a/dive_core/CMakeLists.txt +++ b/dive_core/CMakeLists.txt @@ -333,7 +333,7 @@ if(WIN32) # Supress warning about deprecation of std::iterator when compile with c++17 add_definitions(-D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING) endif() # WIN32 -target_link_libraries(${PROJECT_NAME} PRIVATE ${LibArchive_LIBRARIES}) +target_link_libraries(${PROJECT_NAME} PRIVATE LibArchive::LibArchive) # This is needed in u_debug.h in mesa, which is included by shader_disassembly.cpp check_function_exists(secure_getenv HAVE_SECURE_GETENV) @@ -341,7 +341,6 @@ if(HAVE_SECURE_GETENV) target_compile_definitions(${PROJECT_NAME} PRIVATE -DHAVE_SECURE_GETENV) endif() # HAVE_SECURE_GETENV -include_directories(${LibArchive_INCLUDE_DIRS}) if(MSVC) set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11) # To support alignas set_source_files_properties( diff --git a/libarchive.cmake b/libarchive.cmake index 04b5a98c7..314383cef 100644 --- a/libarchive.cmake +++ b/libarchive.cmake @@ -70,6 +70,7 @@ else() set(LibArchive_INCLUDE_DIRS ${THIRDPARTY_DIRECTORY}/libarchive/libarchive/) add_compile_definitions(LIBARCHIVE_STATIC=ON) include_directories(${THIRDPARTY_DIRECTORY}/libarchive/libarchive/) + add_library(LibArchive::LibArchive ALIAS archive_static) endif() include_directories(LibArchive_INCLUDE_DIRS) diff --git a/lrz_validator/CMakeLists.txt b/lrz_validator/CMakeLists.txt index effc447d3..93336dde9 100644 --- a/lrz_validator/CMakeLists.txt +++ b/lrz_validator/CMakeLists.txt @@ -37,7 +37,6 @@ include_directories( ${THIRDPARTY_DIRECTORY}/Vulkan-Headers/include ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} - ${LibArchive_INCLUDE_DIRS} ) add_executable(${PROJECT_NAME} "main.cpp") diff --git a/src/dive/utils/CMakeLists.txt b/src/dive/utils/CMakeLists.txt index c1256a3ce..09c3313e4 100644 --- a/src/dive/utils/CMakeLists.txt +++ b/src/dive/utils/CMakeLists.txt @@ -17,6 +17,17 @@ message(CHECK_START "Generate build files for src/dive/utils") list(APPEND CMAKE_MESSAGE_INDENT " ") +# === dive_archive ============================================================= + +if(NOT ANDROID) + add_library(dive_archive dive_archive.h dive_archive.cpp) + target_link_libraries( + dive_archive + PUBLIC dive_src_includes absl::statusor + PRIVATE LibArchive::LibArchive + ) +endif() + # === component_files ========================================================== if(NOT ANDROID) diff --git a/src/dive/utils/dive_archive.cpp b/src/dive/utils/dive_archive.cpp new file mode 100644 index 000000000..c37b68f2c --- /dev/null +++ b/src/dive/utils/dive_archive.cpp @@ -0,0 +1,168 @@ +/* + Copyright 2026 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "dive/utils/dive_archive.h" + +// libarchive: +#include +#include + +#include +#include +#include +#include + +namespace +{ + +void ArchiveReadCloseAndFree(struct archive* archive_reader) +{ + if (archive_reader == nullptr) + { + return; + } + archive_read_close(archive_reader); + archive_read_free(archive_reader); +} + +using UniqueArchiveReadPtr = std::unique_ptr; + +UniqueArchiveReadPtr ArchiveReadNew() +{ + return UniqueArchiveReadPtr{archive_read_new(), &ArchiveReadCloseAndFree}; +} + +constexpr auto kKnownDiveArchiveExtension = + std::to_array({".zip", ".tar", ".tar.gz", ".tgz"}); + +// We don't produce captalized extension, so check for lower case only. +constexpr auto kKnownDiveExtension = + std::to_array({".rd", ".gfxr", ".gfxa", ".png", ".csv"}); + +std::string_view GetArchiveEntryPath(struct archive_entry* entry) +{ + const char* pathname = archive_entry_pathname(entry); + if (pathname == nullptr) + { + return ""; + } + return std::string_view(pathname); +} + +int WriteArchiveEntry(std::ostream& ost, struct archive* archive_reader) +{ + // Make sure we don't expand a bad sparse file. + constexpr la_int64_t kMaxSkip = 0x40000000; + + la_int64_t processed = 0; + + while (ost) + { + const void* buff = nullptr; + size_t size = 0; + la_int64_t offset = 0; + auto res = archive_read_data_block(archive_reader, &buff, &size, &offset); + if (res < ARCHIVE_OK) + { + return res; + } + if (size == 0) + { + return ARCHIVE_OK; + } + if (offset - processed > kMaxSkip) + { + return ARCHIVE_FAILED; + } + if (processed != offset) + { + ost.seekp(offset); + } + ost.write(static_cast(buff), static_cast(size)); + processed += static_cast(size); + } + + return ARCHIVE_FAILED; +} + +} // namespace + +namespace Dive +{ + +bool DiveArchive::IsSupportedInputFormat(std::filesystem::path filename) +{ + auto ext = filename.extension().string(); + std::transform(ext.begin(), ext.end(), ext.begin(), [](auto c) { return std::tolower(c); }); + return std::any_of(std::begin(kKnownDiveArchiveExtension), std::end(kKnownDiveArchiveExtension), + [&ext](std::string_view known) { return ext == known; }); +} + +std::unique_ptr DiveArchive::Open(std::filesystem::path filename) +{ + return std::unique_ptr(new DiveArchive(filename)); +} + +DiveArchive::DiveArchive(std::filesystem::path archive_path) : m_path(archive_path) {} + +std::vector DiveArchive::ExtractTo(std::filesystem::path dst) +{ + constexpr size_t kBlockSize = 0x10000; // 64KiB, we don't really care. + auto reader = ArchiveReadNew(); + archive_read_support_format_all(reader.get()); + archive_read_support_filter_all(reader.get()); + + if (auto res = archive_read_open_filename(reader.get(), m_path.string().c_str(), kBlockSize); + res != ARCHIVE_OK) + { + return {}; + } + + std::vector filenames; + while (true) + { + struct archive_entry* entry = nullptr; + if (auto res = archive_read_next_header(reader.get(), &entry); res != ARCHIVE_OK) + { + break; + } + + if (archive_entry_filetype(entry) != AE_IFREG) + { + continue; + } + + std::filesystem::path entry_path = std::filesystem::path(GetArchiveEntryPath(entry)); + if (std::none_of(std::begin(kKnownDiveExtension), std::end(kKnownDiveExtension), + [ext = entry_path.extension().string()](std::string_view expected) { + return ext == expected; + })) + { + continue; + } + + auto dst_file_path = dst / entry_path.filename(); + std::ofstream dst_file(dst_file_path, std::ios::binary | std::ios::out); + if (auto res = WriteArchiveEntry(dst_file, reader.get()); res != ARCHIVE_OK) + { + break; + } + filenames.push_back(dst_file_path); + } + return filenames; +} + +} // namespace Dive diff --git a/src/dive/utils/dive_archive.h b/src/dive/utils/dive_archive.h new file mode 100644 index 000000000..8da68417b --- /dev/null +++ b/src/dive/utils/dive_archive.h @@ -0,0 +1,42 @@ +/* + Copyright 2026 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#pragma once + +#include +#include +#include + +namespace Dive +{ + +class DiveArchive +{ + public: + static std::unique_ptr Open(std::filesystem::path filename); + + // Extract to `dst` directory, returns extracted filepaths. + std::vector ExtractTo(std::filesystem::path dst); + + static bool IsSupportedInputFormat(std::filesystem::path filename); + + private: + explicit DiveArchive(std::filesystem::path archive_path); + + std::filesystem::path m_path; +}; + +} // namespace Dive diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index 6490c9bd6..254cf3998 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -192,7 +192,6 @@ target_include_directories( "${CMAKE_SOURCE_DIR}" # Include CMAKE_BINARY_DIR for generated files. "${CMAKE_BINARY_DIR}" - "${LibArchive_INCLUDE_DIRS}" ) # Enable asan and ubsan @@ -225,6 +224,7 @@ target_link_libraries( absl::span absl::symbolize network + dive_archive dive_core dive_lib_os dive_lib_ui diff --git a/ui/capture_file_manager.cpp b/ui/capture_file_manager.cpp index e8d6ab7e0..a254b059a 100644 --- a/ui/capture_file_manager.cpp +++ b/ui/capture_file_manager.cpp @@ -16,6 +16,7 @@ #include "capture_file_manager.h" +#include #include #include #include @@ -27,6 +28,7 @@ #include "dive/ui/types/context.h" #include "dive/ui/types/file_path.h" #include "dive/ui/utils/debug_utils.h" +#include "dive/utils/dive_archive.h" #include "dive_core/data_core.h" #include "trace_stats/trace_stats.h" @@ -49,6 +51,35 @@ LoadFileResult::Status ToLoadFileStatus(Dive::CaptureData::LoadResult result) } return LoadFileResult::Status::kUnknown; } + +std::filesystem::path GetMainCaptureFile(const std::vector& paths) +{ + std::filesystem::path gfxr_path; + std::filesystem::path rd_path; + for (const auto& filepath : paths) + { + if (filepath.extension() == ".gfxr") + { + if (!gfxr_path.empty()) + { + return {}; + } + gfxr_path = filepath; + } + else if (filepath.extension() == ".rd") + { + if (!rd_path.empty()) + { + return {}; + } + rd_path = filepath; + } + } + + // Prefer gfxr file. + return !gfxr_path.empty() ? gfxr_path : rd_path; +} + } // namespace void CaptureFileManager::RegisterCustomMetaType() { qRegisterMetaType(); } @@ -110,12 +141,12 @@ void CaptureFileManager::OnLoadFileDone(const LoadFileResult& loaded_file) emit FileLoadingFinished(loaded_file); } -Dive::ComponentFilePaths CaptureFileManager::ResolveComponents(const Dive::FilePath& reference) +Dive::ComponentFilePaths CaptureFileManager::ResolveComponents(std::filesystem::path reference) { - if (Dive::IsGfxrFile(reference.value)) + if (Dive::IsGfxrFile(reference)) { - auto ret = Dive::GetComponentFilesHostPaths(reference.value.parent_path(), - reference.value.stem().string()); + auto ret = + Dive::GetComponentFilesHostPaths(reference.parent_path(), reference.stem().string()); if (ret.ok()) { return *ret; @@ -123,15 +154,15 @@ Dive::ComponentFilePaths CaptureFileManager::ResolveComponents(const Dive::FileP return Dive::ComponentFilePaths{}; } - if (Dive::IsRdFile(reference.value)) + if (Dive::IsRdFile(reference)) { - std::filesystem::path gfxr_file_path = reference.value; + std::filesystem::path gfxr_file_path = reference; gfxr_file_path.replace_extension("gfxr"); if (std::filesystem::exists(gfxr_file_path)) { // Try load it as gfxr file: - auto ret = Dive::GetComponentFilesHostPaths(reference.value.parent_path(), - reference.value.stem().string()); + auto ret = Dive::GetComponentFilesHostPaths(reference.parent_path(), + reference.stem().string()); if (ret.ok()) { return *ret; @@ -143,7 +174,7 @@ Dive::ComponentFilePaths CaptureFileManager::ResolveComponents(const Dive::FileP .gfxa = {}, .perf_counter_csv = {}, .gpu_timing_csv = {}, - .pm4_rd = reference.value, + .pm4_rd = reference, .screenshot_png = {}, .renderdoc_rdc = {}, }; @@ -152,11 +183,10 @@ Dive::ComponentFilePaths CaptureFileManager::ResolveComponents(const Dive::FileP return Dive::ComponentFilePaths{}; } -void CaptureFileManager::LoadFile(const Dive::FilePath& reference, - const Dive::ComponentFilePaths& components) +void CaptureFileManager::LoadFile(const Dive::FilePath& reference) { m_loading_in_progress = true; - m_pending_request = LoadFileRequest{.reference = reference, .components = components}; + m_pending_request = reference; // Cancel anything that depend on current capture file. if (!m_capture_file_context.IsNull()) { @@ -184,17 +214,57 @@ void CaptureFileManager::StartLoadFile() }); } -LoadFileResult CaptureFileManager::LoadFileFailed( - LoadFileResult::Status status, const CaptureFileManager::LoadFileRequest& request) +LoadFileResult CaptureFileManager::LoadFileFailed(LoadFileResult::Status status, + const LoadFileResult& partial) { + m_temp_dir = std::nullopt; return LoadFileResult{ - .status = status, .reference = request.reference, .components = request.components}; + .status = status, + .file_type = partial.file_type, + .reference = partial.reference, + .components = partial.components, + }; } LoadFileResult CaptureFileManager::LoadFileImpl(const Dive::Context& context, - const LoadFileRequest& request) + const Dive::FilePath& request) { - const auto& components = request.components; + m_temp_dir = std::nullopt; + LoadFileResult result{ + .status = LoadFileResult::Status::kUnknown, + .file_type = LoadFileResult::FileType::kUnknown, + .reference = request, + .components = {}, + }; + + if (Dive::DiveArchive::IsSupportedInputFormat(request.value)) + { + if (!std::filesystem::exists(request.value)) + { + return LoadFileFailed(LoadFileResult::Status::kFileNotFound, result); + } + m_temp_dir.emplace(); + + qDebug() << "Extracting" << QString::fromStdString(request.value.string()) << "to" + << m_temp_dir->path(); + + auto archive = Dive::DiveArchive::Open(request.value); + + auto dst = std::filesystem::path(m_temp_dir.value().path().toStdString()); + std::vector paths = archive->ExtractTo(dst); + auto main_file = GetMainCaptureFile(paths); + if (main_file.empty()) + { + return LoadFileFailed(LoadFileResult::Status::kUnsupportedFile, result); + } + result.components = ResolveComponents(main_file); + } + else + { + result.components = ResolveComponents(request.value); + } + + const auto& components = result.components; QWriteLocker locker(&m_data_core_lock); // Note: this function might not run on UI thread, thus can't do any UI modification. @@ -210,37 +280,36 @@ LoadFileResult CaptureFileManager::LoadFileImpl(const Dive::Context& context, if (!asset_file_exists) { - return LoadFileFailed(LoadFileResult::Status::kGfxaAssetMissing, request); + return LoadFileFailed(LoadFileResult::Status::kGfxaAssetMissing, result); } } - LoadFileResult::FileType file_type = LoadFileResult::FileType::kUnknown; if (found_gfxr_file && found_rd_file) { - file_type = LoadFileResult::FileType::kCorrelatedFiles; + result.file_type = LoadFileResult::FileType::kCorrelatedFiles; } else if (found_gfxr_file) { - file_type = LoadFileResult::FileType::kGfxrFile; + result.file_type = LoadFileResult::FileType::kGfxrFile; } else if (found_rd_file) { - file_type = LoadFileResult::FileType::kRdFile; + result.file_type = LoadFileResult::FileType::kRdFile; } else { - file_type = LoadFileResult::FileType::kUnknown; + result.file_type = LoadFileResult::FileType::kUnknown; } - switch (file_type) + switch (result.file_type) { case LoadFileResult::FileType::kUnknown: { - if (!std::filesystem::exists(request.reference.value)) + if (!std::filesystem::exists(result.reference.value)) { - return LoadFileFailed(LoadFileResult::Status::kFileNotFound, request); + return LoadFileFailed(LoadFileResult::Status::kFileNotFound, result); } - return LoadFileFailed(LoadFileResult::Status::kUnsupportedFile, request); + return LoadFileFailed(LoadFileResult::Status::kUnsupportedFile, result); } case LoadFileResult::FileType::kCorrelatedFiles: { @@ -248,12 +317,12 @@ LoadFileResult CaptureFileManager::LoadFileImpl(const Dive::Context& context, m_data_core->LoadDiveCaptureData(components.gfxr.string()); load_res != Dive::CaptureData::LoadResult::kSuccess) { - return LoadFileFailed(ToLoadFileStatus(load_res), request); + return LoadFileFailed(ToLoadFileStatus(load_res), result); } if (!m_data_core->ParseDiveCaptureData()) { - return LoadFileFailed(LoadFileResult::Status::kParseFailure, request); + return LoadFileFailed(LoadFileResult::Status::kParseFailure, result); } } break; @@ -263,12 +332,12 @@ LoadFileResult CaptureFileManager::LoadFileImpl(const Dive::Context& context, m_data_core->LoadPm4CaptureData(components.pm4_rd.string()); load_res != Dive::CaptureData::LoadResult::kSuccess) { - return LoadFileFailed(ToLoadFileStatus(load_res), request); + return LoadFileFailed(ToLoadFileStatus(load_res), result); } if (!m_data_core->ParsePm4CaptureData()) { - return LoadFileFailed(LoadFileResult::Status::kParseFailure, request); + return LoadFileFailed(LoadFileResult::Status::kParseFailure, result); } } break; @@ -278,22 +347,19 @@ LoadFileResult CaptureFileManager::LoadFileImpl(const Dive::Context& context, m_data_core->LoadGfxrCaptureData(components.gfxr.string()); load_res != Dive::CaptureData::LoadResult::kSuccess) { - return LoadFileFailed(ToLoadFileStatus(load_res), request); + return LoadFileFailed(ToLoadFileStatus(load_res), result); } if (!m_data_core->ParseGfxrCaptureData()) { - return LoadFileFailed(LoadFileResult::Status::kParseFailure, request); + return LoadFileFailed(LoadFileResult::Status::kParseFailure, result); } } break; } - return LoadFileResult{ - .status = LoadFileResult::Status::kSuccess, - .file_type = file_type, - .reference = request.reference, - .components = request.components, - }; + + result.status = LoadFileResult::Status::kSuccess; + return result; } void CaptureFileManager::GatherTraceStats() diff --git a/ui/capture_file_manager.h b/ui/capture_file_manager.h index 5a183424e..97bfec3fd 100644 --- a/ui/capture_file_manager.h +++ b/ui/capture_file_manager.h @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include "dive/ui/types/context.h" #include "dive/ui/types/file_path.h" @@ -83,8 +85,7 @@ class CaptureFileManager : public QObject // Locking: QReadWriteLock& GetDataCoreLock() { return m_data_core_lock; } - Dive::ComponentFilePaths ResolveComponents(const Dive::FilePath& reference); - void LoadFile(const Dive::FilePath& reference, const Dive::ComponentFilePaths& components); + void LoadFile(const Dive::FilePath& reference); void GatherTraceStats(); void FillCaptureStatsResult(Dive::CaptureStats& out); @@ -102,18 +103,15 @@ class CaptureFileManager : public QObject void OnLoadFileDone(const LoadFileResult&); private: - struct LoadFileRequest - { - Dive::FilePath reference; - Dive::ComponentFilePaths components; - }; std::shared_ptr m_data_core = nullptr; QReadWriteLock m_data_core_lock; bool m_loading_in_progress = false; bool m_working = false; - std::optional m_pending_request; + std::optional m_temp_dir; + + std::optional m_pending_request; Dive::SimpleContext m_capture_file_context; @@ -122,14 +120,14 @@ class CaptureFileManager : public QObject QThread* m_thread = nullptr; QObject* m_worker = nullptr; - static LoadFileResult LoadFileFailed(LoadFileResult::Status status, - const CaptureFileManager::LoadFileRequest& request); + Dive::ComponentFilePaths ResolveComponents(std::filesystem::path reference); + LoadFileResult LoadFileFailed(LoadFileResult::Status status, const LoadFileResult& partial); void GatherTraceStatsImpl(const Dive::Context& context); void StartLoadFile(); - LoadFileResult LoadFileImpl(const Dive::Context& context, const LoadFileRequest& request); + LoadFileResult LoadFileImpl(const Dive::Context& context, const Dive::FilePath& request); }; Q_DECLARE_METATYPE(LoadFileResult) diff --git a/ui/main_window.cpp b/ui/main_window.cpp index 4b191c93f..b7b379d64 100644 --- a/ui/main_window.cpp +++ b/ui/main_window.cpp @@ -194,8 +194,7 @@ MainWindow::MainWindow(ApplicationController& controller) : m_controller(control m_capture_manager = new CaptureFileManager(this); m_capture_manager->Start(m_data_core); - m_capture_manager->GetDataCoreLock().lockForRead(); - m_capture_acquired = true; + m_capture_acquired.emplace(&m_capture_manager->GetDataCoreLock()); QObject::connect(m_capture_manager, &CaptureFileManager::FileLoadingFinished, this, &MainWindow::OnFileLoaded); @@ -948,13 +947,10 @@ void MainWindow::OnTraceStatsUpdated() //-------------------------------------------------------------------------------------------------- bool MainWindow::LoadFile(const std::string& file_name, bool is_temp_file, bool async) { - bool release_capture = m_capture_acquired; - m_capture_acquired = false; - m_gfxr_capture_loaded = false; m_correlated_capture_loaded = false; - if (release_capture) + if (m_capture_acquired.has_value()) { // We don't want other UI interaction as they cause race conditions. setDisabled(true); @@ -972,21 +968,20 @@ bool MainWindow::LoadFile(const std::string& file_name, bool is_temp_file, bool // Discard associated timing results. m_perf_counter_model->OnPerfCounterResultsGenerated("", std::nullopt); m_gpu_timing_model->OnGpuTimingResultsGenerated(""); - m_capture_manager->GetDataCoreLock().unlock(); *m_capture_stats = {}; m_overview_tab_view->LoadStatistics(); } + m_capture_acquired = std::nullopt; + m_progress_tracker.sendMessage("Loading " + file_name); m_last_request = LastRequest{.file_name = file_name, .is_temp_file = is_temp_file}; auto reference = Dive::FilePath{file_name}; - auto components = m_capture_manager->ResolveComponents(reference); - m_capture_manager->LoadFile(reference, components); + m_capture_manager->LoadFile(reference); // Clear task queue for fresh capture. m_loading_pending_task.clear(); - EmitLoadAssociatedFileTasks(components); return true; } @@ -1097,9 +1092,8 @@ void MainWindow::EmitLoadAssociatedFileTasks(const Dive::ComponentFilePaths& com //-------------------------------------------------------------------------------------------------- void MainWindow::OnFileLoaded(const LoadFileResult& loaded_file) { - DIVE_ASSERT(!m_capture_acquired); - m_capture_manager->GetDataCoreLock().lockForRead(); - m_capture_acquired = true; + DIVE_ASSERT(!m_capture_acquired.has_value()); + m_capture_acquired.emplace(&m_capture_manager->GetDataCoreLock()); bool load_succeed = (loaded_file.status == LoadFileResult::Status::kSuccess); if (!load_succeed) @@ -1108,6 +1102,12 @@ void MainWindow::OnFileLoaded(const LoadFileResult& loaded_file) m_error_dialog->OnLoadingFailure(loaded_file); } + if (load_succeed) + { + // Do the default loading first. + EmitLoadAssociatedFileTasks(loaded_file.components); + } + std::vector> tasks; std::swap(tasks, m_loading_pending_task); for (auto& task : tasks) @@ -1145,7 +1145,8 @@ void MainWindow::OnFileLoaded(const LoadFileResult& loaded_file) } m_hover_help->SetCurItem(HoverHelp::Item::kNone); - m_capture_file = QString(m_last_request.file_name.c_str()); + m_capture_file = QString::fromStdString(m_last_request.file_name); + m_gfxr_file = QString::fromStdString(loaded_file.components.gfxr.string()); qDebug() << "MainWindow::OnFileLoaded: m_capture_file: " << m_capture_file; QFileInfo file_info(m_capture_file); SetCurrentFile(m_capture_file, m_last_request.is_temp_file); @@ -1196,15 +1197,15 @@ void MainWindow::OnNormalCapture() { emit OnCapture(false); } //-------------------------------------------------------------------------------------------------- void MainWindow::OnAnalyzeCapture() { - if (!m_gfxr_capture_loaded && !m_correlated_capture_loaded) + if (m_gfxr_file.isEmpty()) { qDebug() << "Not launching AnalyzeDialog because GFXR file not succesfully loaded, instead " "prompting user to load a file"; OnOpenFile(); return; } - qDebug() << "Launching AnalyzeDialog with: " << m_capture_file; - AnalyzeCaptureStarted(m_capture_file); + qDebug() << "Launching AnalyzeDialog with: " << m_gfxr_file; + AnalyzeCaptureStarted(m_gfxr_file); } //-------------------------------------------------------------------------------------------------- diff --git a/ui/main_window.h b/ui/main_window.h index eeef94971..18762e7b2 100644 --- a/ui/main_window.h +++ b/ui/main_window.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -186,6 +187,7 @@ class MainWindow : public QMainWindow ProgressTrackerCallback m_progress_tracker; std::shared_ptr m_data_core; QString m_capture_file; + QString m_gfxr_file; QString m_last_file_path; Dive::LogRecord m_log_record; Dive::LogConsole m_log_console; @@ -303,7 +305,7 @@ class MainWindow : public QMainWindow std::unique_ptr m_available_metrics; std::unique_ptr m_capture_stats; - bool m_capture_acquired = false; + std::optional m_capture_acquired; LastRequest m_last_request; std::vector> m_loading_pending_task;