int vkDisplay::init(const unsigned int gpu_idx) { //m_gpuIdx = gpu_idx; #if 0 VkResult result = init_vk(gpu_idx); if (result != VK_SUCCESS) { vktrace_LogError("could not init vulkan library"); return -1; } else { m_initedVK = true; } #endif #if defined(PLATFORM_LINUX) const xcb_setup_t *setup; xcb_screen_iterator_t iter; int scr; m_pXcbConnection = xcb_connect(NULL, &scr); setup = xcb_get_setup(m_pXcbConnection); iter = xcb_setup_roots_iterator(setup); while (scr-- > 0) xcb_screen_next(&iter); m_pXcbScreen = iter.data; #endif return 0; }
bool InjectTracersIntoProcess(vktrace_process_info* pInfo) { bool bRecordingThreadsCreated = true; vktrace_thread tracingThread; if (vktrace_platform_remote_load_library(pInfo->hProcess, NULL, &tracingThread, NULL)) { // prepare data for capture threads pInfo->pCaptureThreads[0].pProcessInfo = pInfo; pInfo->pCaptureThreads[0].recordingThread = VKTRACE_NULL_THREAD; // create thread to record trace packets from the tracer pInfo->pCaptureThreads[0].recordingThread = vktrace_platform_create_thread(Process_RunRecordTraceThread, &(pInfo->pCaptureThreads[0])); if (pInfo->pCaptureThreads[0].recordingThread == VKTRACE_NULL_THREAD) { vktrace_LogError("Failed to create trace recording thread."); bRecordingThreadsCreated = false; } } else { // failed to inject a DLL bRecordingThreadsCreated = false; } return bRecordingThreadsCreated; }
VkResult vkDisplay::init_vk(unsigned int gpu_idx) { #if 0 VkApplicationInfo appInfo = {}; appInfo.pApplicationName = APP_NAME; appInfo.pEngineName = ""; appInfo.apiVersion = VK_API_VERSION; VkResult res = vkInitAndEnumerateGpus(&appInfo, NULL, VK_MAX_PHYSICAL_GPUS, &m_gpuCount, m_gpus); if ( res == VK_SUCCESS ) { // retrieve the GPU information for all GPUs for( uint32_t gpu = 0; gpu < m_gpuCount; gpu++) { size_t gpuInfoSize = sizeof(m_gpuProps[0]); // get the GPU physical properties: res = vkGetGpuInfo( m_gpus[gpu], VK_INFO_TYPE_PHYSICAL_GPU_PROPERTIES, &gpuInfoSize, &m_gpuProps[gpu]); if (res != VK_SUCCESS) vktrace_LogWarning("Failed to retrieve properties for gpu[%d] result %d", gpu, res); } res = VK_SUCCESS; } else if ((gpu_idx + 1) > m_gpuCount) { vktrace_LogError("vkInitAndEnumerate number of gpus does not include requested index: num %d, requested %d", m_gpuCount, gpu_idx); return -1; } else { vktrace_LogError("vkInitAndEnumerate failed"); return res; } // TODO add multi-gpu support always use gpu[gpu_idx] for now // get all extensions supported by this device gpu[gpu_idx] // first check if extensions are available and save a list of them bool foundWSIExt = false; for( int ext = 0; ext < sizeof( extensions ) / sizeof( extensions[0] ); ext++) { res = vkGetExtensionSupport( m_gpus[gpu_idx], extensions[ext] ); if (res == VK_SUCCESS) { m_extensions.push_back((char *) extensions[ext]); if (!strcmp(extensions[ext], "VK_WSI_WINDOWS")) foundWSIExt = true; } } if (!foundWSIExt) { vktrace_LogError("VK_WSI_WINDOWS extension not supported by gpu[%d]", gpu_idx); return VK_ERROR_INCOMPATIBLE_DEVICE; } // TODO generalize this: use one universal queue for now VkDeviceQueueCreateInfo dqci = {}; dqci.queueCount = 1; dqci.queueType = VK_QUEUE_UNIVERSAL; std::vector<float> queue_priorities (dqci.queueCount, 0.0); dqci.pQueuePriorities = queue_priorities.data(); // create the device enabling validation level 4 const char * const * extensionNames = &m_extensions[0]; VkDeviceCreateInfo info = {}; info.queueCreateInfoCount = 1; info.pQueueCreateInfos = &dqci; info.enabledExtensionCount = static_cast <uint32_t> (m_extensions.size()); info.ppEnabledExtensionNames = extensionNames; info.flags = VK_DEVICE_CREATE_VALIDATION; info.maxValidationLevel = VK_VALIDATION_LEVEL_4; bool32_t vkTrue = VK_TRUE; res = vkDbgSetGlobalOption( VK_DBG_OPTION_BREAK_ON_ERROR, sizeof( vkTrue ), &vkTrue ); if (res != VK_SUCCESS) vktrace_LogWarning("Could not set debug option break on error"); res = vkCreateDevice( m_gpus[0], &info, &m_dev[gpu_idx]); return res; #else return VK_ERROR_INITIALIZATION_FAILED; #endif }
int vkDisplay::create_window(const unsigned int width, const unsigned int height) { #if defined(PLATFORM_LINUX) uint32_t value_mask, value_list[32]; m_XcbWindow = xcb_generate_id(m_pXcbConnection); value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; value_list[0] = m_pXcbScreen->black_pixel; value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE; xcb_create_window(m_pXcbConnection, XCB_COPY_FROM_PARENT, m_XcbWindow, m_pXcbScreen->root, 0, 0, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, m_pXcbScreen->root_visual, value_mask, value_list); xcb_map_window(m_pXcbConnection, m_XcbWindow); xcb_flush(m_pXcbConnection); // TODO : Not sure of best place to put this, but I have all the info I need here so just setting it all here for now //m_XcbPlatformHandle.connection = m_pXcbConnection; //m_XcbPlatformHandle.root = m_pXcbScreen->root; m_surface.base.platform = VK_ICD_WSI_PLATFORM_XCB; m_surface.connection = m_pXcbConnection; m_surface.window = m_XcbWindow; return 0; #elif defined(WIN32) // Register Window class WNDCLASSEX wcex = {}; m_connection = GetModuleHandle(0); wcex.cbSize = sizeof( WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WindowProcVk; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = m_connection; wcex.hIcon = LoadIcon(wcex.hInstance, MAKEINTRESOURCE( IDI_ICON)); wcex.hCursor = LoadCursor( NULL, IDC_ARROW); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = APP_NAME; wcex.hIconSm = LoadIcon( wcex.hInstance, MAKEINTRESOURCE( IDI_ICON)); if( !RegisterClassEx( &wcex)) { vktrace_LogError("Failed to register windows class"); return -1; } // create the window m_windowHandle = CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, 0, 0, width, height, NULL, NULL, wcex.hInstance, NULL); if (m_windowHandle) { ShowWindow( m_windowHandle, SW_SHOWDEFAULT); m_windowWidth = width; m_windowHeight = height; } else { vktrace_LogError("Failed to create window"); return -1; } // TODO : Not sure of best place to put this, but I have all the info I need here so just setting it all here for now m_surface.base.platform = VK_ICD_WSI_PLATFORM_WIN32; m_surface.hinstance = wcex.hInstance; m_surface.hwnd = m_windowHandle; return 0; #endif }
BOOL vktrace_process_spawn(vktrace_process_info* pInfo) { assert(pInfo != NULL); #if defined(WIN32) { unsigned long processCreateFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED; char fullExePath[_MAX_PATH]; PROCESS_INFORMATION processInformation; STARTUPINFO si = { 0 }; si.cb = sizeof(si); memset(&processInformation, 0, sizeof(PROCESS_INFORMATION)); memset(fullExePath, 0, sizeof(char)*_MAX_PATH); fullExePath[0] = 0; SetLastError(0); if (0==SearchPath(NULL, pInfo->exeName, ".exe", ARRAYSIZE(fullExePath), fullExePath, NULL)) { vktrace_LogVerbose("Failed to spawn '%s'.", pInfo->exeName); return FALSE; } if (!CreateProcess(fullExePath, pInfo->fullProcessCmdLine, NULL, NULL, TRUE, processCreateFlags, NULL, pInfo->workingDirectory, &si, &processInformation)) { vktrace_LogVerbose("Failed to spawn '%s'.", fullExePath); return FALSE; } pInfo->hProcess = processInformation.hProcess; pInfo->hThread = processInformation.hThread; pInfo->processId = processInformation.dwProcessId; // TODO : Do we need to do anything with processInformation.dwThreadId? } #elif defined(PLATFORM_LINUX) pInfo->processId = fork(); if (pInfo->processId == -1) { vktrace_LogError("Failed to spawn process."); return FALSE; } else if (pInfo->processId == 0) { // Inside new process char *args[128]; const char delim[] = " \t"; unsigned int idx; // Change process name so the the tracer DLLs will behave as expected when loaded. // NOTE: Must be 15 characters or less. const char * tmpProcName = "vktraceChildProcess"; prctl(PR_SET_NAME, (unsigned long)tmpProcName, 0, 0, 0); // Change working directory if (chdir(pInfo->workingDirectory) == -1) { vktrace_LogError("Failed to set working directory."); } args[0] = pInfo->exeName; args[127] = NULL; idx = 1; args[idx] = strtok(pInfo->processArgs, delim); while ( args[idx] != NULL && idx < 128) { idx++; args[idx] = strtok(NULL, delim); } vktrace_LogDebug("exec process=%s argc=%u\n", pInfo->exeName, idx); #if 0 //uncoment to print out list of env vars char *env = environ[0]; idx = 0; while (env && strlen(env)) { if (strstr(env, "VK") || strstr(env, "LD")) vktrace_LogDebug("env[%d] = %s", idx++, env); else idx++; env = environ[idx]; } #endif if (execv(pInfo->exeName, args) < 0) { vktrace_LogError("Failed to spawn process."); exit(1); } } #endif return TRUE; }
// ------------------------------------------------------------------------------------------------ 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; }
//The function source code is modified from __HOOKED_vkFlushMappedMemoryRanges //for coherent map, need this function to dump data so simulate target application write data when playback. VkResult vkFlushMappedMemoryRangesWithoutAPICall( VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges) { VkResult result = VK_SUCCESS; vktrace_trace_packet_header* pHeader; size_t rangesSize = 0; size_t dataSize = 0; uint32_t iter; packet_vkFlushMappedMemoryRanges* pPacket = nullptr; #ifdef USE_PAGEGUARD_SPEEDUP PBYTE *ppPackageData = new PBYTE[memoryRangeCount]; bool bOPTTargetWithoutChange = getPageGuardControlInstance().vkFlushMappedMemoryRangesPageGuardHandle(device, memoryRangeCount, pMemoryRanges, ppPackageData);//the packet is not needed if no any change on data of all ranges if (bOPTTargetWithoutChange) { return result; } #endif // find out how much memory is in the ranges for (iter = 0; iter < memoryRangeCount; iter++) { VkMappedMemoryRange* pRange = (VkMappedMemoryRange*)&pMemoryRanges[iter]; rangesSize += vk_size_vkmappedmemoryrange(pRange); dataSize += (size_t)pRange->size; } #ifdef USE_PAGEGUARD_SPEEDUP dataSize = getPageGuardControlInstance().getALLChangedPackageSizeInMappedMemory(device, memoryRangeCount, pMemoryRanges, ppPackageData); #endif CREATE_TRACE_PACKET(vkFlushMappedMemoryRanges, rangesSize + sizeof(void*)*memoryRangeCount + dataSize); pPacket = interpret_body_as_vkFlushMappedMemoryRanges(pHeader); vktrace_add_buffer_to_trace_packet(pHeader, (void**)&(pPacket->pMemoryRanges), rangesSize, pMemoryRanges); vktrace_finalize_buffer_address(pHeader, (void**)&(pPacket->pMemoryRanges)); // insert into packet the data that was written by CPU between the vkMapMemory call and here // create a temporary local ppData array and add it to the packet (to reserve the space for the array) void** ppTmpData = (void **)malloc(memoryRangeCount * sizeof(void*)); vktrace_add_buffer_to_trace_packet(pHeader, (void**)&(pPacket->ppData), sizeof(void*)*memoryRangeCount, ppTmpData); free(ppTmpData); // now the actual memory vktrace_enter_critical_section(&g_memInfoLock); for (iter = 0; iter < memoryRangeCount; iter++) { VkMappedMemoryRange* pRange = (VkMappedMemoryRange*)&pMemoryRanges[iter]; VKAllocInfo* pEntry = find_mem_info_entry(pRange->memory); if (pEntry != nullptr) { assert(pEntry->handle == pRange->memory); assert(pEntry->totalSize >= (pRange->size + pRange->offset)); assert(pEntry->totalSize >= pRange->size); assert(pRange->offset >= pEntry->rangeOffset && (pRange->offset + pRange->size) <= (pEntry->rangeOffset + pEntry->rangeSize)); #ifdef USE_PAGEGUARD_SPEEDUP LPPageGuardMappedMemory pOPTMemoryTemp = getPageGuardControlInstance().findMappedMemoryObject(device, pRange); VkDeviceSize OPTPackageSizeTemp = 0; if (pOPTMemoryTemp) { PBYTE pOPTDataTemp = pOPTMemoryTemp->getChangedDataPackage(&OPTPackageSizeTemp); setFlagTovkFlushMappedMemoryRangesSpecial(pOPTDataTemp); vktrace_add_buffer_to_trace_packet(pHeader, (void**)&(pPacket->ppData[iter]), OPTPackageSizeTemp, pOPTDataTemp); pOPTMemoryTemp->clearChangedDataPackage(); pOPTMemoryTemp->resetMemoryObjectAllChangedFlagAndPageGuard(); } else { PBYTE pOPTDataTemp = getPageGuardControlInstance().getChangedDataPackageOutOfMap(ppPackageData, iter, &OPTPackageSizeTemp); setFlagTovkFlushMappedMemoryRangesSpecial(pOPTDataTemp); vktrace_add_buffer_to_trace_packet(pHeader, (void**)&(pPacket->ppData[iter]), OPTPackageSizeTemp, pOPTDataTemp); getPageGuardControlInstance().clearChangedDataPackageOutOfMap(ppPackageData, iter); } #else vktrace_add_buffer_to_trace_packet(pHeader, (void**)&(pPacket->ppData[iter]), pRange->size, pEntry->pData + pRange->offset); #endif vktrace_finalize_buffer_address(pHeader, (void**)&(pPacket->ppData[iter])); pEntry->didFlush = true; } else { vktrace_LogError("Failed to copy app memory into trace packet (idx = %u) on vkFlushedMappedMemoryRanges", pHeader->global_packet_index); } } #ifdef USE_PAGEGUARD_SPEEDUP delete[] ppPackageData; #endif vktrace_leave_critical_section(&g_memInfoLock); // now finalize the ppData array since it is done being updated vktrace_finalize_buffer_address(pHeader, (void**)&(pPacket->ppData)); //result = mdd(device)->devTable.FlushMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges); vktrace_set_packet_entrypoint_end_time(pHeader); pPacket->device = device; pPacket->memoryRangeCount = memoryRangeCount; pPacket->result = result; FINISH_TRACE_PACKET(); return result; }
vktrace_trace_packet_replay_library* ReplayFactory::Create(uint8_t tracerId) { vktrace_trace_packet_replay_library* pReplayer = NULL; //void* pLibrary = NULL; const VKTRACE_TRACER_REPLAYER_INFO* pReplayerInfo = &(gs_tracerReplayerInfo[tracerId]); if (pReplayerInfo->tracerId != tracerId) { vktrace_LogError("Replayer info for TracerId (%d) failed consistency check.", tracerId); assert(!"TracerId in VKTRACE_TRACER_REPLAYER_INFO does not match the requested tracerId. The array needs to be corrected."); } // Vulkan library is built into replayer executable if (tracerId == VKTRACE_TID_VULKAN) { pReplayer = VKTRACE_NEW(vktrace_trace_packet_replay_library); if (pReplayer == NULL) { vktrace_LogError("Failed to allocate replayer library."); } else { pReplayer->pLibrary = NULL; pReplayer->SetLogCallback = VkReplaySetLogCallback; pReplayer->SetLogLevel = VkReplaySetLogLevel; pReplayer->RegisterDbgMsgCallback = VkReplayRegisterDbgMsgCallback; pReplayer->GetSettings = VkReplayGetSettings; pReplayer->UpdateFromSettings = VkReplayUpdateFromSettings; pReplayer->Initialize = VkReplayInitialize; pReplayer->Deinitialize = VkReplayDeinitialize; pReplayer->Interpret = VkReplayInterpret; pReplayer->Replay = VkReplayReplay; pReplayer->Dump = VkReplayDump; pReplayer->GetFrameNumber = VkReplayGetFrameNumber; pReplayer->ResetFrameNumber = VkReplayResetFrameNumber; } } // if (pReplayerInfo->needsReplayer == TRUE) // { // pLibrary = vktrace_platform_open_library(pReplayerInfo->replayerLibraryName); // if (pLibrary == NULL) // { // vktrace_LogError("Failed to load replayer '%s.", pReplayerInfo->replayerLibraryName); //#if defined(PLATFORM_LINUX) // char* error = dlerror(); // vktrace_LogError(error); //#endif // } // } // else // { // vktrace_LogError("A replayer was requested for TracerId (%d), but it does not require a replayer.", tracerId); // assert(!"Invalid TracerId supplied to ReplayFactory"); // } // // if (pLibrary != NULL) // { // pReplayer = VKTRACE_NEW(vktrace_trace_packet_replay_library); // if (pReplayer == NULL) // { // vktrace_LogError("Failed to allocate replayer library."); // vktrace_platform_close_library(pLibrary); // } // else // { // pReplayer->pLibrary = pLibrary; // // pReplayer->SetLogCallback = (funcptr_vkreplayer_setlogcallback)vktrace_platform_get_library_entrypoint(pLibrary, "SetLogCallback"); // pReplayer->SetLogLevel = (funcptr_vkreplayer_setloglevel)vktrace_platform_get_library_entrypoint(pLibrary, "SetLogLevel"); // // pReplayer->RegisterDbgMsgCallback = (funcptr_vkreplayer_registerdbgmsgcallback)vktrace_platform_get_library_entrypoint(pLibrary, "RegisterDbgMsgCallback"); // pReplayer->GetSettings = (funcptr_vkreplayer_getSettings)vktrace_platform_get_library_entrypoint(pLibrary, "GetSettings"); // pReplayer->UpdateFromSettings = (funcptr_vkreplayer_updatefromsettings)vktrace_platform_get_library_entrypoint(pLibrary, "UpdateFromSettings"); // pReplayer->Initialize = (funcptr_vkreplayer_initialize)vktrace_platform_get_library_entrypoint(pLibrary, "Initialize"); // pReplayer->Deinitialize = (funcptr_vkreplayer_deinitialize)vktrace_platform_get_library_entrypoint(pLibrary, "Deinitialize"); // pReplayer->Interpret = (funcptr_vkreplayer_interpret)vktrace_platform_get_library_entrypoint(pLibrary, "Interpret"); // pReplayer->Replay = (funcptr_vkreplayer_replay)vktrace_platform_get_library_entrypoint(pLibrary, "Replay"); // pReplayer->Dump = (funcptr_vkreplayer_dump)vktrace_platform_get_library_entrypoint(pLibrary, "Dump"); // // if (pReplayer->SetLogCallback == NULL || // pReplayer->SetLogLevel == NULL || // pReplayer->RegisterDbgMsgCallback == NULL || // pReplayer->GetSettings == NULL || // pReplayer->UpdateFromSettings == NULL || // pReplayer->Initialize == NULL || // pReplayer->Deinitialize == NULL || // pReplayer->Interpret == NULL || // pReplayer->Replay == NULL || // pReplayer->Dump == NULL) // { // VKTRACE_DELETE(pReplayer); // vktrace_platform_close_library(pLibrary); // pReplayer = NULL; // } // } // } return pReplayer; }
int main_loop(Sequencer &seq, vktrace_trace_packet_replay_library *replayerArray[], vkreplayer_settings settings) { int err = 0; vktrace_trace_packet_header *packet; unsigned int res; vktrace_trace_packet_replay_library *replayer = NULL; vktrace_trace_packet_message* msgPacket; struct seqBookmark startingPacket; bool trace_running = true; int prevFrameNumber = -1; // record the location of looping start packet seq.record_bookmark(); seq.get_bookmark(startingPacket); while (settings.numLoops > 0) { while ((packet = seq.get_next_packet()) != NULL && trace_running) { switch (packet->packet_id) { case VKTRACE_TPI_MESSAGE: msgPacket = vktrace_interpret_body_as_trace_packet_message(packet); vktrace_LogAlways("Packet %lu: Traced Message (%s): %s", packet->global_packet_index, vktrace_LogLevelToShortString(msgPacket->type), msgPacket->message); 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: { if (packet->tracer_id >= VKTRACE_MAX_TRACER_ID_ARRAY_SIZE || packet->tracer_id == VKTRACE_TID_RESERVED) { vktrace_LogError("Tracer_id from packet num packet %d invalid.", packet->packet_id); continue; } replayer = replayerArray[packet->tracer_id]; if (replayer == NULL) { vktrace_LogWarning("Tracer_id %d has no valid replayer.", packet->tracer_id); continue; } if (packet->packet_id >= VKTRACE_TPI_BEGIN_API_HERE) { // replay the API packet res = replayer->Replay(replayer->Interpret(packet)); if (res != VKTRACE_REPLAY_SUCCESS) { vktrace_LogError("Failed to replay packet_id %d.",packet->packet_id); return -1; } // frame control logic int frameNumber = replayer->GetFrameNumber(); if (prevFrameNumber != frameNumber) { prevFrameNumber = frameNumber; if (frameNumber == settings.loopStartFrame) { // record the location of looping start packet seq.record_bookmark(); seq.get_bookmark(startingPacket); } if (frameNumber == settings.loopEndFrame) { trace_running = false; } } } else { vktrace_LogError("Bad packet type id=%d, index=%d.", packet->packet_id, packet->global_packet_index); return -1; } } } } settings.numLoops--; seq.set_bookmark(startingPacket); trace_running = true; if (replayer != NULL) { replayer->ResetFrameNumber(); } } return err; }