//-------------------------------------------------------------------------- /// End the frame. //-------------------------------------------------------------------------- void ModernAPILayerManager::EndFrame() { // Check if we need to collect a trace for this currently-rendering frame. MultithreadedTraceAnalyzerLayer* pTraceAnalyzer = GetTraceAnalyzerLayer(); bool bDisableObjectDataBase = false; if (mCmdFrameCaptureWithSave.IsActive()) { // Extract the capture mode argument from the m_captureType = (CaptureType)mCmdFrameCaptureWithSave.GetCaptureType(); m_captureCount = mCmdFrameCaptureWithSave.GetCaptureCount(); // Exclude Frame Capture if (m_captureType > 0 && m_captureType < 4) { // Now need to make sure that the MultithreadedTraceAnalyzerLayer is on the stack. if (pTraceAnalyzer != nullptr) { pTraceAnalyzer->DisableLinkedTraceCollection(); } // stop objectInspector from writing to disk bDisableObjectDataBase = true; } } LayerManager::EndFrame(); // If the TraceAnalyzer layer is active, and a trace was triggered by keypress, disable the tracing layer. if (pTraceAnalyzer != nullptr) { // Check if the previous frame had been traced. If so, we'll need to clean up the TraceAnalyzer from the stack. bool bTracedLastFrame = (pTraceAnalyzer->GetLastTracedFrameIndex() == static_cast<int>(GetCurrentFrameIndex())); if (bTracedLastFrame && mbTraceTriggeredFromKeypress) { Log(logMESSAGE, "Keypress capture ending.\n"); // Enable trace collection for the next rendered frame. pTraceAnalyzer->DisableLinkedTraceCollection(); if (pTraceAnalyzer->IsEnabled()) { // Remove the TraceAnalyzerLayer that we pushed earlier. PopEnabledLayer(); } #if ENABLE_CLIENT_LOCKOUT_ON_KEYPRESS // Tell the GPUPerfServer to accept all incoming commands SG_SET_BOOL(ForceRenderStallState, false); #endif // ENABLE_CLIENT_LOCKOUT_ON_KEYPRESS // Disable the keypress flag- we've finished tracing the frame. mbTraceTriggeredFromKeypress = false; } } // need to disable ObjectDataBase after because mCmdFrameCaptureWithSave is cleared before object EndFrame if (bDisableObjectDataBase) { // stop objectInspector from writing to disk ObjectDatabaseProcessor* objectDatabase = GetObjectDatabaseProcessor(); objectDatabase->DisableObjectDatabaseCollection(); } }
//-------------------------------------------------------------- // LaunchAppInNewProcess //-------------------------------------------------------------- PROCESS_INFORMATION ProcessTracker::LaunchAppInNewProcess(gtASCIIString strApp, gtASCIIString strDir, gtASCIIString strArgs, osModuleArchitecture binaryType) { #ifdef _LINUX PS_UNREFERENCED_PARAMETER(binaryType); #endif LogConsole(logMESSAGE, "About to launch: %s\n", strApp.asCharArray()); LogConsole(logMESSAGE, "Params: %s\n", strArgs.asCharArray()); LogConsole(logMESSAGE, "Working Directory: %s\n", strDir.asCharArray()); // Get app directory and make it default if (strDir.isEmpty()) { size_t pos = strApp.find_last_of("\\"); if (pos != std::string::npos) { strDir = strApp.substr(0, (int)pos); if (strApp[0] == '\"') { strDir += "\""; } } } PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); #ifdef _WIN32 DWORD dwFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED; SetLastError(0); STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); #endif // Cmd line has to include the exe name since many apps expect the executable name to be in argv[0]! // Note argv[0] on the command line needs to be surrounded with quotes if it contains spaces. // The arguments in strArgs have already been "quoted" as they are parsed. gtASCIIString strCmdLine = AddQuotesIfStringHasSpaces(strApp.asCharArray()); strCmdLine += " "; strCmdLine += strArgs; LogConsole(logMESSAGE, "strApp: %s\n", strApp.asCharArray()); LogConsole(logMESSAGE, "strCmdLine: %s\n", strCmdLine.asCharArray()); // Attempt to initialize the environment that the new process will run in. The child process should inherit "this" environment. if (!PrelaunchEnvironmentInitialization()) { // Log a warning if this failed- initializing the environment for the new process can fail if Mantle support isn't installed. // In these cases, if the user is attempting to debug a Mantle application, they will have bigger problems to deal with. // In cases where a DX/GL app is being debugged, this warning can be ignored without any side effects. Log(logWARNING, "Environment initialization failed. If using DX/GL, it is safe to ignore this warning.\n"); } BOOL succeeded = FALSE; #ifdef _WIN32 char microDLLPath[PS_MAX_PATH]; const char* strServerPath; strServerPath = SG_GET_PATH(ServerPath); if (SG_GET_BOOL(OptionDllReplacement) == true) { DllReplacement::SetDllDirectory(binaryType == OS_X86_64_ARCHITECTURE); } // if using manual dll replacement or the AppInit_DLLs registry setting, don't use any kind of dll injection if (SG_GET_BOOL(OptionManualDllReplacement) == true || SG_GET_BOOL(OptionAppInitDll)) { succeeded = CreateProcess(strApp.asCharArray(), (LPSTR)strCmdLine.asCharArray(), NULL, NULL, TRUE, dwFlags, NULL, strDir.asCharArray(), &si, &pi); } else { #ifdef X64 // can only launch 64 bit applications if (binaryType != OS_X86_64_ARCHITECTURE) { sprintf_s(microDLLPath, PS_MAX_PATH, "%s" MICRODLLNAME "%s%s.dll", SG_GET_PATH(ServerPath), GDT_DEBUG_SUFFIX, GDT_BUILD_SUFFIX); succeeded = AMDT::CreateProcessAndInjectDll(strApp.asCharArray(), (LPSTR)strCmdLine.asCharArray(), NULL, NULL, TRUE, dwFlags, NULL, strDir.asCharArray(), &si, &pi, microDLLPath); } #else if (binaryType != OS_I386_ARCHITECTURE) { sprintf_s(microDLLPath, PS_MAX_PATH, "%s" MICRODLLNAME "-x64%s%s.dll", SG_GET_PATH(ServerPath), GDT_DEBUG_SUFFIX, GDT_BUILD_SUFFIX); succeeded = AMDT::CreateProcessAndInjectDll(strApp.asCharArray(), (LPSTR)strCmdLine.asCharArray(), NULL, NULL, TRUE, dwFlags, NULL, strDir.asCharArray(), &si, &pi, microDLLPath); } #endif // X64 else { succeeded = AMDT::CreateProcessAndInjectDll(strApp.asCharArray(), (LPSTR)strCmdLine.asCharArray(), NULL, NULL, TRUE, dwFlags, NULL, strDir.asCharArray(), &si, &pi, SG_GET_PATH(MicroDLLPath)); } } #else // Create the app process succeeded = CreateProcess(strApp.asCharArray(), strCmdLine.asCharArray(), strDir.asCharArray(), &pi); #endif // _WIN32 if (!succeeded) { osSystemErrorCode systemLastError = osGetLastSystemError(); gtString systemErrorString; osGetLastSystemErrorAsString(systemErrorString); Log(logERROR, "CreateProcessAndInjectDll failed; Error %d: %s\n", systemLastError, systemErrorString.asASCIICharArray()); pi.dwProcessId = 0; } #ifdef _WIN32 else { // Check to see if the Steam.exe has been hooked and if so, set the value in shared memory // If Steam.exe was used to launch the target application, then the checks for cmd.exe and fcx.exe // need to be ignored. if (strApp.length() > 0) { if (strstr(strApp.toLowerCase().asCharArray(), "steam.exe") != NULL) { SG_SET_BOOL(SteamInjected, true); } ShowLauncherReminder(strApp.toLowerCase().asCharArray()); } else { if (strstr(strCmdLine.toLowerCase().asCharArray(), "steam.exe") != NULL) { SG_SET_BOOL(SteamInjected, true); } ShowLauncherReminder(strCmdLine.toLowerCase().asCharArray()); } } #endif // _WIN32 return pi; }
//-------------------------------------------------------------------------- /// Begin the frame. //-------------------------------------------------------------------------- void ModernAPILayerManager::BeginFrame() { GetPendingRequests(); if (mCmdSetSessionName.IsActive()) { gtASCIIString sessionName = mCmdSetSessionName.GetValue(); if (SessionManager::Instance()->SetSessionName(sessionName) == false) { mCmdSetSessionName.Send("Failed"); } else { mCmdSetSessionName.Send("OK"); } } if (mCmdSetProjectName.IsActive()) { gtASCIIString projectName = mCmdSetProjectName.GetValue(); if (SessionManager::Instance()->SetProjectName(projectName) == false) { mCmdSetProjectName.Send("Failed"); } else { mCmdSetProjectName.Send("OK"); } } // Check if we need to collect a trace for this currently-rendering frame. if (mbTraceTriggeredFromKeypress) { Log(logMESSAGE, "Keypress capture starting.\n"); MultithreadedTraceAnalyzerLayer* traceAnalyzer = GetTraceAnalyzerLayer(); if (traceAnalyzer != nullptr) { // Examine the layer stack to check for any enabled layers. If there are, // we won't be able to collect a trace successfully. if (m_EnabledLayers.empty()) { #if ENABLE_CLIENT_LOCKOUT_ON_KEYPRESS // Tell the GPUPerfServer to reject all incoming requests (it will send the stalled status return to all messages) SG_SET_BOOL(ForceRenderStallState, true); #endif // ENABLE_CLIENT_LOCKOUT_ON_KEYPRESS // Since there aren't any layers enabled in the stack, we can proceed with pushing the Logger. if (!traceAnalyzer->IsEnabled()) { // Need to add the TraceAnalyzer layer to the stack. PushLayer(*traceAnalyzer, &m_pushLayer); } // Enable trace collection for the next rendered frame. traceAnalyzer->EnableLinkedTraceCollection(); } else { // The LayerManager's "enabled layer stack" wasn't empty, meaning the client was in the middle of an operation. // Dump a message to the log, and forget that a keypress trace was requested. Log(logMESSAGE, "Layer stack is non-empty. Not going to push the Logger for Keypress Capture.\n"); mbTraceTriggeredFromKeypress = false; } } } if (mCmdFrameCaptureWithSave.IsActive()) { // Extract the capture mode argument from the capture mode string m_captureType = (CaptureType)mCmdFrameCaptureWithSave.GetCaptureType(); m_captureCount = mCmdFrameCaptureWithSave.GetCaptureCount(); if (m_captureCount == 0) { Log(logERROR, "ModernAPILayerManager::BeginFrame - m_captureCount is 0, forcing it to 1.\n"); m_captureCount = 1; } // Exclude Frame Capture if (m_captureType > 0 && m_captureType < 4) { // Now I need to make sure that the MultithreadedTraceAnalyzerLayer is on the stack. MultithreadedTraceAnalyzerLayer* traceAnalyzer = GetTraceAnalyzerLayer(); traceAnalyzer->EnableLinkedTraceCollection(); // enable objectInspector writing to disk ObjectDatabaseProcessor* objectDatabase = GetObjectDatabaseProcessor(); objectDatabase->EnableObjectDatabaseCollection(); } } // Call into the base class to deal with basic layer management. LayerManager::BeginFrame(); }