mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-04 17:10:47 +00:00
313 lines
7.5 KiB
C++
313 lines
7.5 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2015-2016 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 "common/common.h"
|
|
#include "d3d11_debug.h"
|
|
#include "d3d11_device.h"
|
|
#include "d3d11_context.h"
|
|
|
|
#if defined(ENABLE_NVIDIA_PERFKIT)
|
|
#define NVPM_INITGUID
|
|
#include STRINGIZE(CONCAT(NVIDIA_PERFKIT_DIR, inc\\NvPmApi.h))
|
|
|
|
NvPmApi *nvAPI = NULL;
|
|
|
|
int enumFunc(NVPMCounterID id, const char *name)
|
|
{
|
|
RDCLOG("(% 4d): %s", id, name);
|
|
|
|
return NVPM_OK;
|
|
}
|
|
#endif
|
|
|
|
void D3D11DebugManager::PreDeviceInitCounters()
|
|
{
|
|
}
|
|
|
|
void D3D11DebugManager::PostDeviceInitCounters()
|
|
{
|
|
#if defined(ENABLE_NVIDIA_PERFKIT)
|
|
HMODULE nvapi = LoadLibraryA(STRINGIZE(CONCAT(NVIDIA_PERFKIT_DIR, bin\\win7_x86\\NvPmApi.Core.dll)));
|
|
if(nvapi == NULL)
|
|
{
|
|
RDCERR("Couldn't load perfkit");
|
|
return;
|
|
}
|
|
|
|
NVPMGetExportTable_Pfn NVPMGetExportTable = (NVPMGetExportTable_Pfn)GetProcAddress(nvapi, "NVPMGetExportTable");
|
|
if(NVPMGetExportTable == NULL)
|
|
{
|
|
RDCERR("Couldn't Get Symbol 'NVPMGetExportTable'");
|
|
return;
|
|
}
|
|
|
|
NVPMRESULT nvResult = NVPMGetExportTable(&ETID_NvPmApi, (void **)&nvAPI);
|
|
if(nvResult != NVPM_OK)
|
|
{
|
|
RDCERR("Couldn't NVPMGetExportTable");
|
|
return;
|
|
}
|
|
|
|
nvResult = nvAPI->Init();
|
|
|
|
if(nvResult != NVPM_OK)
|
|
{
|
|
RDCERR("Couldn't nvAPI->Init");
|
|
return;
|
|
}
|
|
|
|
NVPMContext context(0);
|
|
nvResult = nvAPI->CreateContextFromD3D11Device(m_pDevice, &context);
|
|
|
|
if(nvResult != NVPM_OK)
|
|
{
|
|
RDCERR("Couldn't nvAPI->CreateContextFromD3D11Device");
|
|
return;
|
|
}
|
|
|
|
nvAPI->EnumCountersByContext(context, &enumFunc);
|
|
|
|
nvAPI->DestroyContext(context);
|
|
nvAPI->Shutdown();
|
|
nvAPI = NULL;
|
|
FreeLibrary(nvapi);
|
|
#endif
|
|
}
|
|
|
|
void D3D11DebugManager::PreDeviceShutdownCounters()
|
|
{
|
|
}
|
|
|
|
void D3D11DebugManager::PostDeviceShutdownCounters()
|
|
{
|
|
}
|
|
|
|
vector<uint32_t> D3D11DebugManager::EnumerateCounters()
|
|
{
|
|
vector<uint32_t> ret;
|
|
|
|
ret.push_back(eCounter_EventGPUDuration);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void D3D11DebugManager::DescribeCounter(uint32_t counterID, CounterDescription &desc)
|
|
{
|
|
desc.counterID = counterID;
|
|
|
|
if(counterID == eCounter_EventGPUDuration)
|
|
{
|
|
desc.name = "GPU Duration";
|
|
desc.description = "Time taken for this event on the GPU, as measured by delta between two GPU timestamps.";
|
|
desc.resultByteWidth = 8;
|
|
desc.resultCompType = eCompType_Double;
|
|
desc.units = eUnits_Seconds;
|
|
}
|
|
else
|
|
{
|
|
desc.name = "Unknown";
|
|
desc.description = "Unknown counter ID";
|
|
desc.resultByteWidth = 0;
|
|
desc.resultCompType = eCompType_None;
|
|
desc.units = eUnits_Absolute;
|
|
}
|
|
}
|
|
|
|
struct GPUTimer
|
|
{
|
|
ID3D11Query *before;
|
|
ID3D11Query *after;
|
|
uint32_t eventID;
|
|
};
|
|
|
|
struct CounterContext
|
|
{
|
|
uint32_t frameID;
|
|
uint32_t eventStart;
|
|
vector<GPUTimer> timers;
|
|
int reuseIdx;
|
|
};
|
|
|
|
void D3D11DebugManager::FillTimers(CounterContext &ctx, const DrawcallTreeNode &drawnode)
|
|
{
|
|
const D3D11_QUERY_DESC qdesc = { D3D11_QUERY_TIMESTAMP, 0 };
|
|
|
|
if(drawnode.children.empty()) return;
|
|
|
|
for(size_t i=0; i < drawnode.children.size(); i++)
|
|
{
|
|
const FetchDrawcall &d = drawnode.children[i].draw;
|
|
FillTimers(ctx, drawnode.children[i]);
|
|
|
|
if(d.events.count == 0) continue;
|
|
|
|
GPUTimer *timer = NULL;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
{
|
|
if(ctx.reuseIdx == -1)
|
|
{
|
|
ctx.timers.push_back(GPUTimer());
|
|
|
|
timer = &ctx.timers.back();
|
|
timer->eventID = d.eventID;
|
|
timer->before = timer->after = NULL;
|
|
|
|
hr = m_pDevice->CreateQuery(&qdesc, &timer->before);
|
|
RDCASSERT(SUCCEEDED(hr));
|
|
hr = m_pDevice->CreateQuery(&qdesc, &timer->after);
|
|
RDCASSERT(SUCCEEDED(hr));
|
|
}
|
|
else
|
|
{
|
|
timer = &ctx.timers[ctx.reuseIdx++];
|
|
}
|
|
}
|
|
|
|
m_WrappedDevice->ReplayLog(ctx.frameID, ctx.eventStart, d.eventID, eReplay_WithoutDraw);
|
|
|
|
m_pImmediateContext->Flush();
|
|
|
|
if(timer->before && timer->after)
|
|
{
|
|
m_pImmediateContext->End(timer->before);
|
|
m_WrappedDevice->ReplayLog(ctx.frameID, ctx.eventStart, d.eventID, eReplay_OnlyDraw);
|
|
m_pImmediateContext->End(timer->after);
|
|
}
|
|
else
|
|
{
|
|
m_WrappedDevice->ReplayLog(ctx.frameID, ctx.eventStart, d.eventID, eReplay_OnlyDraw);
|
|
}
|
|
|
|
ctx.eventStart = d.eventID+1;
|
|
}
|
|
}
|
|
|
|
vector<CounterResult> D3D11DebugManager::FetchCounters(uint32_t frameID, const vector<uint32_t> &counters)
|
|
{
|
|
vector<CounterResult> ret;
|
|
|
|
if(counters.empty())
|
|
{
|
|
RDCERR("No counters specified to FetchCounters");
|
|
return ret;
|
|
}
|
|
|
|
uint32_t counterID = counters[0];
|
|
RDCASSERT(counters.size() == 1);
|
|
RDCASSERT(counterID == eCounter_EventGPUDuration);
|
|
|
|
SCOPED_TIMER("Fetch Counters for %u", counterID);
|
|
|
|
D3D11_QUERY_DESC disjointdesc = { D3D11_QUERY_TIMESTAMP_DISJOINT, 0 };
|
|
ID3D11Query *disjoint = NULL;
|
|
|
|
D3D11_QUERY_DESC qdesc = { D3D11_QUERY_TIMESTAMP, 0 };
|
|
ID3D11Query *start = NULL;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = m_pDevice->CreateQuery(&disjointdesc, &disjoint);
|
|
if(FAILED(hr))
|
|
{
|
|
RDCERR("Failed to create disjoint query %08x", hr);
|
|
return ret;
|
|
}
|
|
|
|
hr = m_pDevice->CreateQuery(&qdesc, &start);
|
|
if(FAILED(hr))
|
|
{
|
|
RDCERR("Failed to create start query %08x", hr);
|
|
return ret;
|
|
}
|
|
|
|
CounterContext ctx;
|
|
ctx.frameID = frameID;
|
|
|
|
for(int loop=0; loop < 1; loop++)
|
|
{
|
|
{
|
|
m_pImmediateContext->Begin(disjoint);
|
|
|
|
m_pImmediateContext->End(start);
|
|
|
|
ctx.eventStart = 0;
|
|
ctx.reuseIdx = loop == 0 ? -1 : 0;
|
|
FillTimers(ctx, m_WrappedContext->GetRootDraw());
|
|
|
|
m_pImmediateContext->End(disjoint);
|
|
}
|
|
|
|
{
|
|
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData;
|
|
do
|
|
{
|
|
hr = m_pImmediateContext->GetData(disjoint, &disjointData, sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT), 0);
|
|
} while(hr == S_FALSE);
|
|
RDCASSERT(hr == S_OK);
|
|
|
|
RDCASSERT(!disjointData.Disjoint);
|
|
|
|
double ticksToSecs = double(disjointData.Frequency);
|
|
|
|
UINT64 a=0;
|
|
m_pImmediateContext->GetData(start, &a, sizeof(UINT64), 0);
|
|
|
|
for(size_t i=0; i < ctx.timers.size(); i++)
|
|
{
|
|
if(ctx.timers[i].before && ctx.timers[i].after)
|
|
{
|
|
hr = m_pImmediateContext->GetData(ctx.timers[i].before, &a, sizeof(UINT64), 0);
|
|
RDCASSERT(hr == S_OK);
|
|
|
|
UINT64 b=0;
|
|
hr = m_pImmediateContext->GetData(ctx.timers[i].after, &b, sizeof(UINT64), 0);
|
|
RDCASSERT(hr == S_OK);
|
|
|
|
double duration = (double(b-a)/ticksToSecs);
|
|
|
|
ret.push_back(CounterResult(ctx.timers[i].eventID, counterID, duration));
|
|
|
|
a = b;
|
|
}
|
|
else
|
|
{
|
|
ret.push_back(CounterResult(ctx.timers[i].eventID, counterID, 0.0));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for(size_t i=0; i < ctx.timers.size(); i++)
|
|
{
|
|
SAFE_RELEASE(ctx.timers[i].before);
|
|
SAFE_RELEASE(ctx.timers[i].after);
|
|
}
|
|
|
|
SAFE_RELEASE(disjoint);
|
|
SAFE_RELEASE(start);
|
|
|
|
return ret;
|
|
} |