//----------------------------------------------------------------------------- void vktraceviewer_QTraceFileLoader::loadTraceFile(const QString& filename) { // open trace file and read in header memset(&m_traceFileInfo, 0, sizeof(vktraceviewer_trace_file_info)); m_traceFileInfo.pFile = fopen(filename.toStdString().c_str(), "rb"); bool bOpened = (m_traceFileInfo.pFile != NULL); if (!bOpened) { emit OutputMessage(VKTRACE_LOG_ERROR, "Unable to open file."); } else { m_traceFileInfo.filename = vktrace_allocate_and_copy(filename.toStdString().c_str()); if (populate_trace_file_info(&m_traceFileInfo) == FALSE) { emit OutputMessage(VKTRACE_LOG_ERROR, "Unable to populate trace file info from file."); bOpened = false; } else { // Make sure trace file version is supported if (m_traceFileInfo.header.trace_file_version < VKTRACE_TRACE_FILE_VERSION_MINIMUM_COMPATIBLE) { emit OutputMessage(VKTRACE_LOG_ERROR, QString("Trace file version %1 is older than minimum compatible version (%2).\nYou'll need to make a new trace file, or use an older replayer.").arg(m_traceFileInfo.header.trace_file_version).arg(VKTRACE_TRACE_FILE_VERSION_MINIMUM_COMPATIBLE)); bOpened = false; } #ifdef USE_STATIC_CONTROLLER_LIBRARY m_pController = vtvCreateQController(); if (bOpened) #else if (!load_controllers(&m_traceFileInfo)) { emit OutputMessage(VKTRACE_LOG_ERROR, "Failed to load necessary debug controllers."); bOpened = false; } else if (bOpened) #endif { connect(m_pController, SIGNAL(OutputMessage(VktraceLogLevel, const QString&)), this, SIGNAL(OutputMessage(VktraceLogLevel, const QString&))); connect(m_pController, SIGNAL(OutputMessage(VktraceLogLevel, uint64_t, const QString&)), this, SIGNAL(OutputMessage(VktraceLogLevel, uint64_t, const QString&))); // interpret the trace file packets for (uint64_t i = 0; i < m_traceFileInfo.packetCount; i++) { vktraceviewer_trace_file_packet_offsets* pOffsets = &m_traceFileInfo.pPacketOffsets[i]; switch (pOffsets->pHeader->packet_id) { case VKTRACE_TPI_MESSAGE: m_traceFileInfo.pPacketOffsets[i].pHeader = vktrace_interpret_body_as_trace_packet_message(pOffsets->pHeader)->pHeader; break; case VKTRACE_TPI_MARKER_CHECKPOINT: break; case VKTRACE_TPI_MARKER_API_BOUNDARY: break; case VKTRACE_TPI_MARKER_API_GROUP_BEGIN: break; case VKTRACE_TPI_MARKER_API_GROUP_END: break; case VKTRACE_TPI_MARKER_TERMINATE_PROCESS: break; //TODO processing code for all the above cases default: { vktrace_trace_packet_header* pHeader = m_pController->InterpretTracePacket(pOffsets->pHeader); if (pHeader == NULL) { bOpened = false; emit OutputMessage(VKTRACE_LOG_ERROR, QString("Unrecognized packet type: %1").arg(pOffsets->pHeader->packet_id)); m_traceFileInfo.pPacketOffsets[i].pHeader = NULL; break; } m_traceFileInfo.pPacketOffsets[i].pHeader = pHeader; } } // break from loop if there is an error if (bOpened == false) { break; } } #ifdef USE_STATIC_CONTROLLER_LIBRARY vtvDeleteQController(&m_pController); #else m_controllerFactory.Unload(&m_pController); #endif } } // TODO: We don't really want to close the trace file yet. // I think we want to keep it open so that we can dynamically read from it. // BUT we definitely don't want it to get locked open, so we need a smart // way to open / close from it when reading. fclose(m_traceFileInfo.pFile); m_traceFileInfo.pFile = NULL; } // populate the UI based on trace file info emit TraceFileLoaded(bOpened, m_traceFileInfo, m_controllerFilename); emit Finished(); }
// ------------------------------------------------------------------------------------------------ int main(int argc, char* argv[]) { memset(&g_settings, 0, sizeof(vktrace_settings)); vktrace_LogSetCallback(loggingCallback); vktrace_LogSetLevel(VKTRACE_LOG_ERROR); // setup defaults memset(&g_default_settings, 0, sizeof(vktrace_settings)); g_default_settings.output_trace = vktrace_allocate_and_copy("vktrace_out.vktrace"); g_default_settings.verbosity = "errors"; g_default_settings.screenshotList = NULL; if (vktrace_SettingGroup_init(&g_settingGroup, NULL, argc, argv, &g_settings.arguments) != 0) { // invalid cmd-line parameters vktrace_SettingGroup_delete(&g_settingGroup); vktrace_free(g_default_settings.output_trace); return -1; } else { // Validate vktrace inputs BOOL validArgs = TRUE; if (g_settings.output_trace == NULL || strlen (g_settings.output_trace) == 0) { validArgs = FALSE; } else { size_t len = strlen(g_settings.output_trace); if (strncmp(&g_settings.output_trace[len-8], ".vktrace", 8) != 0) { // output trace filename does not end in .vktrace vktrace_LogError("Output trace file specified with -o parameter must have a '.vktrace' extension."); validArgs = FALSE; } } if (strcmp(g_settings.verbosity, "quiet") == 0) vktrace_LogSetLevel(VKTRACE_LOG_NONE); else if (strcmp(g_settings.verbosity, "errors") == 0) vktrace_LogSetLevel(VKTRACE_LOG_ERROR); else if (strcmp(g_settings.verbosity, "warnings") == 0) vktrace_LogSetLevel(VKTRACE_LOG_WARNING); else if (strcmp(g_settings.verbosity, "full") == 0) vktrace_LogSetLevel(VKTRACE_LOG_VERBOSE); #if _DEBUG else if (strcmp(g_settings.verbosity, "debug") == 0) vktrace_LogSetLevel(VKTRACE_LOG_DEBUG); #endif else { vktrace_LogSetLevel(VKTRACE_LOG_ERROR); validArgs = FALSE; } vktrace_set_global_var("_VK_TRACE_VERBOSITY", g_settings.verbosity); if (validArgs == FALSE) { vktrace_SettingGroup_print(&g_settingGroup); return -1; } if (g_settings.program == NULL || strlen(g_settings.program) == 0) { vktrace_LogWarning("No program (-p) parameter found: Will run vktrace as server."); printf("Running vktrace as server...\n"); fflush(stdout); g_settings.arguments = NULL; } else { if (g_settings.working_dir == NULL || strlen(g_settings.working_dir) == 0) { CHAR* buf = VKTRACE_NEW_ARRAY(CHAR, 4096); vktrace_LogVerbose("No working directory (-w) parameter found: Assuming executable's path as working directory."); vktrace_platform_full_path(g_settings.program, 4096, buf); g_settings.working_dir = vktrace_platform_extract_path(buf); VKTRACE_DELETE(buf); } vktrace_LogVerbose("Running vktrace as parent process will spawn child process: %s", g_settings.program); if (g_settings.arguments != NULL && strlen(g_settings.arguments) > 0) { vktrace_LogVerbose("Args to be passed to child process: '%s'", g_settings.arguments); } } } if (g_settings.screenshotList) { // Export list to screenshot layer vktrace_set_global_var("_VK_SCREENSHOT", g_settings.screenshotList); } else { vktrace_set_global_var("_VK_SCREENSHOT",""); } unsigned int serverIndex = 0; do { // Create and start the process or run in server mode BOOL procStarted = TRUE; vktrace_process_info procInfo; memset(&procInfo, 0, sizeof(vktrace_process_info)); if (g_settings.program != NULL) { procInfo.exeName = vktrace_allocate_and_copy(g_settings.program); procInfo.processArgs = vktrace_allocate_and_copy(g_settings.arguments); procInfo.fullProcessCmdLine = vktrace_copy_and_append(g_settings.program, " ", g_settings.arguments); procInfo.workingDirectory = vktrace_allocate_and_copy(g_settings.working_dir); procInfo.traceFilename = vktrace_allocate_and_copy(g_settings.output_trace); } else { const char *pExtension = strrchr(g_settings.output_trace, '.'); char *basename = vktrace_allocate_and_copy_n(g_settings.output_trace, (int) ((pExtension == NULL) ? strlen(g_settings.output_trace) : pExtension - g_settings.output_trace)); char num[16]; #ifdef PLATFORM_LINUX snprintf(num, 16, "%u", serverIndex); #elif defined(WIN32) _snprintf_s(num, 16, _TRUNCATE, "%u", serverIndex); #endif procInfo.traceFilename = vktrace_copy_and_append(basename, num, pExtension); } procInfo.parentThreadId = vktrace_platform_get_thread_id(); // setup tracer, only Vulkan tracer suppported PrepareTracers(&procInfo.pCaptureThreads); if (g_settings.program != NULL) { char *instEnv = vktrace_get_global_var("VK_INSTANCE_LAYERS"); // Add ScreenShot layer if enabled if (g_settings.screenshotList && (!instEnv || !strstr(instEnv, "VK_LAYER_LUNARG_screenshot"))) { if (!instEnv || strlen(instEnv) == 0) vktrace_set_global_var("VK_INSTANCE_LAYERS", "VK_LAYER_LUNARG_screenshot"); else { char *newEnv = vktrace_copy_and_append(instEnv, VKTRACE_LIST_SEPARATOR, "VK_LAYER_LUNARG_screenshot"); vktrace_set_global_var("VK_INSTANCE_LAYERS", newEnv); } instEnv = vktrace_get_global_var("VK_INSTANCE_LAYERS"); } char *devEnv = vktrace_get_global_var("VK_DEVICE_LAYERS"); if (g_settings.screenshotList && (!devEnv || !strstr(devEnv, "VK_LAYER_LUNARG_screenshot"))) { if (!devEnv || strlen(devEnv) == 0) vktrace_set_global_var("VK_DEVICE_LAYERS", "VK_LAYER_LUNARG_screenshot"); else { char *newEnv = vktrace_copy_and_append(devEnv, VKTRACE_LIST_SEPARATOR, "VK_LAYER_LUNARG_screenshot"); vktrace_set_global_var("VK_DEVICE_LAYERS", newEnv); } devEnv = vktrace_get_global_var("VK_DEVICE_LAYERS"); } // Add vktrace_layer enable env var if needed if (!instEnv || strlen(instEnv) == 0) { vktrace_set_global_var("VK_INSTANCE_LAYERS", "VK_LAYER_LUNARG_vktrace"); } else if (instEnv != strstr(instEnv, "VK_LAYER_LUNARG_vktrace")) { char *newEnv = vktrace_copy_and_append("VK_LAYER_LUNARG_vktrace", VKTRACE_LIST_SEPARATOR, instEnv); vktrace_set_global_var("VK_INSTANCE_LAYERS", newEnv); } if (!devEnv || strlen(devEnv) == 0) { vktrace_set_global_var("VK_DEVICE_LAYERS", "VK_LAYER_LUNARG_vktrace"); } else if (devEnv != strstr(devEnv, "VK_LAYER_LUNARG_vktrace")) { char *newEnv = vktrace_copy_and_append("VK_LAYER_LUNARG_vktrace", VKTRACE_LIST_SEPARATOR, devEnv); vktrace_set_global_var("VK_DEVICE_LAYERS", newEnv); } // call CreateProcess to launch the application procStarted = vktrace_process_spawn(&procInfo); } if (procStarted == FALSE) { vktrace_LogError("Failed to setup remote process."); } else { if (InjectTracersIntoProcess(&procInfo) == FALSE) { vktrace_LogError("Failed to setup tracer communication threads."); return -1; } // create watchdog thread to monitor existence of remote process if (g_settings.program != NULL) procInfo.watchdogThread = vktrace_platform_create_thread(Process_RunWatchdogThread, &procInfo); #if defined(PLATFORM_LINUX) // Sync wait for local threads and remote process to complete. vktrace_platform_sync_wait_for_thread(&(procInfo.pCaptureThreads[0].recordingThread)); if (g_settings.program != NULL) vktrace_platform_sync_wait_for_thread(&procInfo.watchdogThread); #else vktrace_platform_resume_thread(&procInfo.hThread); // Now into the main message loop, listen for hotkeys to send over. MessageLoop(); #endif } vktrace_process_info_delete(&procInfo); serverIndex++; } while (g_settings.program == NULL); vktrace_SettingGroup_delete(&g_settingGroup); vktrace_free(g_default_settings.output_trace); return 0; }
void vktraceviewer::onTraceFileLoaded(bool bSuccess, vktraceviewer_trace_file_info fileInfo, const QString& controllerFilename) { QApplication::restoreOverrideCursor(); if (fileInfo.packetCount == 0) { LogWarning("The trace file has 0 packets."); } else if (fileInfo.pPacketOffsets == NULL) { LogError("No packet offsets read from trace file."); bSuccess = false; } if (!bSuccess) { LogAlways("...FAILED!"); QMessageBox::critical(this, tr("Error"), tr("Could not open trace file.")); close_trace_file(); if (m_bGeneratingTrace) { // if the user was generating a trace file, but the trace failed to load, // then re-spawn the generate trace dialog. prompt_generate_trace(); } } else { m_traceFileInfo = fileInfo; setWindowTitle(QString(m_traceFileInfo.filename) + " - " + g_PROJECT_NAME); LogAlways("...success!"); // update settings to reflect the currently open file g_settings.trace_file_to_open = vktrace_allocate_and_copy(m_traceFileInfo.filename); vktraceviewer_settings_updated(); #ifndef USE_STATIC_CONTROLLER_LIBRARY if (!controllerFilename.isEmpty()) { m_pController = m_controllerFactory.Load(controllerFilename.toStdString().c_str()); } #else m_pController = vtvCreateQController(); #endif if (m_pController != NULL) { connect(m_pController, SIGNAL(OutputMessage(VktraceLogLevel, const QString&)), this, SLOT(OnOutputMessage(VktraceLogLevel, const QString&))); connect(m_pController, SIGNAL(OutputMessage(VktraceLogLevel, uint64_t, const QString&)), this, SLOT(OnOutputMessage(VktraceLogLevel, uint64_t, const QString&))); // Merge in settings from the controller. // This won't replace settings that may have already been loaded from disk. vktrace_SettingGroup_merge(m_pController->GetSettings(), &g_pAllSettings, &g_numAllSettings); // now update the controller with the loaded settings m_pController->UpdateFromSettings(g_pAllSettings, g_numAllSettings); //// trace file was loaded, now attempt to open additional session data //if (load_or_create_session(filename.c_str(), m_pTraceReader) == false) //{ // // failing to load session data is not critical, but may result in unexpected behavior at times. // vktraceviewer_output_error("VkTraceViewer was unable to create a session folder to save viewing information. Functionality may be limited."); //} // Update the UI with the controller m_pController->LoadTraceFile(&m_traceFileInfo, this); } // update toolbar ui->searchTextBox->setEnabled(true); ui->searchPrevButton->setEnabled(true); ui->searchNextButton->setEnabled(true); ui->action_Close->setEnabled(true); ui->actionExport_API_Calls->setEnabled(true); ui->prevDrawcallButton->setEnabled(true); ui->nextDrawcallButton->setEnabled(true); // reset flag indicating that the ui may have been generating a trace file. m_bGeneratingTrace = false; GenerateTraceFileStats(); }