mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-04 17:10:47 +00:00
Implement Intel performance counters support for D3D11
This commit is contained in:
committed by
Baldur Karlsson
parent
d61726bde3
commit
4a4fdb40e7
@@ -81,6 +81,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NV", "renderdoc\driver\ihv\
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AMD_RGP", "renderdoc\driver\ihv\amd\AMD_RGP.vcxproj", "{B33F8FFD-3C04-4779-9C3B-E2858387971B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Intel", "renderdoc\driver\ihv\intel\Intel.vcxproj", "{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Development|x64 = Development|x64
|
||||
@@ -273,6 +275,14 @@ Global
|
||||
{B33F8FFD-3C04-4779-9C3B-E2858387971B}.Release|x64.Build.0 = Release|x64
|
||||
{B33F8FFD-3C04-4779-9C3B-E2858387971B}.Release|x86.ActiveCfg = Release|Win32
|
||||
{B33F8FFD-3C04-4779-9C3B-E2858387971B}.Release|x86.Build.0 = Release|Win32
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Development|x64.ActiveCfg = Development|x64
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Development|x64.Build.0 = Development|x64
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Development|x86.ActiveCfg = Development|Win32
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Development|x86.Build.0 = Development|Win32
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Release|x64.ActiveCfg = Release|x64
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Release|x64.Build.0 = Release|x64
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Release|x86.ActiveCfg = Release|Win32
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -307,5 +317,6 @@ Global
|
||||
{37955C79-D91D-423F-8C6C-8F5BCF4F28D4} = {B5A783D9-AEB9-420D-8E77-D4D930F8D88C}
|
||||
{40349AD9-5558-4DF4-84E2-11934DE90A11} = {4DA2F3E3-9A65-45DD-A69B-82C7757D4904}
|
||||
{B33F8FFD-3C04-4779-9C3B-E2858387971B} = {4DA2F3E3-9A65-45DD-A69B-82C7757D4904}
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5} = {4DA2F3E3-9A65-45DD-A69B-82C7757D4904}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <iterator>
|
||||
#include "common/common.h"
|
||||
#include "driver/ihv/amd/amd_counters.h"
|
||||
#include "driver/ihv/intel/intel_counters.h"
|
||||
#include "driver/ihv/nv/nv_counters.h"
|
||||
#include "d3d11_context.h"
|
||||
#include "d3d11_debug.h"
|
||||
@@ -61,6 +62,12 @@ vector<GPUCounter> D3D11Replay::EnumerateCounters()
|
||||
ret.insert(ret.end(), nvCounters.begin(), nvCounters.end());
|
||||
}
|
||||
|
||||
if(m_pIntelCounters)
|
||||
{
|
||||
vector<GPUCounter> intelCounters = m_pIntelCounters->GetPublicCounterIds();
|
||||
ret.insert(ret.end(), intelCounters.begin(), intelCounters.end());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -87,6 +94,15 @@ CounterDescription D3D11Replay::DescribeCounter(GPUCounter counterID)
|
||||
}
|
||||
}
|
||||
|
||||
// Intel
|
||||
if(IsIntelCounter(counterID))
|
||||
{
|
||||
if(m_pIntelCounters)
|
||||
{
|
||||
return m_pIntelCounters->GetCounterDescription(counterID);
|
||||
}
|
||||
}
|
||||
|
||||
// 448A0516-B50E-4312-A6DC-CFE7222FC1AC
|
||||
desc.uuid.words[0] = 0x448A0516;
|
||||
desc.uuid.words[1] = 0xB50E4312;
|
||||
@@ -383,6 +399,41 @@ void D3D11Replay::FillTimersNV(uint32_t &eventStartID, uint32_t &sampleIndex,
|
||||
}
|
||||
}
|
||||
|
||||
void D3D11Replay::FillTimersIntel(uint32_t &eventStartID, uint32_t &sampleIndex,
|
||||
vector<uint32_t> &eventIDs, const DrawcallDescription &drawnode)
|
||||
{
|
||||
if(drawnode.children.empty())
|
||||
return;
|
||||
|
||||
for(size_t i = 0; i < drawnode.children.size(); i++)
|
||||
{
|
||||
const DrawcallDescription &d = drawnode.children[i];
|
||||
|
||||
FillTimersIntel(eventStartID, sampleIndex, eventIDs, drawnode.children[i]);
|
||||
|
||||
if(d.events.empty() || (!(drawnode.children[i].flags & DrawFlags::Drawcall) &&
|
||||
!(drawnode.children[i].flags & DrawFlags::Dispatch)))
|
||||
continue;
|
||||
|
||||
eventIDs.push_back(d.eventId);
|
||||
|
||||
m_pDevice->ReplayLog(eventStartID, d.eventId, eReplay_WithoutDraw);
|
||||
|
||||
SerializeImmediateContext();
|
||||
|
||||
m_pIntelCounters->BeginSample();
|
||||
|
||||
m_pDevice->ReplayLog(eventStartID, d.eventId, eReplay_OnlyDraw);
|
||||
|
||||
SerializeImmediateContext();
|
||||
|
||||
m_pIntelCounters->EndSample();
|
||||
|
||||
eventStartID = d.eventId + 1;
|
||||
sampleIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
vector<CounterResult> D3D11Replay::FetchCountersAMD(const vector<GPUCounter> &counters)
|
||||
{
|
||||
ID3D11Device *d3dDevice = m_pDevice->GetReal();
|
||||
@@ -472,6 +523,45 @@ vector<CounterResult> D3D11Replay::FetchCountersNV(const vector<GPUCounter> &cou
|
||||
return ret;
|
||||
}
|
||||
|
||||
vector<CounterResult> D3D11Replay::FetchCountersIntel(const vector<GPUCounter> &counters)
|
||||
{
|
||||
m_pIntelCounters->DisableAllCounters();
|
||||
|
||||
// enable counters it needs
|
||||
for(size_t i = 0; i < counters.size(); i++)
|
||||
{
|
||||
// This function is only called internally, and violating this assertion means our
|
||||
// caller has invoked this method incorrectly
|
||||
RDCASSERT(IsIntelCounter(counters[i]));
|
||||
m_pIntelCounters->EnableCounter(counters[i]);
|
||||
}
|
||||
|
||||
m_pIntelCounters->BeginSession();
|
||||
|
||||
uint32_t passCount = m_pIntelCounters->GetPassCount();
|
||||
|
||||
uint32_t sampleIndex = 0;
|
||||
|
||||
vector<uint32_t> eventIDs;
|
||||
|
||||
for(uint32_t p = 0; p < passCount; p++)
|
||||
{
|
||||
m_pIntelCounters->BeginPass();
|
||||
uint32_t eventStartID = 0;
|
||||
|
||||
sampleIndex = 0;
|
||||
|
||||
eventIDs.clear();
|
||||
|
||||
FillTimersIntel(eventStartID, sampleIndex, eventIDs, m_pImmediateContext->GetRootDraw());
|
||||
m_pIntelCounters->EndPass();
|
||||
}
|
||||
|
||||
m_pIntelCounters->EndSession();
|
||||
|
||||
return m_pIntelCounters->GetCounterData(eventIDs, counters);
|
||||
}
|
||||
|
||||
vector<CounterResult> D3D11Replay::FetchCounters(const vector<GPUCounter> &counters)
|
||||
{
|
||||
vector<CounterResult> ret;
|
||||
@@ -486,7 +576,9 @@ vector<CounterResult> D3D11Replay::FetchCounters(const vector<GPUCounter> &count
|
||||
|
||||
vector<GPUCounter> d3dCounters;
|
||||
std::copy_if(counters.begin(), counters.end(), std::back_inserter(d3dCounters),
|
||||
[](const GPUCounter &c) { return !IsAMDCounter(c) && !IsNvidiaCounter(c); });
|
||||
[](const GPUCounter &c) {
|
||||
return !IsAMDCounter(c) && !IsNvidiaCounter(c) && !IsIntelCounter(c);
|
||||
});
|
||||
|
||||
if(m_pAMDCounters)
|
||||
{
|
||||
@@ -514,6 +606,18 @@ vector<CounterResult> D3D11Replay::FetchCounters(const vector<GPUCounter> &count
|
||||
}
|
||||
}
|
||||
|
||||
if(m_pIntelCounters)
|
||||
{
|
||||
vector<GPUCounter> intelCounters;
|
||||
std::copy_if(counters.begin(), counters.end(), std::back_inserter(intelCounters),
|
||||
[](const GPUCounter &c) { return IsIntelCounter(c); });
|
||||
|
||||
if(!intelCounters.empty())
|
||||
{
|
||||
ret = FetchCountersIntel(intelCounters);
|
||||
}
|
||||
}
|
||||
|
||||
if(d3dCounters.empty())
|
||||
{
|
||||
return ret;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "d3d11_replay.h"
|
||||
#include "driver/dx/official/d3dcompiler.h"
|
||||
#include "driver/ihv/amd/amd_counters.h"
|
||||
#include "driver/ihv/intel/intel_counters.h"
|
||||
#include "driver/ihv/nv/nv_counters.h"
|
||||
#include "driver/shaders/dxbc/dxbc_debug.h"
|
||||
#include "maths/camera.h"
|
||||
@@ -159,6 +160,7 @@ void D3D11Replay::CreateResources()
|
||||
|
||||
AMDCounters *countersAMD = NULL;
|
||||
NVCounters *countersNV = NULL;
|
||||
IntelCounters *countersIntel = NULL;
|
||||
|
||||
if(m_Vendor == GPUVendor::AMD)
|
||||
{
|
||||
@@ -170,6 +172,11 @@ void D3D11Replay::CreateResources()
|
||||
RDCLOG("nVidia GPU detected - trying to initialise nVidia counters");
|
||||
countersNV = new NVCounters();
|
||||
}
|
||||
else if(m_Vendor == GPUVendor::Intel)
|
||||
{
|
||||
RDCLOG("Intel GPU detected - trying to initialize Intel counters");
|
||||
countersIntel = new IntelCounters();
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCLOG("%s GPU detected - no counters available", ToStr(m_Vendor).c_str());
|
||||
@@ -196,6 +203,17 @@ void D3D11Replay::CreateResources()
|
||||
delete countersNV;
|
||||
m_pNVCounters = NULL;
|
||||
}
|
||||
|
||||
if(countersIntel && countersIntel->Init(d3dDevice))
|
||||
{
|
||||
m_pIntelCounters = countersIntel;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete countersIntel;
|
||||
m_pIntelCounters = NULL;
|
||||
}
|
||||
|
||||
RenderDoc::Inst().SetProgress(LoadProgress::DebugManagerInit, 1.0f);
|
||||
}
|
||||
|
||||
@@ -214,6 +232,7 @@ void D3D11Replay::DestroyResources()
|
||||
|
||||
SAFE_DELETE(m_pAMDCounters);
|
||||
SAFE_DELETE(m_pNVCounters);
|
||||
SAFE_DELETE(m_pIntelCounters);
|
||||
|
||||
ShutdownStreamOut();
|
||||
ClearPostVSCache();
|
||||
@@ -3533,6 +3552,8 @@ ReplayStatus D3D11_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver)
|
||||
{
|
||||
RDCDEBUG("Creating a D3D11 replay device");
|
||||
|
||||
IntelCounters::Load();
|
||||
|
||||
HMODULE lib = NULL;
|
||||
lib = LoadLibraryA("d3d11.dll");
|
||||
if(lib == NULL)
|
||||
|
||||
@@ -38,6 +38,7 @@ class WrappedID3D11DeviceContext;
|
||||
|
||||
class AMDCounters;
|
||||
class NVCounters;
|
||||
class IntelCounters;
|
||||
struct D3D11CounterContext;
|
||||
|
||||
struct D3D11PostVSData
|
||||
@@ -255,12 +256,15 @@ private:
|
||||
|
||||
std::vector<CounterResult> FetchCountersAMD(const vector<GPUCounter> &counters);
|
||||
std::vector<CounterResult> FetchCountersNV(const vector<GPUCounter> &counters);
|
||||
std::vector<CounterResult> FetchCountersIntel(const vector<GPUCounter> &counters);
|
||||
|
||||
void FillTimers(D3D11CounterContext &ctx, const DrawcallDescription &drawnode);
|
||||
void FillTimersAMD(uint32_t &eventStartID, uint32_t &sampleIndex, vector<uint32_t> &eventIDs,
|
||||
const DrawcallDescription &drawnode);
|
||||
void FillTimersNV(uint32_t &eventStartID, uint32_t &sampleIndex, vector<uint32_t> &eventIDs,
|
||||
const DrawcallDescription &drawnode);
|
||||
void FillTimersIntel(uint32_t &eventStartID, uint32_t &sampleIndex, vector<uint32_t> &eventIDs,
|
||||
const DrawcallDescription &drawnode);
|
||||
|
||||
void SerializeImmediateContext();
|
||||
|
||||
@@ -301,6 +305,7 @@ private:
|
||||
|
||||
AMDCounters *m_pAMDCounters = NULL;
|
||||
NVCounters *m_pNVCounters = NULL;
|
||||
IntelCounters *m_pIntelCounters = NULL;
|
||||
|
||||
WrappedID3D11Device *m_pDevice = NULL;
|
||||
WrappedID3D11DeviceContext *m_pImmediateContext = NULL;
|
||||
|
||||
@@ -158,6 +158,9 @@
|
||||
<ProjectReference Include="..\ihv\amd\AMD.vcxproj">
|
||||
<Project>{5de5a561-548a-4dd7-90f0-06a2b39eae9a}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ihv\intel\Intel.vcxproj">
|
||||
<Project>{7fcb5fc5-1dbd-4da6-83a0-6ba4e945bda5}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\shaders\dxbc\renderdoc_dxbc.vcxproj">
|
||||
<Project>{c43ff27e-a155-4852-88ec-5ce9334c07a8}</Project>
|
||||
<Private>false</Private>
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Development|Win32">
|
||||
<Configuration>Development</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Development|x64">
|
||||
<Configuration>Development</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}</ProjectGuid>
|
||||
<RootNamespace>Intel</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
|
||||
<ExecutablePath>$(ExecutablePath)</ExecutablePath>
|
||||
<IncludePath>$(SolutionDir)\breakpad;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
<ExcludePath>$(ExcludePath)</ExcludePath>
|
||||
<TargetName>driver_$(ProjectName)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)renderdoc\;$(SolutionDir)renderdoc\3rdparty\</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>RENDERDOC_EXPORTS;RENDERDOC_PLATFORM_WIN32;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4100</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Development'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="intel_counters.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="intel_counters.h" />
|
||||
<ClInclude Include="official\DriverStorePath.h" />
|
||||
<ClInclude Include="official\metrics_discovery_api.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,440 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 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 "common/common.h"
|
||||
|
||||
#include "official/DriverStorePath.h"
|
||||
#include "intel_counters.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
const static std::vector<std::string> metricSetBlacklist = {"TestOa"};
|
||||
|
||||
HMODULE IntelCounters::m_MDLibraryHandle = 0;
|
||||
IMetricsDevice_1_5 *IntelCounters::m_metricsDevice = NULL;
|
||||
OpenMetricsDevice_fn IntelCounters::OpenMetricsDevice = NULL;
|
||||
CloseMetricsDevice_fn IntelCounters::CloseMetricsDevice = NULL;
|
||||
|
||||
IntelCounters::IntelCounters()
|
||||
: m_device(NULL), m_deviceContext(NULL), m_counter(NULL), m_passIndex(0), m_sampleIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
IntelCounters::~IntelCounters()
|
||||
{
|
||||
if(CloseMetricsDevice)
|
||||
{
|
||||
CloseMetricsDevice(m_metricsDevice);
|
||||
m_metricsDevice = NULL;
|
||||
}
|
||||
|
||||
if(m_MDLibraryHandle)
|
||||
FreeLibrary(m_MDLibraryHandle);
|
||||
}
|
||||
|
||||
void IntelCounters::Load()
|
||||
{
|
||||
if(m_metricsDevice)
|
||||
return;
|
||||
|
||||
m_MDLibraryHandle = LoadDynamicLibrary(L"igdmd64.dll", NULL, 0);
|
||||
if(!m_MDLibraryHandle)
|
||||
return;
|
||||
|
||||
OpenMetricsDevice = (OpenMetricsDevice_fn)GetProcAddress(m_MDLibraryHandle, "OpenMetricsDevice");
|
||||
if(!OpenMetricsDevice)
|
||||
return;
|
||||
|
||||
CloseMetricsDevice =
|
||||
(CloseMetricsDevice_fn)GetProcAddress(m_MDLibraryHandle, "CloseMetricsDevice");
|
||||
if(!CloseMetricsDevice)
|
||||
return;
|
||||
|
||||
OpenMetricsDevice(&m_metricsDevice);
|
||||
}
|
||||
|
||||
bool IntelCounters::Init(void *pContext)
|
||||
{
|
||||
if(!pContext)
|
||||
return false;
|
||||
|
||||
if(!m_metricsDevice)
|
||||
return false;
|
||||
|
||||
m_device = (ID3D11Device *)pContext;
|
||||
m_device->GetImmediateContext(&m_deviceContext);
|
||||
if(!m_deviceContext)
|
||||
return false;
|
||||
|
||||
TMetricsDeviceParams_1_2 *deviceParams = m_metricsDevice->GetParams();
|
||||
if(deviceParams->Version.MajorNumber < 1 ||
|
||||
(deviceParams->Version.MajorNumber == 1 && deviceParams->Version.MinorNumber < 1))
|
||||
{
|
||||
CloseMetricsDevice(m_metricsDevice);
|
||||
FreeLibrary(m_MDLibraryHandle);
|
||||
m_metricsDevice = NULL;
|
||||
m_MDLibraryHandle = (HMODULE)0;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Counters = EnumerateCounters();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CounterDescription IntelCounters::GetCounterDescription(GPUCounter counter)
|
||||
{
|
||||
return m_Counters[GPUCounterToCounterIndex(counter)];
|
||||
}
|
||||
|
||||
std::vector<CounterDescription> IntelCounters::EnumerateCounters()
|
||||
{
|
||||
m_Counters.clear();
|
||||
m_allMetricSets.clear();
|
||||
std::set<std::string> addedMetrics;
|
||||
TMetricsDeviceParams_1_2 *deviceParams = m_metricsDevice->GetParams();
|
||||
for(unsigned int i = 0; i < deviceParams->ConcurrentGroupsCount; ++i)
|
||||
{
|
||||
IConcurrentGroup_1_1 *concurrentGroup = m_metricsDevice->GetConcurrentGroup(i);
|
||||
TConcurrentGroupParams_1_0 *groupParams = concurrentGroup->GetParams();
|
||||
if(strcmp(groupParams->SymbolName, "OA") != 0)
|
||||
continue;
|
||||
|
||||
m_subscribedMetricsByCounterSet.resize(groupParams->MetricSetsCount);
|
||||
|
||||
for(unsigned int j = 0; j < groupParams->MetricSetsCount; ++j)
|
||||
{
|
||||
IMetricSet_1_1 *metricSet = concurrentGroup->GetMetricSet(j);
|
||||
metricSet->SetApiFiltering(API_TYPE_DX11);
|
||||
m_allMetricSets.push_back(metricSet);
|
||||
TMetricSetParams_1_0 *setParams = metricSet->GetParams();
|
||||
|
||||
if(std::find(metricSetBlacklist.begin(), metricSetBlacklist.end(), setParams->SymbolName) !=
|
||||
metricSetBlacklist.end())
|
||||
continue;
|
||||
|
||||
for(unsigned int k = 0; k < setParams->MetricsCount; ++k)
|
||||
{
|
||||
IMetric_1_0 *metric = metricSet->GetMetric(k);
|
||||
TMetricParams_1_0 *metricParams = metric->GetParams();
|
||||
|
||||
if((metricParams->UsageFlagsMask & EMetricUsageFlag::USAGE_FLAG_OVERVIEW) == 0)
|
||||
continue;
|
||||
|
||||
if(metricParams->ResultType == TMetricResultType::RESULT_BOOL)
|
||||
continue;
|
||||
|
||||
if(addedMetrics.count(metricParams->ShortName) > 0)
|
||||
continue;
|
||||
|
||||
CounterDescription counterDesc;
|
||||
counterDesc.name = metricParams->ShortName;
|
||||
counterDesc.description = metricParams->LongName;
|
||||
counterDesc.category = metricParams->GroupName;
|
||||
counterDesc.resultByteWidth = 8;
|
||||
counterDesc.resultType = CompType::Double;
|
||||
switch(metricParams->ResultType)
|
||||
{
|
||||
case RESULT_UINT32:
|
||||
counterDesc.resultType = CompType::UInt;
|
||||
counterDesc.resultByteWidth = sizeof(uint32_t);
|
||||
break;
|
||||
case RESULT_UINT64:
|
||||
counterDesc.resultType = CompType::UInt;
|
||||
counterDesc.resultByteWidth = sizeof(uint64_t);
|
||||
break;
|
||||
case RESULT_FLOAT:
|
||||
counterDesc.resultType = CompType::Float;
|
||||
counterDesc.resultByteWidth = sizeof(float);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
counterDesc.unit = CounterUnit::Absolute;
|
||||
if(strcmp(metricParams->MetricResultUnits, "cycles") == 0)
|
||||
counterDesc.unit = CounterUnit::Cycles;
|
||||
else if(strcmp(metricParams->MetricResultUnits, "bytes") == 0)
|
||||
counterDesc.unit = CounterUnit::Bytes;
|
||||
else if(strcmp(metricParams->MetricResultUnits, "percent") == 0)
|
||||
counterDesc.unit = CounterUnit::Percentage;
|
||||
else if(strcmp(metricParams->MetricResultUnits, "ns") == 0)
|
||||
{
|
||||
counterDesc.unit = CounterUnit::Seconds;
|
||||
counterDesc.resultType = CompType::Float;
|
||||
counterDesc.resultByteWidth = sizeof(float);
|
||||
}
|
||||
|
||||
uint32_t counterId = (uint32_t)GPUCounter::FirstIntel + (uint32_t)m_Counters.size();
|
||||
counterDesc.counter = (GPUCounter)counterId;
|
||||
m_Counters.push_back(counterDesc);
|
||||
addedMetrics.insert(counterDesc.name);
|
||||
m_metricLocation[(GPUCounter)counterId] = std::pair<uint32_t, uint32_t>(j, k);
|
||||
m_counterIds.push_back((GPUCounter)counterId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_Counters;
|
||||
}
|
||||
|
||||
uint32_t IntelCounters::GetPassCount()
|
||||
{
|
||||
return (uint32_t)m_subscribedMetricSets.size();
|
||||
}
|
||||
|
||||
uint32_t IntelCounters::BeginSession()
|
||||
{
|
||||
if(!m_metricsDevice)
|
||||
return 0;
|
||||
|
||||
m_passIndex = 0;
|
||||
TMetricsDeviceParams_1_2 *deviceParams = m_metricsDevice->GetParams();
|
||||
if(deviceParams->Version.MajorNumber < 1 ||
|
||||
(deviceParams->Version.MajorNumber == 1 && deviceParams->Version.MinorNumber < 2))
|
||||
return 0;
|
||||
|
||||
IOverride_1_2 *frequencyOverride = m_metricsDevice->GetOverrideByName("FrequencyOverride");
|
||||
if(!frequencyOverride)
|
||||
return 0;
|
||||
|
||||
TTypedValue_1_0 *maxFreqSymbol =
|
||||
m_metricsDevice->GetGlobalSymbolValueByName("GpuMaxFrequencyMHz");
|
||||
if(!maxFreqSymbol)
|
||||
return 0;
|
||||
|
||||
TSetFrequencyOverrideParams_1_2 params;
|
||||
params.Enable = true;
|
||||
params.FrequencyMhz = maxFreqSymbol->ValueUInt32;
|
||||
params.Pid = 0;
|
||||
frequencyOverride->SetOverride(¶ms, sizeof(params));
|
||||
Sleep(500);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void IntelCounters::EndSession()
|
||||
{
|
||||
if(!m_metricsDevice)
|
||||
return;
|
||||
|
||||
TMetricsDeviceParams_1_2 *deviceParams = m_metricsDevice->GetParams();
|
||||
if(deviceParams->Version.MajorNumber > 1 ||
|
||||
(deviceParams->Version.MajorNumber == 1 && deviceParams->Version.MinorNumber >= 2))
|
||||
{
|
||||
IOverride_1_2 *frequencyOverride = m_metricsDevice->GetOverrideByName("FrequencyOverride");
|
||||
|
||||
if(frequencyOverride)
|
||||
{
|
||||
TSetFrequencyOverrideParams_1_2 params;
|
||||
params.Enable = false;
|
||||
params.Pid = 0;
|
||||
frequencyOverride->SetOverride(¶ms, sizeof(params));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IntelCounters::BeginPass()
|
||||
{
|
||||
m_sampleIndex = 0;
|
||||
TMetricSetParams_1_0 *metricSetParams = m_subscribedMetricSets[m_passIndex]->GetParams();
|
||||
m_queryResult.resize(metricSetParams->MetricsCount + metricSetParams->InformationCount);
|
||||
}
|
||||
|
||||
void IntelCounters::EndPass()
|
||||
{
|
||||
m_passIndex++;
|
||||
}
|
||||
|
||||
void IntelCounters::EnableCounter(GPUCounter index)
|
||||
{
|
||||
uint32_t metricSetIdx = m_metricLocation[index].first;
|
||||
IMetricSet_1_1 *metricSet = m_allMetricSets[metricSetIdx];
|
||||
auto iter = std::find(m_subscribedMetricSets.begin(), m_subscribedMetricSets.end(), metricSet);
|
||||
if(iter == m_subscribedMetricSets.end())
|
||||
{
|
||||
m_subscribedMetricSets.push_back(metricSet);
|
||||
metricSetIdx = (uint32_t)m_subscribedMetricSets.size() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
metricSetIdx = (uint32_t)(iter - m_subscribedMetricSets.begin());
|
||||
}
|
||||
m_subscribedMetricsByCounterSet[metricSetIdx].push_back(index);
|
||||
}
|
||||
|
||||
void IntelCounters::DisableAllCounters()
|
||||
{
|
||||
m_subscribedMetricSets.clear();
|
||||
for(size_t i = 0; i < m_subscribedMetricsByCounterSet.size(); i++)
|
||||
m_subscribedMetricsByCounterSet[i].clear();
|
||||
}
|
||||
|
||||
void IntelCounters::BeginSample()
|
||||
{
|
||||
if(!m_metricsDevice)
|
||||
return;
|
||||
|
||||
D3D11_COUNTER_DESC counter_desc;
|
||||
counter_desc.MiscFlags = 0;
|
||||
counter_desc.Counter =
|
||||
(D3D11_COUNTER)m_subscribedMetricSets[m_passIndex]->GetParams()->ApiSpecificId.D3D1XDevDependentId;
|
||||
|
||||
if(counter_desc.Counter == 0)
|
||||
return;
|
||||
|
||||
TCompletionCode res = m_subscribedMetricSets[m_passIndex]->Activate();
|
||||
if(res != TCompletionCode::CC_OK)
|
||||
return;
|
||||
|
||||
HRESULT hr = m_device->CreateCounter(&counter_desc, &m_counter);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
m_subscribedMetricSets[m_passIndex]->Deactivate();
|
||||
return;
|
||||
}
|
||||
|
||||
res = m_subscribedMetricSets[m_passIndex]->Deactivate();
|
||||
if(res != TCompletionCode::CC_OK)
|
||||
return;
|
||||
|
||||
m_deviceContext->Begin(m_counter);
|
||||
}
|
||||
|
||||
void IntelCounters::EndSample()
|
||||
{
|
||||
if(!m_metricsDevice)
|
||||
return;
|
||||
|
||||
m_deviceContext->End(m_counter);
|
||||
HRESULT hr = S_OK;
|
||||
uint32_t iteration = 0;
|
||||
const uint32_t max_attempts = 0xFFFF;
|
||||
void *counter_data = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
uint32_t flags = (iteration == 0) ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH;
|
||||
hr = m_deviceContext->GetData(m_counter, &counter_data, m_counter->GetDataSize(), flags);
|
||||
iteration++;
|
||||
} while(hr != S_OK && iteration < max_attempts);
|
||||
m_counter->Release();
|
||||
|
||||
if(hr != S_OK)
|
||||
return;
|
||||
|
||||
IMetricSet_1_1 *metricSet = m_subscribedMetricSets[m_passIndex];
|
||||
TMetricSetParams_1_0 *metricSetParams = metricSet->GetParams();
|
||||
|
||||
uint32_t calculatedReportCount = 0;
|
||||
TCompletionCode res = m_subscribedMetricSets[m_passIndex]->CalculateMetrics(
|
||||
(const unsigned char *)counter_data, metricSetParams->QueryReportSize, m_queryResult.data(),
|
||||
(uint32_t)m_queryResult.size() * sizeof(TTypedValue_1_0), &calculatedReportCount, false);
|
||||
|
||||
if(res != TCompletionCode::CC_OK)
|
||||
return;
|
||||
|
||||
for(size_t i = 0; i < m_subscribedMetricsByCounterSet[m_passIndex].size(); i++)
|
||||
{
|
||||
GPUCounter counterId = m_subscribedMetricsByCounterSet[m_passIndex][i];
|
||||
uint32_t counterIndex = m_metricLocation[counterId].second;
|
||||
|
||||
m_results[std::pair<GPUCounter, uint32_t>(counterId, m_sampleIndex)] =
|
||||
m_queryResult[counterIndex];
|
||||
}
|
||||
m_sampleIndex++;
|
||||
}
|
||||
|
||||
std::vector<CounterResult> IntelCounters::GetCounterData(const std::vector<uint32_t> &eventIDs,
|
||||
const std::vector<GPUCounter> &counters)
|
||||
{
|
||||
std::vector<CounterResult> ret;
|
||||
for(uint32_t sample = 0; sample < (uint32_t)eventIDs.size(); sample++)
|
||||
{
|
||||
for(size_t counter = 0; counter < counters.size(); counter++)
|
||||
{
|
||||
const CounterDescription desc = GetCounterDescription(counters[counter]);
|
||||
|
||||
switch(desc.resultType)
|
||||
{
|
||||
case CompType::UInt:
|
||||
{
|
||||
if(desc.resultByteWidth == sizeof(uint32_t))
|
||||
{
|
||||
uint32_t value =
|
||||
m_results[std::pair<GPUCounter, uint32_t>(desc.counter, sample)].ValueUInt32;
|
||||
if(desc.unit == CounterUnit::Percentage)
|
||||
{
|
||||
value = RDCCLAMP(value, 0U, 100U);
|
||||
}
|
||||
|
||||
ret.push_back(CounterResult(eventIDs[sample], counters[counter], value));
|
||||
}
|
||||
else if(desc.resultByteWidth == sizeof(uint64_t))
|
||||
{
|
||||
uint64_t value =
|
||||
m_results[std::pair<GPUCounter, uint32_t>(desc.counter, sample)].ValueUInt64;
|
||||
|
||||
if(desc.unit == CounterUnit::Percentage)
|
||||
{
|
||||
value = RDCCLAMP(value, 0ULL, 100ULL);
|
||||
}
|
||||
|
||||
ret.push_back(CounterResult(eventIDs[sample], counters[counter], value));
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Unexpected byte width %u", desc.resultByteWidth);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CompType::Float:
|
||||
{
|
||||
float value = m_results[std::pair<GPUCounter, uint32_t>(desc.counter, sample)].ValueFloat;
|
||||
if(desc.unit == CounterUnit::Seconds)
|
||||
{
|
||||
float nanoseconds =
|
||||
(float)m_results[std::pair<GPUCounter, uint32_t>(desc.counter, sample)].ValueUInt64;
|
||||
value = nanoseconds / 1e9f;
|
||||
}
|
||||
|
||||
if(fabs(value) < 1e-9)
|
||||
{
|
||||
value = 0.0f;
|
||||
}
|
||||
|
||||
if(desc.unit == CounterUnit::Percentage)
|
||||
{
|
||||
value = RDCCLAMP(value, 0.0f, 100.0f);
|
||||
}
|
||||
|
||||
ret.push_back(CounterResult(eventIDs[sample], counters[counter], value));
|
||||
}
|
||||
break;
|
||||
default: RDCASSERT(0); break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 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.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <windows.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "api/replay/renderdoc_replay.h"
|
||||
#include "official/metrics_discovery_api.h"
|
||||
|
||||
using namespace MetricsDiscovery;
|
||||
|
||||
inline constexpr GPUCounter MakeIntelCounter(int index)
|
||||
{
|
||||
return GPUCounter((int)GPUCounter::FirstIntel + index);
|
||||
}
|
||||
|
||||
class IntelCounters
|
||||
{
|
||||
public:
|
||||
IntelCounters();
|
||||
|
||||
static void Load();
|
||||
|
||||
bool Init(void *pDevice);
|
||||
~IntelCounters();
|
||||
|
||||
std::vector<GPUCounter> GetPublicCounterIds() const { return m_counterIds; }
|
||||
CounterDescription GetCounterDescription(GPUCounter index);
|
||||
|
||||
void EnableCounter(GPUCounter index);
|
||||
void DisableAllCounters();
|
||||
|
||||
uint32_t GetPassCount();
|
||||
|
||||
uint32_t BeginSession();
|
||||
void EndSession();
|
||||
|
||||
void BeginPass();
|
||||
void EndPass();
|
||||
|
||||
void BeginSample();
|
||||
void EndSample();
|
||||
|
||||
std::vector<CounterResult> GetCounterData(const std::vector<uint32_t> &eventIDs,
|
||||
const std::vector<GPUCounter> &counters);
|
||||
|
||||
private:
|
||||
static uint32_t GPUCounterToCounterIndex(GPUCounter counter)
|
||||
{
|
||||
return (uint32_t)(counter) - (uint32_t)(GPUCounter::FirstIntel);
|
||||
}
|
||||
|
||||
std::vector<CounterDescription> EnumerateCounters();
|
||||
std::vector<GPUCounter> m_counterIds;
|
||||
std::vector<CounterDescription> m_Counters;
|
||||
std::vector<IMetricSet_1_1 *> m_allMetricSets;
|
||||
std::vector<IMetricSet_1_1 *> m_subscribedMetricSets;
|
||||
std::map<GPUCounter, std::pair<uint32_t, uint32_t>> m_metricLocation;
|
||||
std::vector<std::vector<GPUCounter>> m_subscribedMetricsByCounterSet;
|
||||
ID3D11Device *m_device;
|
||||
ID3D11DeviceContext *m_deviceContext;
|
||||
ID3D11Counter *m_counter;
|
||||
std::vector<TTypedValue_1_0> m_queryResult;
|
||||
uint32_t m_passIndex;
|
||||
uint32_t m_sampleIndex;
|
||||
std::map<std::pair<GPUCounter, uint32_t>, TTypedValue_1_0> m_results;
|
||||
|
||||
static HMODULE m_MDLibraryHandle;
|
||||
static IMetricsDevice_1_5 *m_metricsDevice;
|
||||
static OpenMetricsDevice_fn OpenMetricsDevice;
|
||||
static CloseMetricsDevice_fn CloseMetricsDevice;
|
||||
};
|
||||
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <initguid.h>
|
||||
#include <ntddvdeo.h>
|
||||
#include <Devpkey.h>
|
||||
#include <SetupAPI.h>
|
||||
#include <Shlwapi.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#if DEBUG
|
||||
#define DBG(std, fmt, ...) fprintf_s(stderr, fmt, __VA_ARGS__)
|
||||
#else
|
||||
#define DBG(std, fmt, ...)
|
||||
#endif
|
||||
|
||||
/********************************************************************************************/
|
||||
/* GetPropertyFromDevice */
|
||||
/* */
|
||||
/* This function can be used to request a value of any device property. */
|
||||
/* There are many types of properties values. Refer to devpkey.h for more details. */
|
||||
/* Function SetupDiGetDeviceProperty() inside GetPropertyFromDevice() fills a property value*/
|
||||
/* in a correct format, but always returns the value as a pointer to a string of bytes. */
|
||||
/* The string of bytes must be casted outside of the function GetPropertyFromDevice() */
|
||||
/* to get a value in a format suitable for the given type of property. */
|
||||
/* */
|
||||
/********************************************************************************************/
|
||||
static bool GetPropertyFromDevice(
|
||||
void* pDevInfo,
|
||||
PSP_DEVINFO_DATA pDevInfoData,
|
||||
const DEVPROPKEY* pPropertyKey,
|
||||
unsigned char** ppStringOut,
|
||||
unsigned long* pStringOutSize)
|
||||
{
|
||||
unsigned long propertyType = 0;
|
||||
unsigned long propertySize = 0;
|
||||
|
||||
// request a size, in bytes, required for a buffer in which property value will be stored
|
||||
// SetupDiGetDeviceProperty() returns false and ERROR_INSUFFICIENT_BUFFER for the call
|
||||
if (SetupDiGetDevicePropertyW(pDevInfo, pDevInfoData, pPropertyKey, &propertyType, NULL, 0, &propertySize, 0))
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> SetupDiGetDeviceProperty() failed with the error code 0x%02x\n", __FUNCTION__, __LINE__, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> SetupDiGetDeviceProperty() failed with the error code 0x%02x\n", __FUNCTION__, __LINE__, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ppStringOut == NULL)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
DBG(stderr, "%s [%d] ---> Error: input parameter ppStringOut = NULL\n", __FUNCTION__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// allocate memory for the buffer
|
||||
*ppStringOut = new (std::nothrow) unsigned char[propertySize];
|
||||
if (*ppStringOut == NULL)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
DBG(stderr, "%s [%d] ---> Error: *ppStringOut = NULL\n", __FUNCTION__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// fill in the buffer with property value
|
||||
if (!SetupDiGetDevicePropertyW(pDevInfo, pDevInfoData, pPropertyKey, &propertyType, *ppStringOut, propertySize, NULL, 0))
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> SetupDiGetDeviceProperty() failed with the error code 0x%02x\n", __FUNCTION__, __LINE__, GetLastError());
|
||||
delete[] *ppStringOut;
|
||||
*ppStringOut = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pStringOutSize)
|
||||
{
|
||||
*pStringOutSize = propertySize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* GetIntelDriverStoreFullPath */
|
||||
/************************************************************************/
|
||||
static bool GetIntelDriverStoreFullPath(
|
||||
wchar_t* pDriverStorePath,
|
||||
unsigned long driverStorePathSizeInCharacters,
|
||||
unsigned long* pDriverStorePathLengthInCharacters)
|
||||
{
|
||||
bool result = false;
|
||||
// allocated memory must be freed with delete operation
|
||||
unsigned char* pPropertyInfName = NULL;
|
||||
// allocated memory must be freed with delete operation
|
||||
unsigned char* pPropertyDevServiceName = NULL;
|
||||
|
||||
// guid defined for display adapters
|
||||
const GUID guid = GUID_DISPLAY_DEVICE_ARRIVAL;
|
||||
|
||||
// create device information set containing display adapters which support interfaces and are currently present in the system
|
||||
void* pDevInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
|
||||
if (pDevInfo == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> SetupDiGetClassDevs() failed with the error code 0x%02x, pDevInfo = INVALID_HANDLE_VALUE\n", __FUNCTION__, __LINE__, GetLastError());
|
||||
goto END;
|
||||
}
|
||||
|
||||
unsigned long deviceIndex = 0;
|
||||
SP_DEVINFO_DATA devInfoData;
|
||||
ZeroMemory(&devInfoData, sizeof(SP_DEVINFO_DATA));
|
||||
unsigned long interfaceIndex = 0;
|
||||
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
|
||||
ZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
|
||||
DEVPROPKEY devPropKey;
|
||||
ZeroMemory(&devPropKey, sizeof(DEVPROPKEY));
|
||||
unsigned long driverStorePathLengthInCharacters = 0;
|
||||
|
||||
// enumerate display adapters
|
||||
while (true)
|
||||
{
|
||||
ZeroMemory(&devInfoData, sizeof(SP_DEVINFO_DATA));
|
||||
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
|
||||
if (!SetupDiEnumDeviceInfo(pDevInfo, deviceIndex, &devInfoData))
|
||||
{
|
||||
if (GetLastError() != ERROR_NO_MORE_ITEMS)
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> SetupDiEnumDeviceInfo() failed with the error code 0x%02x\n", __FUNCTION__, __LINE__, GetLastError());
|
||||
}
|
||||
|
||||
deviceIndex = 0;
|
||||
goto END;
|
||||
}
|
||||
|
||||
// enumerate interfaces of display adapters
|
||||
while (true)
|
||||
{
|
||||
ZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
|
||||
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||
|
||||
if (!SetupDiEnumDeviceInterfaces(pDevInfo, &devInfoData, &guid, interfaceIndex, &deviceInterfaceData))
|
||||
{
|
||||
if (GetLastError() == ERROR_NO_MORE_ITEMS)
|
||||
{
|
||||
interfaceIndex = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> SetupDiEnumDeviceInterfaces() failed with the error code 0x%02x\n", __FUNCTION__, __LINE__, GetLastError());
|
||||
interfaceIndex = 0;
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
|
||||
// get an inf file name for a display adapter
|
||||
if (GetPropertyFromDevice(pDevInfo, &devInfoData, &DEVPKEY_Device_DriverInfPath, &pPropertyInfName, NULL) == false)
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> GetPropertyFromDevice() failed with the error code 0x%02x\n", __FUNCTION__, __LINE__, GetLastError());
|
||||
goto END;
|
||||
}
|
||||
|
||||
// to read DEVPKEY_Device_DriverInfPath property value correctly just cast unsigned char* (means PBYTE) to const wchar_t*
|
||||
const wchar_t* pInfName = reinterpret_cast<const wchar_t*>(pPropertyInfName);
|
||||
DBG(stdout, "\n");
|
||||
DBG(stdout, "pPropertyInfName = %ws\n", pInfName);
|
||||
wchar_t driverStorePath[MAX_PATH];
|
||||
ZeroMemory(driverStorePath, sizeof(driverStorePath));
|
||||
|
||||
// get a fully qualified name of an inf file (directory path and file name)
|
||||
if (!SetupGetInfDriverStoreLocationW(pInfName, NULL, NULL, driverStorePath, ARRAYSIZE(driverStorePath), NULL))
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> SetupGetInfDriverStoreLocation() failed with the error code 0x%02x\n", __FUNCTION__, __LINE__, GetLastError());
|
||||
goto END;
|
||||
}
|
||||
|
||||
// remove backslash and file name from the fully qualified name
|
||||
PathRemoveFileSpecW(driverStorePath);
|
||||
DBG(stdout, "driverStorePath = %ws\n", driverStorePath);
|
||||
driverStorePathLengthInCharacters = (unsigned long)wcsnlen_s(driverStorePath, ARRAYSIZE(driverStorePath));
|
||||
DBG(stdout, "driverStorePathLengthInCharacters = %d\n", driverStorePathLengthInCharacters);
|
||||
|
||||
// get service name for a display adapter
|
||||
if (GetPropertyFromDevice(pDevInfo, &devInfoData, &DEVPKEY_Device_Service, &pPropertyDevServiceName, NULL) == false)
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> GetPropertyFromDevice() failed with the error code 0x%02x\n", __FUNCTION__, __LINE__, GetLastError());
|
||||
goto END;
|
||||
}
|
||||
|
||||
// to read DEVPKEY_Device_Service property value correctly just cast unsigned char* (means PBYTE) to const wchar_t*
|
||||
const wchar_t* pDevServiceName = reinterpret_cast<const wchar_t*>(pPropertyDevServiceName);
|
||||
DBG(stdout, "pDevServiceName = %ws\n", pDevServiceName);
|
||||
|
||||
// check if a given display adapter is from Intel based on driver device service name "igfx"
|
||||
// check if pDevServiceName contains "igfx" name
|
||||
if (wcsstr(pDevServiceName, L"igfx"))
|
||||
{
|
||||
// display adapter is from Intel
|
||||
DBG(stdout, "this display adapter is from Intel\n");
|
||||
|
||||
if (pDriverStorePath == NULL)
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> Error: input parameter pDriverStorePath = NULL\n", __FUNCTION__, __LINE__);
|
||||
goto END;
|
||||
}
|
||||
|
||||
if (driverStorePathSizeInCharacters < driverStorePathLengthInCharacters + 1)
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> Error: input parameter driverStorePathSizeInCharacters = %d is too small, the required size is %d\n", __FUNCTION__, __LINE__, driverStorePathSizeInCharacters, driverStorePathLengthInCharacters + 1);
|
||||
goto END;
|
||||
}
|
||||
|
||||
wcscpy_s(pDriverStorePath, driverStorePathSizeInCharacters, driverStorePath);
|
||||
|
||||
if (pDriverStorePathLengthInCharacters)
|
||||
{
|
||||
*pDriverStorePathLengthInCharacters = driverStorePathLengthInCharacters;
|
||||
}
|
||||
|
||||
result = (driverStorePathLengthInCharacters > 0) ? true : false;
|
||||
if (result == false)
|
||||
{
|
||||
SetLastError(ERROR_BAD_LENGTH);
|
||||
DBG(stderr, "%s [%d] ---> Error: driverStorePathLengthInCharacters = 0, result = false\n", __FUNCTION__, __LINE__);
|
||||
}
|
||||
goto END;
|
||||
}
|
||||
else
|
||||
{
|
||||
// display adapter is from other vendor
|
||||
DBG(stdout, "this display adapter is NOT from Intel\n");
|
||||
|
||||
if (pPropertyDevServiceName)
|
||||
{
|
||||
delete[] pPropertyDevServiceName;
|
||||
pPropertyDevServiceName = NULL;
|
||||
}
|
||||
|
||||
if (pPropertyInfName)
|
||||
{
|
||||
delete[] pPropertyInfName;
|
||||
pPropertyInfName = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
++interfaceIndex;
|
||||
}
|
||||
|
||||
++deviceIndex;
|
||||
}
|
||||
|
||||
END:
|
||||
DBG(stdout, "\n");
|
||||
|
||||
if (pPropertyDevServiceName)
|
||||
{
|
||||
delete[] pPropertyDevServiceName;
|
||||
pPropertyDevServiceName = NULL;
|
||||
}
|
||||
|
||||
if (pPropertyInfName)
|
||||
{
|
||||
delete[] pPropertyInfName;
|
||||
pPropertyInfName = NULL;
|
||||
}
|
||||
|
||||
if (pDevInfo)
|
||||
{
|
||||
SetupDiDestroyDeviceInfoList(pDevInfo);
|
||||
pDevInfo = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* LoadDynamicLibrary */
|
||||
/************************************************************************/
|
||||
static HMODULE LoadDynamicLibrary(const wchar_t* pFileName, HANDLE hFile = NULL, unsigned long flags = 0)
|
||||
{
|
||||
HMODULE hModule = NULL;
|
||||
unsigned long driverStorePathLengthInCharacters = 0;
|
||||
// contains fully qualified name of DriverStore (directory path only without backslash at the end) for Intel display driver
|
||||
// for example: C:\Windows\System32\DriverStore\FileRepository\igdlh64.inf_amd64_1d1d318ad2d391db
|
||||
wchar_t driverStorePath[MAX_PATH] = { 0 };
|
||||
|
||||
// find fully qualified name of DriverStore for Intel graphics driver
|
||||
if (GetIntelDriverStoreFullPath(driverStorePath, ARRAYSIZE(driverStorePath), &driverStorePathLengthInCharacters) == true)
|
||||
{
|
||||
std::wstring driverStoreFullPath(driverStorePath);
|
||||
|
||||
if (driverStorePathLengthInCharacters)
|
||||
{
|
||||
driverStoreFullPath += L"\\";
|
||||
driverStoreFullPath += pFileName;
|
||||
}
|
||||
|
||||
DBG(stdout, "full path: %ws\n\n", driverStoreFullPath.c_str());
|
||||
|
||||
// load dll from DriverStore full path
|
||||
hModule = LoadLibraryExW(driverStoreFullPath.c_str(), NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG(stderr, "%s [%d] ---> GetIntelDriverStoreFullPath() failed\n", __FUNCTION__, __LINE__);
|
||||
hModule = NULL;
|
||||
}
|
||||
|
||||
return hModule;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -78,7 +78,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalDependencies>tdh.lib;ws2_32.lib;kernel32.lib;user32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>tdh.lib;ws2_32.lib;kernel32.lib;user32.lib;shlwapi.lib;setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(ProjectDir)os\win32\comexport.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<DelayLoadDLLs>tdh.dll</DelayLoadDLLs>
|
||||
@@ -585,6 +585,9 @@
|
||||
<ProjectReference Include="driver\ihv\amd\AMD.vcxproj">
|
||||
<Project>{5de5a561-548a-4dd7-90f0-06a2b39eae9a}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="driver\ihv\intel\Intel.vcxproj">
|
||||
<Project>{7fcb5fc5-1dbd-4da6-83a0-6ba4e945bda5}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="driver\ihv\nv\NV.vcxproj">
|
||||
<Project>{40349ad9-5558-4df4-84e2-11934de90a11}</Project>
|
||||
</ProjectReference>
|
||||
|
||||
Reference in New Issue
Block a user