//-------------------------------------------------------------------------- /// Constructor where available layers are pushed. //-------------------------------------------------------------------------- DX12LayerManager::DX12LayerManager() : ModernAPILayerManager() , mInterceptor(NULL) , mbIsInitialized(false) { m_LayerList = (LAYERDESC*) & s_LayerList; m_LayerListSize = sizeof(s_LayerList) / sizeof(s_LayerList[0]); // Start with the object database layer enabled, as we want to track object instances from the start. m_AvailableLayers.push_back(DX12ObjectDatabaseProcessor::Instance()); m_AvailableLayers.push_back(DX12FrameDebuggerLayer::Instance()); // @TODO: Remove this DEBUG code when the client knows how to request the backbuffer image. // This will stay for now to eliminate the manual step of PushLayer'ing the DX12FrameDebuggerLayer. DX12FrameDebuggerLayer* frameDebuggerLayer = DX12FrameDebuggerLayer::Instance(); PushLayer(*frameDebuggerLayer, &m_pushLayer); // If AutoCapture is enabled in the log file, automatically push the TraceAnalyzer to the stack. bool bPushTraceAnalyzer = (SG_GET_INT(OptionTraceType) != kTraceType_None); if (bPushTraceAnalyzer) { // Add the TraceAnalyzer so it can AutoCapture at a specified frame. DX12TraceAnalyzerLayer* traceLayer = DX12TraceAnalyzerLayer::Instance(); m_AvailableLayers.push_back(traceLayer); PushLayer(*traceLayer, &m_pushLayer); } }
//----------------------------------------------------------------------------- /// Constructor where available layers are pushed. //----------------------------------------------------------------------------- DX12LayerManager::DX12LayerManager() : ModernAPILayerManager() , mInterceptor(nullptr) , mbIsInitialized(false) { m_LayerList = (LAYERDESC*) & s_LayerList; m_LayerListSize = sizeof(s_LayerList) / sizeof(s_LayerList[0]); // Start with the object database layer enabled, as we want to track object instances from the start. m_AvailableLayers.push_back(DX12ObjectDatabaseProcessor::Instance()); m_AvailableLayers.push_back(DX12FrameDebuggerLayer::Instance()); m_AvailableLayers.push_back(DX12TraceAnalyzerLayer::Instance()); // If AutoCapture is enabled in the config file, automatically push the TraceAnalyzer to the stack. bool bPushTraceAnalyzer = (SG_GET_INT(OptionTraceType) != kTraceType_None); if (bPushTraceAnalyzer) { // Add the TraceAnalyzer so it can AutoCapture at a specified frame. DX12TraceAnalyzerLayer* traceLayer = DX12TraceAnalyzerLayer::Instance(); PushLayer(*traceLayer, &m_pushLayer); } osFilePath logFilePath; logFilePath.setPath(osFilePath::OS_TEMP_DIRECTORY); char fullPath[PS_MAX_PATH] = {}; sprintf(fullPath, "%s\\%s\\GPS", logFilePath.asString().asASCIICharArray(), GetPerfStudioDirName()); mStreamLog.SetBaseNamePath(fullPath); }
//-------------------------------------------------------------------------- /// A handler invoked when Autocapture mode has been triggered. //-------------------------------------------------------------------------- void ModernAPILayerManager::AutocaptureTriggered() { // Only enable AutoCapture mode with a valid trace type. bool bValidTraceMode = SG_GET_INT(OptionTraceType) != kTraceType_None; if (bValidTraceMode) { m_AutoCapture = true; } }
//-------------------------------------------------------------------------- /// Constructor //-------------------------------------------------------------------------- FrameDebugger::FrameDebugger() { m_dwBreakPoint = 0; m_bAutoRenderTarget = true; m_ulDrawCallCounter = 0; m_bForceClear = true; m_ClearColor[0] = 0.0f; // red m_ClearColor[1] = 0.4f; // green m_ClearColor[2] = 0.8f; // blue m_ClearColor[3] = 1.0f; // alpha m_iWireframeColor = SG_GET_INT(OptionWireFrameColor); m_bWireframeOverlay = SG_GET_BOOL(OptionWireFrameOverlay); // 1 = pink/purple, 2 = green, 3 = blue if (2 == m_iWireframeColor) { // green m_fWireframeOverlayColor[0] = 0.0f; m_fWireframeOverlayColor[1] = 1.0f; m_fWireframeOverlayColor[2] = 0.0f; } else if (3 == m_iWireframeColor) { // blue m_fWireframeOverlayColor[0] = 0.0f; m_fWireframeOverlayColor[1] = 0.0f; m_fWireframeOverlayColor[2] = 1.0f; } else { // 1 or other // pink / purple m_fWireframeOverlayColor[0] = 1.0f; m_fWireframeOverlayColor[1] = 0.0f; m_fWireframeOverlayColor[2] = 1.0f; } m_fWireframeOverlayColor[3] = 1.0f; AddCommand(CONTENT_XML, "breakpoint", "BreakPoint", CMD_BREAKPOINT, NO_DISPLAY, INCLUDE, m_dwBreakPoint); AddCommand(CONTENT_XML, "autorendertarget", "Auto Render Target", CMD_AUTORENDERTARGET, NO_DISPLAY, INCLUDE, m_bAutoRenderTarget); AddCommand(CONTENT_XML, "forceclear", "Force Clear", CMD_FORCECLEAR, NO_DISPLAY, INCLUDE, m_bForceClear); AddCommand(CONTENT_XML, "wireframeoverlay", "WireFrame Overlay", CMD_WIREFRAMEOVERLAY, NO_DISPLAY, INCLUDE, m_bWireframeOverlay); AddCommand(CONTENT_XML, "stats", "Stats", CMD_STATISTICS, NO_DISPLAY, INCLUDE, m_Stats); AddCommand(CONTENT_XML, "currentdrawcall", "Current Draw Call", CMD_CURRENTDRAWCALL, NO_DISPLAY, INCLUDE, m_CurrentDrawCall); AddCommand(CONTENT_XML, "DrawCallList", "DrawCallList", "DrawCallList.xml", NO_DISPLAY, INCLUDE, m_drawCallList); AddCommand(CONTENT_XML, "ConfigHUD", "Config HUD", CMD_CONFIGHUD, NO_DISPLAY, INCLUDE, m_bConfigHUD); SetLayerName("FrameDebugger"); }
//-------------------------------------------------------------------------- /// Check if the newly-started frame should be automatically traced at a specific frame. /// \returns An eTraceType value, corresponding to the value set in the server config. //-------------------------------------------------------------------------- int MultithreadedTraceAnalyzerLayer::GetTraceTypeFlags() { int traceTypeFlags = kTraceType_None; // It's time to capture a frame. Check the trace type that was requested. if (GetParentLayerManager()->IsAutocaptureFrame()) { traceTypeFlags = SG_GET_INT(OptionTraceType); } return traceTypeFlags; }
//-------------------------------------------------------------------------- /// Check if the newly-started frame should be automatically traced at a specific frame. /// \returns An eTraceType value, corresponding to the value set in the server config. //-------------------------------------------------------------------------- int MultithreadedTraceAnalyzerLayer::GetTraceTypeFlags() { int traceTypeFlags = kTraceType_None; // It's time to capture a frame. Check the trace type that was requested. InterceptorBase* interceptor = GetInterceptor(); LayerManager* thisLayerManager = interceptor->GetParentLayerManager(); if (thisLayerManager->IsAutocaptureFrame()) { traceTypeFlags = SG_GET_INT(OptionTraceType); } return traceTypeFlags; }
// Generate a composite log message - then finally send to handler to write and/or display void _Log(enum LogType type, const char* fmt, ...) { // check to see if logging of the level is enabled, or if s_LogConsole is specified // if not, don't process it. int logLevel = SG_GET_INT(OptionLogLevel); if (((type - logERROR) > logLevel && s_LogConsole == false)) { return; } // Define buffer to store maximum current log message. // Different destinations will receive a subset of this string. // On Win32 the entire string is passed to OutputDebugString() char fullString[PS_LOG_MAX_LENGTH] = ""; int nLen = 0; int nSize; bool truncated = false; char* pLogString; // String to print to logfile char* pConsole; // String to print to console doesn't include debug information char* pRaw; // Raw string passed in without any additional decoration if (truncated == false) { // Prepend "PerfStudio: " for windows OutputDebugString() messages nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "PerfStudio: "); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } pLogString = &fullString[nLen]; // logfile message doesn't include above WIN32 section #if (defined PS_LOG_DEBUG) && (defined _DEBUG) if (truncated == false) { // In debug builds, include the __FILE__, __LINE__ and __FUNCTION__ information nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "%s(%d) : %s(): ", s_LogFile, s_LogLine, s_LogFunction); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } #endif // Prepend accurate timestamp if (truncated == false) { gtASCIIString time = GetMicroTimeStr(); time = time.substr(12); nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "%-14s: ", time.asCharArray()); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } pConsole = &fullString[nLen]; // String to print to console starts here if (truncated == false) { // Add the message type string switch (type) { case logERROR: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Error: "); break; case logWARNING: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Warning: "); break; case logMESSAGE: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Message: "); break; case logTRACE: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Trace: "); break; case logASSERT: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Assert: "); break; case logDEBUG: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Debug: "); break; case logRAW: // Skip nSize = 0; break; default: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Unknown: "); break; } if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } // Add the module identifier if (s_LogModule && (truncated == false)) { nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "PID: %10u TID: %10u %-14s: ", osGetCurrentProcessId(), osGetCurrentThreadId(), s_LogModule); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } if (truncated == false) { if (SG_GET_INT(OptionLogLevel) >= logTRACE - logERROR) { // Add the indent for (int i = 0; (i < logIndent) && (nLen < PS_LOG_MAX_LENGTH - 1); i++, nLen++) { fullString[nLen] = ' '; } fullString[nLen] = 0; // Ensure string in buffer remains null terminated truncated = (nLen == PS_LOG_MAX_LENGTH - 1); } } pRaw = &fullString[nLen]; // Raw undecorated string starts here // Add the actual Log Message if (truncated == false) { va_list arg_ptr; va_start(arg_ptr, fmt); nSize = vsnprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, fmt, arg_ptr); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } va_end(arg_ptr); } // Check if message has been truncated and clean up accordingly if (truncated == true) { // Truncation occurred - change end of line to reflect this char truncationString[] = " ... \n"; sprintf_s(&fullString[PS_LOG_MAX_LENGTH - sizeof(truncationString)], sizeof(truncationString), "%s", truncationString); } // Message Constructed. Print to Log, Console, and OutputDebugString as necessary if (type == logRAW) { if (s_LogConsole) { // Send string to console printf("%s", pRaw); } _logWrite(pRaw); } else { if (s_LogConsole) { // Console messages are always printed in console and in log file // regardless of logLEVEL printf("%s", pConsole); _logWrite(pLogString); OutputDebugString(fullString); } else { // not a console message - filter based on log level if ((type - logERROR) <= SG_GET_INT(OptionLogLevel)) { if (type == logTRACE) { // Trace messages also go to the console printf("%s", pConsole); } _logWrite(pLogString); OutputDebugString(fullString); } } } }
void _LogTrace(enum LogTraceType traceType, const char* fmt, ...) { // check to see if logging of trace messages is enabled, // if not, don't process the call. if (((logTRACE - logERROR) > SG_GET_INT(OptionLogLevel)) && (s_LogConsole == false)) { return; } int nSize; int nLen = 0; bool truncated = false; char traceString[PS_LOG_MAX_LENGTH] = ""; switch (traceType) { case traceENTER: if (truncated == false) { nSize = _snprintf_s(&traceString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Enter: %s() ", s_LogFunction); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } break; case traceEXIT: logIndent -= PS_LOG_INDENT_SIZE; if (logIndent < 0) { logIndent = 0; } truncated = (nLen == PS_LOG_MAX_LENGTH); if (truncated == false) { nSize = _snprintf_s(&traceString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Exit : %s() ", s_LogFunction); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } break; case traceMESSAGE: // do nothing break; default: break; } // Add the actual Log Message if (truncated == false) { va_list arg_ptr; va_start(arg_ptr, fmt); nSize = vsnprintf_s(&traceString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, fmt, arg_ptr); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } va_end(arg_ptr); /*lint -esym(438,arg_ptr) suppress lint warning for variable not used after assignment */ } // For trace messages - force a "\n" at the end if (truncated == false) { nSize = _snprintf_s(&traceString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "\n"); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } /*lint -esym(438,nLen) suppress lint warning for variable not used after assignment */ /*lint -esym(438,truncated) suppress lint warning for variable not used after assignment */ _Log(logTRACE, traceString); // log the ENTER message at the previous depth // and indent the upcoming messages if (traceType == traceENTER) { logIndent += PS_LOG_INDENT_SIZE; } }