//--------------------------------------------------------------------------
/// 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);
    }
}
Exemple #2
0
//-----------------------------------------------------------------------------
/// 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;
    }
}