mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-07 23:31:13 +00:00
* Remove peak clock flag while interrogating GPA about counter information.
790 lines
20 KiB
C++
790 lines
20 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2015-2018 Baldur Karlsson
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#include "amd_counters.h"
|
|
#include "common/common.h"
|
|
#include "common/timing.h"
|
|
#include "core/core.h"
|
|
#include "core/plugins.h"
|
|
#include "official/GPUPerfAPI/Include/GPUPerfAPIFunctionTypes.h"
|
|
#include "strings/string_utils.h"
|
|
|
|
inline bool AMD_FAILED(GPA_Status status)
|
|
{
|
|
return status < GPA_STATUS_OK;
|
|
}
|
|
|
|
inline bool AMD_SUCCEEDED(GPA_Status status)
|
|
{
|
|
return status >= GPA_STATUS_OK;
|
|
}
|
|
|
|
static void GPA_LoggingCallback(GPA_Logging_Type messageType, const char *pMessage)
|
|
{
|
|
if(messageType == GPA_LOGGING_ERROR)
|
|
{
|
|
RDCWARN(pMessage);
|
|
}
|
|
else
|
|
{
|
|
RDCLOG(pMessage);
|
|
}
|
|
}
|
|
|
|
#define GPA_ERROR(text, status) \
|
|
RDCERR(text ". %s", m_pGPUPerfAPI->GPA_GetStatusAsStr((GPA_Status)status));
|
|
|
|
#define GPA_WARNING(text, status) \
|
|
RDCWARN(text ". %s", m_pGPUPerfAPI->GPA_GetStatusAsStr((GPA_Status)status));
|
|
|
|
AMDCounters::AMDCounters(bool dx12DebugLayerEnabled)
|
|
: m_pGPUPerfAPI(NULL),
|
|
m_gpaSessionCounter(0u),
|
|
m_passCounter(-1),
|
|
m_dx12DebugLayerEnabled(dx12DebugLayerEnabled)
|
|
{
|
|
}
|
|
|
|
bool AMDCounters::Init(ApiType apiType, void *pContext)
|
|
{
|
|
#if DISABLED(RDOC_WIN32) && DISABLED(RDOC_LINUX)
|
|
(void)m_dx12DebugLayerEnabled;
|
|
return false;
|
|
#else
|
|
|
|
std::string dllName("GPUPerfAPI");
|
|
|
|
switch(apiType)
|
|
{
|
|
case ApiType::Dx11: dllName += "DX11"; break;
|
|
case ApiType::Dx12: dllName += "DX12"; break;
|
|
case ApiType::Ogl: dllName += "GL"; break;
|
|
case ApiType::Vk: dllName += "VK"; break;
|
|
default:
|
|
RDCWARN(
|
|
"AMD GPU performance counters could not be initialized successfully. "
|
|
"Unsupported API type specified");
|
|
return false;
|
|
}
|
|
|
|
#if ENABLED(RDOC_WIN32)
|
|
#if ENABLED(RDOC_X64)
|
|
dllName += "-x64";
|
|
#endif
|
|
dllName += ".dll";
|
|
#else
|
|
dllName = "lib" + dllName;
|
|
dllName += ".so";
|
|
#endif
|
|
|
|
// first try in the plugin location it will be in distributed builds
|
|
std::string dllPath = LocatePluginFile("amd/counters", dllName.c_str());
|
|
|
|
void *module = Process::LoadModule(dllPath.c_str());
|
|
if(module == NULL)
|
|
{
|
|
module = Process::LoadModule(dllName.c_str());
|
|
}
|
|
|
|
if(module == NULL)
|
|
{
|
|
RDCWARN(
|
|
"AMD GPU performance counters could not be initialized successfully. "
|
|
"Are you missing the DLLs?");
|
|
return false;
|
|
}
|
|
|
|
bool disableCounters = false;
|
|
|
|
if(apiType == ApiType::Dx12 && m_dx12DebugLayerEnabled)
|
|
{
|
|
// Disable counters in DX12 Debug configuration
|
|
void *versionFunc = Process::GetFunctionAddress(module, "GPA_GetVersion");
|
|
|
|
if(NULL == versionFunc)
|
|
{
|
|
disableCounters = true;
|
|
}
|
|
}
|
|
|
|
if(disableCounters)
|
|
{
|
|
RDCLOG("AMD counters are disabled in DX12 Debug version for GPA v3.0");
|
|
return false;
|
|
}
|
|
|
|
GPA_GetFuncTablePtrType getFuncTable =
|
|
(GPA_GetFuncTablePtrType)Process::GetFunctionAddress(module, "GPA_GetFuncTable");
|
|
|
|
m_pGPUPerfAPI = new GPAFunctionTable();
|
|
if(getFuncTable)
|
|
{
|
|
GPA_Status gpaStatus = getFuncTable((void *)m_pGPUPerfAPI);
|
|
|
|
if(AMD_FAILED(gpaStatus))
|
|
{
|
|
RDCERR("Failed to load the GPA function entrypoint.");
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SAFE_DELETE(m_pGPUPerfAPI);
|
|
RDCERR("Failed to get GPA function table. Invalid dynamic library?");
|
|
return false;
|
|
}
|
|
|
|
GPA_Logging_Type loggingType = GPA_LOGGING_ERROR;
|
|
#if ENABLED(RDOC_DEVEL)
|
|
loggingType = GPA_LOGGING_ERROR_AND_MESSAGE;
|
|
#endif
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_RegisterLoggingCallback(loggingType, GPA_LoggingCallback);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Failed to initialize logging", status);
|
|
return false;
|
|
}
|
|
|
|
status = m_pGPUPerfAPI->GPA_Initialize(GPA_INITIALIZE_DEFAULT_BIT);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Initialization failed", status);
|
|
SAFE_DELETE(m_pGPUPerfAPI);
|
|
return false;
|
|
}
|
|
|
|
status = m_pGPUPerfAPI->GPA_OpenContext(
|
|
pContext, GPA_OPENCONTEXT_HIDE_SOFTWARE_COUNTERS_BIT | GPA_OPENCONTEXT_CLOCK_MODE_NONE_BIT,
|
|
&m_gpaContextId);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_WARNING("Open context for counters failed", status);
|
|
m_pGPUPerfAPI->GPA_Destroy();
|
|
SAFE_DELETE(m_pGPUPerfAPI);
|
|
return false;
|
|
}
|
|
|
|
m_Counters = EnumerateCounters();
|
|
m_apiType = apiType;
|
|
|
|
status = m_pGPUPerfAPI->GPA_CloseContext(m_gpaContextId);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Close context failed", status);
|
|
}
|
|
|
|
m_gpaContextId = NULL;
|
|
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
AMDCounters::~AMDCounters()
|
|
{
|
|
if(m_pGPUPerfAPI)
|
|
{
|
|
if(m_gpaContextId)
|
|
{
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_CloseContext(m_gpaContextId);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Close context failed", status);
|
|
}
|
|
}
|
|
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_Destroy();
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Destroy failed", status);
|
|
}
|
|
|
|
SAFE_DELETE(m_pGPUPerfAPI);
|
|
}
|
|
}
|
|
|
|
std::map<uint32_t, CounterDescription> AMDCounters::EnumerateCounters()
|
|
{
|
|
std::map<uint32_t, CounterDescription> counters;
|
|
|
|
gpa_uint32 num;
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_GetNumCounters(m_gpaContextId, &num);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get number of counters", status);
|
|
return counters;
|
|
}
|
|
|
|
for(uint32_t i = 0; i < num; ++i)
|
|
{
|
|
GPA_Usage_Type usageType;
|
|
|
|
status = m_pGPUPerfAPI->GPA_GetCounterUsageType(m_gpaContextId, i, &usageType);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get counter usage type.", status);
|
|
return counters;
|
|
}
|
|
|
|
// Ignore percentage counters due to aggregate roll-up support
|
|
if(usageType == GPA_USAGE_TYPE_PERCENTAGE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
CounterDescription desc = InternalGetCounterDescription(i);
|
|
|
|
desc.counter = MakeAMDCounter(i);
|
|
counters[i] = desc;
|
|
|
|
m_PublicToInternalCounter[desc.counter] = i;
|
|
}
|
|
|
|
return counters;
|
|
}
|
|
|
|
std::vector<GPUCounter> AMDCounters::GetPublicCounterIds() const
|
|
{
|
|
std::vector<GPUCounter> ret;
|
|
|
|
for(const std::pair<GPUCounter, uint32_t> &entry : m_PublicToInternalCounter)
|
|
ret.push_back(entry.first);
|
|
|
|
return ret;
|
|
}
|
|
|
|
CounterDescription AMDCounters::GetCounterDescription(GPUCounter counter)
|
|
{
|
|
return m_Counters[m_PublicToInternalCounter[counter]];
|
|
}
|
|
|
|
CounterDescription AMDCounters::InternalGetCounterDescription(uint32_t internalIndex)
|
|
{
|
|
CounterDescription desc = {};
|
|
const char *tmp = NULL;
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_GetCounterName(m_gpaContextId, internalIndex, &tmp);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get counter name.", status);
|
|
return desc;
|
|
}
|
|
|
|
desc.name = tmp;
|
|
status = m_pGPUPerfAPI->GPA_GetCounterDescription(m_gpaContextId, internalIndex, &tmp);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get counter description.", status);
|
|
return desc;
|
|
}
|
|
|
|
desc.description = tmp;
|
|
status = m_pGPUPerfAPI->GPA_GetCounterGroup(m_gpaContextId, internalIndex, &tmp);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get counter category.", status);
|
|
return desc;
|
|
}
|
|
|
|
desc.category = tmp;
|
|
|
|
GPA_Usage_Type usageType;
|
|
status = m_pGPUPerfAPI->GPA_GetCounterUsageType(m_gpaContextId, internalIndex, &usageType);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get counter usage type.", status);
|
|
return desc;
|
|
}
|
|
|
|
switch(usageType)
|
|
{
|
|
case GPA_USAGE_TYPE_RATIO: ///< Result is a ratio of two different values or types
|
|
desc.unit = CounterUnit::Ratio;
|
|
break;
|
|
case GPA_USAGE_TYPE_PERCENTAGE: ///< Result is a percentage, typically within [0,100] range,
|
|
/// but may be higher for certain counters
|
|
desc.unit = CounterUnit::Percentage;
|
|
break;
|
|
case GPA_USAGE_TYPE_CYCLES: ///< Result is in clock cycles
|
|
desc.unit = CounterUnit::Cycles;
|
|
break;
|
|
case GPA_USAGE_TYPE_MILLISECONDS: ///< Result is in milliseconds
|
|
desc.unit = CounterUnit::Seconds;
|
|
break;
|
|
case GPA_USAGE_TYPE_KILOBYTES: ///< Result is in kilobytes
|
|
case GPA_USAGE_TYPE_BYTES: ///< Result is in bytes
|
|
desc.unit = CounterUnit::Bytes;
|
|
break;
|
|
case GPA_USAGE_TYPE_ITEMS: ///< Result is a count of items or objects (ie, vertices,
|
|
/// triangles, threads, pixels, texels, etc)
|
|
desc.unit = CounterUnit::Absolute;
|
|
break;
|
|
default: desc.unit = CounterUnit::Absolute;
|
|
}
|
|
|
|
GPA_Data_Type type;
|
|
status = m_pGPUPerfAPI->GPA_GetCounterDataType(m_gpaContextId, internalIndex, &type);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get counter data type.", status);
|
|
return desc;
|
|
}
|
|
|
|
// results should either be float32/64 or uint32/64 as the GetSample functions only support those
|
|
switch(type)
|
|
{
|
|
case GPA_DATA_TYPE_FLOAT64: ///< Result will be a 64-bit float
|
|
desc.resultType = CompType::Double;
|
|
desc.resultByteWidth = sizeof(double);
|
|
break;
|
|
case GPA_DATA_TYPE_UINT64: ///< Result will be a 64-bit unsigned int
|
|
desc.resultType = CompType::UInt;
|
|
desc.resultByteWidth = sizeof(uint64_t);
|
|
break;
|
|
default: desc.resultType = CompType::UInt; desc.resultByteWidth = sizeof(uint32_t);
|
|
}
|
|
|
|
status = m_pGPUPerfAPI->GPA_GetCounterUuid(m_gpaContextId, internalIndex, (GPA_UUID *)&desc.uuid);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get counter UUID.", status);
|
|
return desc;
|
|
}
|
|
|
|
return desc;
|
|
}
|
|
|
|
void AMDCounters::EnableCounter(GPUCounter counter)
|
|
{
|
|
const uint32_t internalIndex = m_PublicToInternalCounter[counter];
|
|
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_EnableCounter(m_gpaSessionInfo.back(), internalIndex);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Enable counter.", status);
|
|
}
|
|
}
|
|
|
|
void AMDCounters::EnableAllCounters()
|
|
{
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_EnableAllCounters(m_gpaSessionInfo.back());
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Enable all counters.", status);
|
|
}
|
|
}
|
|
|
|
void AMDCounters::DisableAllCounters()
|
|
{
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_DisableAllCounters(m_gpaSessionInfo.back());
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Disable all counters.", status);
|
|
}
|
|
}
|
|
|
|
bool AMDCounters::BeginMeasurementMode(ApiType apiType, void *pContext)
|
|
{
|
|
RDCASSERT(apiType == m_apiType);
|
|
RDCASSERT(pContext);
|
|
RDCASSERT(!m_gpaContextId);
|
|
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_OpenContext(
|
|
pContext, GPA_OPENCONTEXT_HIDE_SOFTWARE_COUNTERS_BIT | GPA_OPENCONTEXT_CLOCK_MODE_PEAK_BIT,
|
|
&m_gpaContextId);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_WARNING("Creating context for analysis failed", status);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void AMDCounters::EndMeasurementMode()
|
|
{
|
|
if(m_gpaContextId)
|
|
{
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_CloseContext(m_gpaContextId);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Close context failed", status);
|
|
}
|
|
|
|
m_gpaContextId = NULL;
|
|
}
|
|
}
|
|
|
|
uint32_t AMDCounters::GetPassCount()
|
|
{
|
|
gpa_uint32 numRequiredPasses = 0;
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_GetPassCount(m_gpaSessionInfo.back(), &numRequiredPasses);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get pass count.", status);
|
|
}
|
|
|
|
return (uint32_t)numRequiredPasses;
|
|
}
|
|
|
|
uint32_t AMDCounters::CreateSession()
|
|
{
|
|
uint32_t sessionID = m_gpaSessionCounter;
|
|
GPA_SessionId gpaSessionId = NULL;
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_CreateSession(
|
|
m_gpaContextId, GPA_SESSION_SAMPLE_TYPE_DISCRETE_COUNTER, &gpaSessionId);
|
|
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Create session.", status);
|
|
}
|
|
else
|
|
{
|
|
InitializeCmdInfo();
|
|
m_gpaSessionInfo.push_back(gpaSessionId);
|
|
++m_gpaSessionCounter;
|
|
}
|
|
|
|
return sessionID;
|
|
}
|
|
|
|
void AMDCounters::BeginSession(uint32_t sessionId)
|
|
{
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_BeginSession(m_gpaSessionInfo.at(sessionId));
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Begin session.", status);
|
|
}
|
|
else
|
|
{
|
|
m_passCounter = -1;
|
|
}
|
|
}
|
|
|
|
void AMDCounters::EndSesssion(uint32_t sessionId)
|
|
{
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_EndSession(m_gpaSessionInfo.at(sessionId));
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("End session.", status);
|
|
}
|
|
|
|
m_passCounter = 0u;
|
|
}
|
|
|
|
void AMDCounters::InitializeCmdInfo()
|
|
{
|
|
switch(m_apiType)
|
|
{
|
|
case ApiType::Dx11:
|
|
case ApiType::Ogl: break;
|
|
case ApiType::Vk:
|
|
case ApiType::Dx12:
|
|
if(NULL == m_gpaCmdListInfo.m_pCommandListMap)
|
|
{
|
|
m_gpaCmdListInfo.m_pCommandListMap = new std::map<void *, GPA_CommandListId>();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void AMDCounters::DeInitializeCmdInfo()
|
|
{
|
|
switch(m_apiType)
|
|
{
|
|
case ApiType::Dx11:
|
|
case ApiType::Ogl: break;
|
|
case ApiType::Vk:
|
|
case ApiType::Dx12: SAFE_DELETE(m_gpaCmdListInfo.m_pCommandListMap); break;
|
|
}
|
|
}
|
|
|
|
void AMDCounters::DeleteSession(uint32_t sessionId)
|
|
{
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_DeleteSession(m_gpaSessionInfo.at(sessionId));
|
|
DeInitializeCmdInfo();
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Create session.", status);
|
|
}
|
|
}
|
|
|
|
std::vector<CounterResult> AMDCounters::GetCounterData(uint32_t sessionID, uint32_t maxSampleIndex,
|
|
const std::vector<uint32_t> &eventIDs,
|
|
const std::vector<GPUCounter> &counters)
|
|
{
|
|
std::vector<CounterResult> ret;
|
|
|
|
bool isReady = false;
|
|
|
|
const uint32_t timeoutPeriod = 10000; // ms
|
|
|
|
PerformanceTimer timeout;
|
|
|
|
do
|
|
{
|
|
isReady = IsSessionReady(sessionID);
|
|
if(!isReady)
|
|
{
|
|
Threading::Sleep(0);
|
|
|
|
if(timeout.GetMilliseconds() > timeoutPeriod)
|
|
{
|
|
GPA_LoggingCallback(GPA_LOGGING_ERROR, "GetCounterData failed due to elapsed timeout.");
|
|
return ret;
|
|
}
|
|
}
|
|
} while(!isReady);
|
|
|
|
GPA_SessionId gpaSessionId = m_gpaSessionInfo.at(sessionID);
|
|
size_t sampleResultSize = 0u;
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_GetSampleResultSize(gpaSessionId, 0, &sampleResultSize);
|
|
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get Sample Result Size", status);
|
|
}
|
|
|
|
void *pSampleResult = malloc(sampleResultSize);
|
|
|
|
for(uint32_t s = 0; s < maxSampleIndex; s++)
|
|
{
|
|
status = m_pGPUPerfAPI->GPA_GetSampleResult(gpaSessionId, s, sampleResultSize, pSampleResult);
|
|
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get Sample Result ", status);
|
|
}
|
|
|
|
for(size_t c = 0; c < counters.size(); c++)
|
|
{
|
|
const CounterDescription desc = GetCounterDescription(counters[c]);
|
|
const uint32_t internalIndex = m_PublicToInternalCounter[counters[c]];
|
|
|
|
GPA_Usage_Type usageType;
|
|
status = m_pGPUPerfAPI->GPA_GetCounterUsageType(m_gpaContextId, internalIndex, &usageType);
|
|
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Get counter usage type.", status);
|
|
}
|
|
|
|
switch(desc.resultType)
|
|
{
|
|
case CompType::UInt:
|
|
{
|
|
uint64_t value = 0;
|
|
|
|
memcpy(&value, (uint64_t *)(pSampleResult) + c, sizeof(uint64_t));
|
|
// normalise units as expected
|
|
if(usageType == GPA_USAGE_TYPE_KILOBYTES)
|
|
{
|
|
value *= 1000;
|
|
}
|
|
|
|
if(desc.unit == CounterUnit::Percentage)
|
|
{
|
|
value = RDCCLAMP(value, (uint64_t)0ULL, (uint64_t)100ULL);
|
|
}
|
|
ret.push_back(CounterResult(eventIDs[s], counters[c], (uint64_t)value));
|
|
}
|
|
break;
|
|
case CompType::Double:
|
|
{
|
|
double value = 0.0;
|
|
memcpy(&value, (double *)(pSampleResult) + c, sizeof(double));
|
|
|
|
// normalise units as expected
|
|
if(usageType == GPA_USAGE_TYPE_KILOBYTES)
|
|
{
|
|
value *= 1000.0;
|
|
}
|
|
else if(usageType == GPA_USAGE_TYPE_MILLISECONDS)
|
|
{
|
|
value /= 1000.0;
|
|
}
|
|
|
|
ret.push_back(CounterResult(eventIDs[s], counters[c], value));
|
|
}
|
|
break;
|
|
default: RDCASSERT(0); break;
|
|
};
|
|
}
|
|
}
|
|
|
|
free(pSampleResult);
|
|
DeleteSession(sessionID);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool AMDCounters::IsSessionReady(uint32_t sessionIndex)
|
|
{
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_IsSessionComplete(m_gpaSessionInfo.at(sessionIndex));
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Is session ready", status);
|
|
}
|
|
|
|
return status == GPA_STATUS_OK;
|
|
}
|
|
|
|
void AMDCounters::BeginPass()
|
|
{
|
|
m_passCounter++;
|
|
|
|
if(m_apiType == ApiType::Dx12 || m_apiType == ApiType::Vk)
|
|
{
|
|
if(NULL != m_gpaCmdListInfo.m_pCommandListMap)
|
|
{
|
|
m_gpaCmdListInfo.m_pCommandListMap->clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
void AMDCounters::EndPass()
|
|
{
|
|
bool isReady = false;
|
|
|
|
const uint32_t timeoutPeriod = 10000; // ms
|
|
|
|
PerformanceTimer timeout;
|
|
|
|
do
|
|
{
|
|
isReady =
|
|
GPA_STATUS_OK == m_pGPUPerfAPI->GPA_IsPassComplete(m_gpaSessionInfo.back(), m_passCounter);
|
|
if(!isReady)
|
|
{
|
|
Threading::Sleep(0);
|
|
|
|
PerformanceTimer endTime;
|
|
|
|
if(timeout.GetMilliseconds() > timeoutPeriod)
|
|
{
|
|
GPA_LoggingCallback(GPA_LOGGING_ERROR, "GPA_IsPassComplete failed due to elapsed timeout.");
|
|
break;
|
|
}
|
|
}
|
|
} while(!isReady);
|
|
}
|
|
|
|
void AMDCounters::BeginSample(uint32_t sampleID, void *pCommandList)
|
|
{
|
|
GPA_CommandListId startingSampleCmd = GPA_NULL_COMMAND_LIST;
|
|
|
|
switch(m_apiType)
|
|
{
|
|
case ApiType::Dx11:
|
|
case ApiType::Ogl: startingSampleCmd = m_gpaCmdListInfo.m_gpaCommandListId; break;
|
|
case ApiType::Vk:
|
|
case ApiType::Dx12:
|
|
startingSampleCmd = m_gpaCmdListInfo.m_pCommandListMap->at(pCommandList);
|
|
break;
|
|
}
|
|
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_BeginSample(sampleID, startingSampleCmd);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("Begin sample.", status);
|
|
}
|
|
}
|
|
|
|
void AMDCounters::EndSample(void *pCommandList)
|
|
{
|
|
GPA_CommandListId endingSampleCmd = GPA_NULL_COMMAND_LIST;
|
|
|
|
switch(m_apiType)
|
|
{
|
|
case ApiType::Dx11:
|
|
case ApiType::Ogl: endingSampleCmd = m_gpaCmdListInfo.m_gpaCommandListId; break;
|
|
case ApiType::Vk:
|
|
case ApiType::Dx12:
|
|
endingSampleCmd = m_gpaCmdListInfo.m_pCommandListMap->at(pCommandList);
|
|
break;
|
|
}
|
|
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_EndSample(endingSampleCmd);
|
|
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("End sample.", status);
|
|
}
|
|
}
|
|
|
|
void AMDCounters::BeginCommandList(void *pCommandList)
|
|
{
|
|
void *cmdList = NULL;
|
|
GPA_Command_List_Type cmdType = GPA_COMMAND_LIST_NONE;
|
|
switch(m_apiType)
|
|
{
|
|
case ApiType::Dx11:
|
|
case ApiType::Ogl: cmdList = GPA_NULL_COMMAND_LIST; break;
|
|
case ApiType::Vk:
|
|
case ApiType::Dx12:
|
|
cmdList = pCommandList;
|
|
cmdType = GPA_COMMAND_LIST_PRIMARY;
|
|
break;
|
|
}
|
|
|
|
GPA_CommandListId gpaCmdId = NULL;
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_BeginCommandList(m_gpaSessionInfo.back(), m_passCounter,
|
|
cmdList, cmdType, &gpaCmdId);
|
|
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("BeginCommandList.", status);
|
|
}
|
|
else
|
|
{
|
|
switch(m_apiType)
|
|
{
|
|
case ApiType::Dx11:
|
|
case ApiType::Ogl: m_gpaCmdListInfo.m_gpaCommandListId = gpaCmdId; break;
|
|
case ApiType::Vk:
|
|
case ApiType::Dx12:
|
|
m_gpaCmdListInfo.m_pCommandListMap->insert(
|
|
std::pair<void *, GPA_CommandListId>(cmdList, gpaCmdId));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AMDCounters::EndCommandList(void *pCommandList)
|
|
{
|
|
GPA_CommandListId endingCmd = GPA_NULL_COMMAND_LIST;
|
|
|
|
switch(m_apiType)
|
|
{
|
|
case ApiType::Dx11:
|
|
case ApiType::Ogl: endingCmd = m_gpaCmdListInfo.m_gpaCommandListId; break;
|
|
case ApiType::Vk:
|
|
case ApiType::Dx12: endingCmd = m_gpaCmdListInfo.m_pCommandListMap->at(pCommandList); break;
|
|
}
|
|
|
|
GPA_Status status = m_pGPUPerfAPI->GPA_EndCommandList(endingCmd);
|
|
if(AMD_FAILED(status))
|
|
{
|
|
GPA_ERROR("EndCommandList.", status);
|
|
}
|
|
}
|