bool GraphicsServerCommunication::CaptureFrameStub(gtASCIIString& frameInfoAsXML, unsigned char*& pImageBuffer, unsigned long& imageSize)
{
    bool retVal = true;
#pragma message ("TODO: FA: remove this function")

    static gtASCIIString serverResponseFormat = "<Root><Location></Location>"\
                                                "<FrameNumber>%d</FrameNumber><Contents>"\
                                                "<LinkedTrace>linkedtrace_20150915_091403.ltr</LinkedTrace>"\
                                                "<FrameBufferImage></FrameBufferImage>"\
                                                "<ElapsedTime>%d</ElapsedTime>"\
                                                "<FPS>%d</FPS>"\
                                                "<CPUFrameDuration>%f</CPUFrameDuration>"\
                                                "<APICallCount>%d</APICallCount>"\
                                                "<DrawCallCount>%d</DrawCallCount>"\
                                                "</Contents></Root>";

    static int frameIndex = 1345;
    frameIndex += rand() % 50;
    int elapsedTimeMS = rand() % 1000000;
    int fps = rand() % 250;
    double frameDuration = (double)rand() / 2.345;
    int apiCalls = rand() % 500000;
    int drawCalls = rand() % apiCalls;

    frameInfoAsXML.appendFormattedString(serverResponseFormat.asCharArray(), frameIndex, elapsedTimeMS, fps, frameDuration, apiCalls, drawCalls);

    GetFrameThumbnail(pImageBuffer, imageSize, frameIndex % 12);
    return retVal;
}
Beispiel #2
0
//-----------------------------------------------------------------------------
/// escapes special characters for formating into XML
///
/// \param strValue value that needs to have special characters escaped so that
///    the XML can be parsed properly
/// \return generated XML string
//-----------------------------------------------------------------------------
gtASCIIString XMLEscape(gtASCIIString strValue)
{
    // fix special characters
    strValue.replace("&", "&amp;");
    strValue.replace("<", "&lt;");
    strValue.replace(">", "&gt;");
    strValue.replace("'", "&apos;");
    strValue.replace("\"", "&quot;");

    return strValue;
}
// ---------------------------------------------------------------------------
// Name:        osPortAddress::osPortAddress
// Description: Constructor - Represents a remote machine port. (uses ASCII string)
// Arguments:   hostName - The host on which the port resides.
//              remotePortNumber - The port number on the local machine.
// Author:      AMD Developer Tools Team
// Date:        13/9/2010
// ---------------------------------------------------------------------------
osPortAddress::osPortAddress(const gtASCIIString& hostName, unsigned short remotePortNumber)
{
    // Convert the host name to a unicode string:
    gtString hostNameUnicode;
    hostNameUnicode.fromASCIIString(hostName.asCharArray());
    setAsRemotePortAddress(hostNameUnicode, remotePortNumber);
}
// ---------------------------------------------------------------------------
// Name:        GraphicsServerCommunication::ConnectProcess
// Description: Connect to Graphics server's specific process
// Arguments:   strPid - Process ID to connect to and update current PID, (optional) can be "", function will then connect to known process
// Return Val:  bool  - Success / failure
// ---------------------------------------------------------------------------
bool GraphicsServerCommunication::ConnectProcess(const gtASCIIString strPid, const gtASCIIString& apiType)
{
    gtASCIIString strWebResponse;

    bool retVal = false;

    if ((0 < strPid.length()) && (true == strPid.isIntegerNumber()))
    {
        m_strPid = strPid;
    }

    if (apiType.isEmpty() == false)
    {
        if (apiType == GP_GRAPHICS_SERVER_DX12_API_TYPE || apiType == GP_GRAPHICS_SERVER_VULKAN_API_TYPE)
        {
            m_strApiHttpCommand = "/";
            m_strApiHttpCommand.append(apiType);
        }
        else
        {
            gtString msg = L"Wrong API given : ";
            msg.append(gtString().fromASCIIString(apiType.asCharArray()));
            GT_ASSERT_EX(false, msg.asCharArray());
            m_strApiHttpCommand = "";
        }
    }
    if (m_strPid.isEmpty() == false && m_strApiHttpCommand.isEmpty() == false)
    {
        // Connect
        gtASCIIString showStack = m_strApiHttpCommand;
        retVal = SendCommandPid(showStack.append("/ShowStack"), strWebResponse, "");

        if (retVal)
        {
            gtASCIIString timeControl = m_strApiHttpCommand;
            retVal = SendCommandPid(timeControl.append("/PushLayer=TimeControl") , strWebResponse, "");
        }

        if (retVal)
        {
            gtASCIIString tcSettings = m_strApiHttpCommand;
            retVal = SendCommandPid(tcSettings.append("/TC/Settings.xml"), strWebResponse, "");
        }
    }

    return retVal;
}
//--------------------------------------------------------------------------
/// Read a chunk of metadata XML to populate all members.
/// \param inMetadataXML A string of XML metadata that will be parsed.
/// \returns True if parsing was successful. False if an error occurred.
//--------------------------------------------------------------------------
bool TraceMetadata::ReadFromXML(const gtASCIIString& inMetadataXML)
{
    TiXmlDocument xmlDocument;
    xmlDocument.Parse(inMetadataXML.asCharArray());

    // Create a visitor, which will populate "this" TraceMetadata instance.
    MetadataXMLVisitor elementVisitor(this);
    bool bVisistedSuccessfully = xmlDocument.Accept(&elementVisitor);

    return bVisistedSuccessfully;
}
//--------------------------------------------------------------------------
/// Generate a trace info block that can be appended to the top of the trace. Included application and system information.
/// \param outHeaderString A string containing the generated block of header text.
/// \returns True if the header was generated successfully. False if it failed.
//--------------------------------------------------------------------------
bool MultithreadedTraceAnalyzerLayer::GenerateLinkedTraceHeader(gtASCIIString& outHeaderString)
{
    bool bHeaderGenerated = false;

    // The response should include a header when connected to CodeXL Graphics.
    outHeaderString.appendFormattedString("//CodeXL Frame Trace\n");

    osModuleArchitecture moduleArchitecture;
    osRuntimePlatform currentPlatform;
    gtString executablePath;
    gtString commandLine;
    gtString workingDirectory;

    if (osGetProcessLaunchInfo(osGetCurrentProcessId(), moduleArchitecture, currentPlatform, executablePath, commandLine, workingDirectory) == true)
    {
        outHeaderString.appendFormattedString("//ProcessExe=%s\n", executablePath.asASCIICharArray());

        // Build a timestamp.
        osTime currentTime;
        currentTime.setFromCurrentTime();
        tm timeStruct;
        currentTime.timeAsTmStruct(timeStruct, osTime::LOCAL);

        // Need to add 1900, since tm contains "years since 1900".
        int year = timeStruct.tm_year + 1900;

        // Need to add 1, since tm contains "months since January".
        int month = timeStruct.tm_mon + 1;

        int day = timeStruct.tm_mday;
        int hour = timeStruct.tm_hour;
        int minute = timeStruct.tm_min;
        int second = timeStruct.tm_sec;

        gtASCIIString timestampBuilder;
        timestampBuilder.appendFormattedString("%d/%d/%d %d:%d:%d", month, day, year, hour, minute, second);
        outHeaderString.appendFormattedString("//TraceDateTime=%s\n", timestampBuilder.asCharArray());

        outHeaderString.appendFormattedString("//TraceFileVersion=%d\n", 1);
        outHeaderString.appendFormattedString("//ApplicationArgs=%s\n", commandLine.asASCIICharArray());
        outHeaderString.appendFormattedString("//WorkingDirectory=%s\n", workingDirectory.asASCIICharArray());

        // Build a system information header string.
        std::string systemInfo;
        OSWrappers::WriteSystemInfoString(systemInfo);
        outHeaderString.appendFormattedString("\n%s\n", systemInfo.c_str());

        bHeaderGenerated = true;
    }
    else
    {
        Log(logERROR, "Failed to retrieve process info when building response header.\n");
    }

    return bHeaderGenerated;
}
bool GraphicsServerCommunication::GetNumCapturedFrames(gtASCIIString& executable, int& numFrames)
{
    bool retVal = true;
    OS_DEBUG_LOG_TRACER_WITH_RETVAL(retVal);

    numFrames = 3;

    if (executable.length() > 6)
    {
        numFrames = 4;
    }

    return retVal;
}
// ---------------------------------------------------------------------------
// Name:        GraphicsServerCommunication::SendCommandPid
// Description: locate available Graphics server
// Arguments:   strWebResponse(return) - web string returned.
//              strCommand - URL command to send to server
//              strPid - optional Process ID string, leave empty, "", to use existing Process ID
// Return Val:  bool  - Success / failure
// ---------------------------------------------------------------------------
bool GraphicsServerCommunication::SendCommandPid(const gtASCIIString& strCommand, gtASCIIString& strWebResponse, const gtASCIIString& strPid, bool isResendAllowed)
{
    bool retVal = false;
    gtASCIIString strConnectPid;
    gtASCIIString strQueryUrl;

    if ((0 < strPid.length()) && (true == strPid.isIntegerNumber()))
    {
        strConnectPid = strPid;
    }
    else if ((0 < m_strPid.length()) && (true == m_strPid.isIntegerNumber()))
    {
        strConnectPid = m_strPid;
    }

    strQueryUrl = "/";
    strQueryUrl.append(strConnectPid);
    strQueryUrl.append(strCommand);

    retVal = RequestData(strQueryUrl, strWebResponse, isResendAllowed);

    return retVal;
}
// ---------------------------------------------------------------------------
// Name:        GraphicsServerCommunication::ConnectServer
// Description: Connect to server with specified Address or existing address
// Arguments:   strServer - optional address to override and update existing information
// Return Val:  bool  - Success / failure
// ---------------------------------------------------------------------------
bool GraphicsServerCommunication::ConnectServer(const gtASCIIString strServer)
{
    bool retVal = false;
    m_isStopSignaled = false;

    if (0 < strServer.length())
    {
        m_serverURL = strServer;
    }

    // Set the server address and port
    m_GPSServer = osPortAddress(m_serverURL, m_Port);

    m_httpClient = osHTTPClient(m_GPSServer);
    m_httpClient.GetTCPSocket().setReadOperationTimeOut(GRAPHIC_SERVER_READ_TIMEOUT);

    if (true == m_httpClient.connect())
    {
        retVal = true;
    }

    return retVal;
}
//---------------------------------------------------------------------------------------------------------------
// This function checks if argument is constant. If it is it returns true, overwise false
//---------------------------------------------------------------------------------------------------------------
static bool GetConstantIDFromArgument(gtASCIIString sArgument, gtASCIIString cKey, unsigned int& nSlotID)
{
    unsigned int nKeyPosition = (unsigned int)sArgument.find(cKey);

    // Check if cKey is not end of other argument
    if (nKeyPosition == std::string::npos || (nKeyPosition != 0
                                              && sArgument[nKeyPosition - 1] != '>' // code can be in HTML
                                              && sArgument[nKeyPosition - 1] != ' '))

    {
        return false;
    } // End of if

    // Looking for not digital symbols in argument
    unsigned int nNextNotDigit = (unsigned int)sArgument.find_first_not_of("0123456789", nKeyPosition + cKey.length());

    gtASCIIString sSlotID; // this variable contains string with the slot number

    if (nNextNotDigit == std::string::npos)   // All character after cKey are digits
    {
        sSlotID = sArgument.substr(nKeyPosition + cKey.length());
    } // End of if

    // Check if the variable is finished with digit
    else if ((sArgument[nNextNotDigit] != '<' && sArgument[nNextNotDigit] != ' ' && sArgument[nNextNotDigit] != ',' &&
              sArgument[nNextNotDigit] != '.' && sArgument[nNextNotDigit] != '['  && sArgument[nNextNotDigit] != '\n')
             || nNextNotDigit <= nKeyPosition + 1)
    {
        return false;
    } // End of else if
    else
    {
        sSlotID = sArgument.substr(nKeyPosition + cKey.length(), nNextNotDigit - nKeyPosition - cKey.length());
    } // End of else

    int nScanRes = sscanf_s(sSlotID.asCharArray(), "%d", &nSlotID);

    if (nScanRes < 1)
    {
        Log(logERROR, "%s: Failed to read integer from Str = %s\n", __FUNCTION__, sSlotID.asCharArray());
        return false;
    }

    return true;
}// End of GetConstantIDFromArgument
//--------------------------------------------------------------
//  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;
}
//---------------------------------------------------------------------------------------------------------------
// This function returns of slots used in code
// cKey is symbol which shows what kind of slots are requested: 'c' for float constants, 'b' for boolean
// constants etc. Results are kept in usedSlots.
//---------------------------------------------------------------------------------------------------------------
long GetConstantsFromCode(gtASCIIString code, gtASCIIString cKey, std::list<unsigned long>& usedSlots)
{
    long hr = 0;
    typedef std::map<  gtASCIIString, std::vector<unsigned long> > ArgumentType;
    typedef std::map<  gtASCIIString, std::vector<unsigned long> >::iterator ArgumentIter;

    ArgumentType ArgumentLength;
    ArgumentIter ArgIter;

    // This map contains infoemation about arguments lenth
    // i.e the third argument of the m4x4 itstruction is 4x4 matrix,
    // which uses 4 slots, so if shader has instruction m4x4 oPos, v0, c0 it means
    // c0, c1, c3 and c4 are used, that is why ArgumentLength["m4x4"][2] = 4

    ArgumentLength["m3x2"].resize(3);
    ArgumentLength["m3x2"][0] = 1;
    ArgumentLength["m3x2"][1] = 1;
    ArgumentLength["m3x2"][2] = 2;
    ArgumentLength["m3x3"].resize(3);
    ArgumentLength["m3x3"][0] = 1;
    ArgumentLength["m3x3"][1] = 1;
    ArgumentLength["m3x3"][2] = 3;
    ArgumentLength["m3x4"].resize(3);
    ArgumentLength["m3x4"][0] = 1;
    ArgumentLength["m3x4"][1] = 1;
    ArgumentLength["m3x4"][2] = 4;
    ArgumentLength["m4x3"].resize(3);
    ArgumentLength["m4x3"][0] = 1;
    ArgumentLength["m4x3"][1] = 1;
    ArgumentLength["m4x3"][2] = 3;
    ArgumentLength["m4x4"].resize(3);
    ArgumentLength["m4x4"][0] = 1;
    ArgumentLength["m4x4"][1] = 1;
    ArgumentLength["m4x4"][2] = 4;

    ArgumentLength["texm3x2depth"].resize(2);
    ArgumentLength["texm3x2depth"][0] = 3;
    ArgumentLength["texm3x2depth"][1] = 2;
    ArgumentLength["texm3x2pad"].resize(2);
    ArgumentLength["texm3x2pad"][0] = 3;
    ArgumentLength["texm3x2pad"][1] = 2;
    ArgumentLength["texm3x2tex"].resize(2);
    ArgumentLength["texm3x2tex"][0] = 3;
    ArgumentLength["texm3x2tex"][1] = 2;
    ArgumentLength["texm3x3"].resize(2);
    ArgumentLength["texm3x3"][0] = 3;
    ArgumentLength["texm3x3"][1] = 3;
    ArgumentLength["texm3x3pad"].resize(2);
    ArgumentLength["texm3x3pad"][0] = 3;
    ArgumentLength["texm3x3pad"][1] = 3;
    ArgumentLength["texm3x3spec"].resize(2);
    ArgumentLength["texm3x3spec"][0] = 3;
    ArgumentLength["texm3x3spec"][1] = 3;
    ArgumentLength["texm3x3tex"].resize(2);
    ArgumentLength["texm3x3tex"][0] = 3;
    ArgumentLength["texm3x3tex"][1] = 3;
    ArgumentLength["texm3x3vspec"].resize(2);
    ArgumentLength["texm3x3vspec"][0] = 3;
    ArgumentLength["texm3x3vspec"][1] = 3;


    unsigned int nStartOfToken = 0;

    // This loop splits code to tokens
    while (nStartOfToken != std::string::npos)
    {
        unsigned int nNextToken = (unsigned int)code.find('\n', nStartOfToken + 1);

        // comment
        gtASCIIString sToken = (nNextToken == std::string::npos) ? code.substr(nStartOfToken) : code.substr(nStartOfToken, nNextToken - nStartOfToken);

        if (sToken.length() > 1 && sToken.substr(0, 1) != "//")      // Skip comments and empty strings
        {
            unsigned int nStartOfInstruction = (unsigned int)sToken.find_first_not_of(" \n", 0);      // comment
            unsigned int nEndOfInstruction = (unsigned int)sToken.find(' ', nStartOfInstruction);

            if (nEndOfInstruction == std::string::npos)
            {
                nStartOfToken = nNextToken;
                continue;
            }

            gtASCIIString sCommand = sToken.substr(nStartOfInstruction, nEndOfInstruction - nStartOfInstruction);

            unsigned int nArgument = 0;
            unsigned int nStartOfArgument = nEndOfInstruction + 1;
            unsigned int nEndOfArgument;

            do // This separates arguments of command
            {
                nEndOfArgument = (unsigned int)sToken.find(',', nStartOfArgument);
                gtASCIIString sArgument = (nEndOfArgument == std::string::npos) ?
                                          sToken.substr(nStartOfArgument) :
                                          sToken.substr(nStartOfArgument, nEndOfArgument - nStartOfArgument);
                unsigned int nSlotID;

                if (GetConstantIDFromArgument(sArgument, cKey,  nSlotID) == false)
                {
                    nArgument++;
                    nStartOfArgument = nEndOfArgument + 1;
                    continue;
                }

                // Calculation of used constants. Default is 1. Next 2 lines check if the command in "special cases map"
                ArgIter = ArgumentLength.find(sCommand);

                int nArgsCount = (ArgIter == ArgumentLength.end()) ? 1 :   // If coommand has not been find the lenth of argument is supposed 1
                                 (ArgIter->second.size() > nArgument ? ArgIter->second[nArgument] :
                                  1);  // If there no information for considered argument its lenth is supposed 1

                // This loop adds variables in the used constants list
                for (unsigned int i = nSlotID; i < nSlotID + nArgsCount; i++)
                {
                    bool nNotFind = true;

                    for (std::list<unsigned long>::const_iterator iter = usedSlots.begin(); iter != usedSlots.end(); ++iter)
                    {
                        if (*iter == i)
                        {
                            nNotFind = false;
                            break;
                        }
                    }

                    if (nNotFind)
                    {
                        usedSlots.push_back(i);
                    } // End of if
                }// End of for

                nArgument++;
                nStartOfArgument = nEndOfArgument + 1;
            }
            while (nEndOfArgument != std::string::npos);
        } // End of if ( sToken.size() > 1 && sToken.substr( 0, 1 ) != "//" )

        nStartOfToken = nNextToken;
    }// End of while ( nFound  != string::npos )

    return hr;
}// End of GetConstantsFromCode
Beispiel #13
0
//-----------------------------------------------------------------------------
/// Get the API parameters as a single string. Build the string from the
/// individual parameters if necessary
/// \return parameter string
//-----------------------------------------------------------------------------
const char* DX12APIEntry::GetParameterString() const
{
    static gtASCIIString parameterString;

    if (mNumParameters == 0)
    {
        return mParameters.asCharArray();
    }
    else
    {
        parameterString = "";
        // get the API function parameters from the raw memory buffer
        int arrayCount = 0;
        char* buffer = mParameterBuffer;

        if (buffer != nullptr)
        {
            for (UINT32 loop = 0; loop < mNumParameters; loop++)
            {
                char* ptr = buffer;
                PARAMETER_TYPE paramType;
                memcpy(&paramType, ptr, sizeof(PARAMETER_TYPE));
                ptr += sizeof(PARAMETER_TYPE);
                unsigned char length = *ptr++;

                if (length < BYTES_PER_PARAMETER)
                {
                    // if an array token is found, add an opening brace and start the array elements countdown
                    if (paramType == PARAMETER_ARRAY)
                    {
                        memcpy(&arrayCount, ptr, sizeof(unsigned int));
                        parameterString += "[ ";
                    }
                    else
                    {
                        char parameter[BYTES_PER_PARAMETER] = {};

                        GetParameterAsString(paramType, length, ptr, parameter);
                        parameterString += parameter;

                        // check to see if this is the last array element. If so, output a closing brace
                        // before the comma separator (if needed)
                        if (arrayCount > 0)
                        {
                            arrayCount--;

                            if (arrayCount == 0)
                            {
                                parameterString += " ]";
                            }
                        }

                        // if there are more parameters to come, insert a comma delimiter
                        if ((loop + 1) < mNumParameters)
                        {
                            parameterString += ", ";
                        }
                    }
                }

                // point to next parameter in the buffer
                buffer += BYTES_PER_PARAMETER;
            }
        }

        return parameterString.asCharArray();
    }
}
//--------------------------------------------------------------------------
/// Handle what happens when a Linked Trace is requested. We can either:
/// 1. Return the trace response as normal.
/// 2. Cache the response to disk, and generate a "trace metadata" file used to retrieve the trace later.
/// \param inFullResponseString The response string built by tracing the application.
/// \param inbSaveResponseToFile A switch used to determine which response method to use.
//--------------------------------------------------------------------------
void MultithreadedTraceAnalyzerLayer::HandleLinkedTraceResponse(gtASCIIString& inFullResponseString, bool inbSaveResponseToFile)
{
    ModernAPILayerManager* parentLayerManager = GetParentLayerManager();

    if (parentLayerManager->InCapturePlayer())
    {
        const std::string& metadataFile = parentLayerManager->GetPathToTargetMetadataFile();

        if (metadataFile.length() > 0)
        {
            // Read the metadata file and store the contents in a structure.
            TraceMetadata traceMetadata;
            traceMetadata.mFrameInfo = new FrameInfo;

            bool bReadMetadataFileSuccessfully = ReadMetadataFile(metadataFile, &traceMetadata);

            if (bReadMetadataFileSuccessfully)
            {
                gtASCIIString traceContents;
                bool bReadTraceSuccessfully = LoadTraceFile(traceMetadata.mPathToTraceFile, traceContents);

                if (bReadTraceSuccessfully)
                {
                    // At this point the full trace response text should be loaded into our string and ready to be sent back to the client.
                    mCmdLinkedTrace.Send(traceContents.asCharArray());
                }
                else
                {
                    Log(logERROR, "Failed to read trace file at '%s'.", traceMetadata.mPathToTraceFile.c_str());
                }
            }
            else
            {
                Log(logERROR, "Failed to read metadata file at '%s'.", metadataFile.c_str());
            }

            // Destroy the FrameInfo instance that was created above.
            SAFE_DELETE(traceMetadata.mFrameInfo);
        }
        else
        {
            Log(logERROR, "Failed to locate valid path to trace metadata file.");
        }
    }
    else
    {
        gtASCIIString traceHeaderBlock;
        bool bBuiltHeaderSuccessfully = GenerateLinkedTraceHeader(traceHeaderBlock);

        if (bBuiltHeaderSuccessfully)
        {
            bool bKeypressTrigger = parentLayerManager->IsTraceTriggeredByKeypress();

            // Collect a trace and generate the trace metadata string. Write the trace and metadata files to disk.
            std::string metadataXMLString;
            bool bWriteMetadataSuccessful = WriteTraceAndMetadataFiles(traceHeaderBlock, inFullResponseString, metadataXMLString);

            // If the trace wasn't triggered by a keypress, we'll need to send a response back through either of the following commands.
            CommandResponse& frameCaptureWithSaveResponse = (inbSaveResponseToFile == true) ? parentLayerManager->mCmdFrameCaptureWithSave : mCmdLinkedTrace;

            if (bWriteMetadataSuccessful)
            {
                // We only need to send the response back through a request if the client triggered collection.
                if (!bKeypressTrigger)
                {
                    // Check if we want to cache the response to disk, or return it as-is.
                    if (inbSaveResponseToFile)
                    {
                        if (bWriteMetadataSuccessful)
                        {
                            // Send a response back to the client indicating which trace metadata file was written to disk.
                            frameCaptureWithSaveResponse.Send(metadataXMLString.c_str());
                        }
                        else
                        {
                            Log(logERROR, "Failed to write trace metadata XML.\n");
                            frameCaptureWithSaveResponse.Send("Failed");
                        }
                    }
                    else
                    {
                        // Send a response containing the API and GPU trace text.
                        frameCaptureWithSaveResponse.Send(inFullResponseString.asCharArray());
                    }
                }
                else
                {
                    Log(logMESSAGE, "Successfully traced frame %d.\n", parentLayerManager->GetFrameCount());
                }
            }
            else
            {
                Log(logERROR, "Failed to write trace metadata XML.\n");

                // If a failed trace collection was triggered by a command, we need to respond with an error message.
                if (!bKeypressTrigger)
                {
                    frameCaptureWithSaveResponse.Send("Failed");
                }
            }
        }
    }
}