diff --git a/.gitignore b/.gitignore
index 85e332d4..d64c929c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,5 +41,3 @@ PresentData/PresentData.args.json
IntelPresentMon/SampleClient/log.txt
IntelPresentMon/PresentMonAPI2/Internal.h
-
-IntelPresentMon/CommonUtilities/git_hash.h
diff --git a/IntelPresentMon/AppCef/AppCef.rc b/IntelPresentMon/AppCef/AppCef.rc
index b7457c74..405860fc 100644
--- a/IntelPresentMon/AppCef/AppCef.rc
+++ b/IntelPresentMon/AppCef/AppCef.rc
@@ -61,8 +61,8 @@ IDI_ICON1 ICON "flask.ico"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,0
- PRODUCTVERSION 2,1,0,0
+ FILEVERSION 1,0,3,0
+ PRODUCTVERSION 2,3,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -79,12 +79,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Intel(R) Corporation"
VALUE "FileDescription", "Intel(R) PresentMon application"
- VALUE "FileVersion", "1.0.0.0"
+ VALUE "FileVersion", "1.0.3.0"
VALUE "InternalName", "CefNano.exe"
VALUE "LegalCopyright", "Copyright (C) 2017-2024"
VALUE "OriginalFilename", "CefNano.exe"
VALUE "ProductName", "Intel(R) PresentMon"
- VALUE "ProductVersion", "2.1.0.0"
+ VALUE "ProductVersion", "2.3.0.0"
END
END
BLOCK "VarFileInfo"
diff --git a/IntelPresentMon/AppCef/CefNano.vcxproj b/IntelPresentMon/AppCef/CefNano.vcxproj
index ce6a0b4e..e1b2f62b 100644
--- a/IntelPresentMon/AppCef/CefNano.vcxproj
+++ b/IntelPresentMon/AppCef/CefNano.vcxproj
@@ -83,6 +83,9 @@
{808f5ea9-ea09-4d72-87b4-5397d43cba54}
+
+ {c73aa532-e532-4d93-9279-905444653c08}
+
diff --git a/IntelPresentMon/AppCef/source/util/PathSanitaryCheck.cpp b/IntelPresentMon/AppCef/source/util/PathSanitaryCheck.cpp
index de1b23bc..eaa6f3db 100644
--- a/IntelPresentMon/AppCef/source/util/PathSanitaryCheck.cpp
+++ b/IntelPresentMon/AppCef/source/util/PathSanitaryCheck.cpp
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
namespace p2c::client::util
@@ -43,8 +44,9 @@ namespace p2c::client::util
}
bool PathSanitaryCheck(const std::filesystem::path& path, const std::filesystem::path& root)
{
- const auto canonicalString = std::filesystem::weakly_canonical(path).wstring();
- const auto rootString = root.wstring();
- return canonicalString.starts_with(rootString);
+ const auto canonicalString = pmon::util::str::ToLower(std::filesystem::weakly_canonical(path).wstring());
+ const auto rootString = pmon::util::str::ToLower(root.wstring());
+ const auto isSanitary = canonicalString.starts_with(rootString);
+ return isSanitary;
}
}
\ No newline at end of file
diff --git a/IntelPresentMon/AppCef/source/util/async/Introspect.h b/IntelPresentMon/AppCef/source/util/async/Introspect.h
index eaec485b..234a9501 100644
--- a/IntelPresentMon/AppCef/source/util/async/Introspect.h
+++ b/IntelPresentMon/AppCef/source/util/async/Introspect.h
@@ -34,8 +34,7 @@ namespace p2c::client::util::async
// filter predicate to only pick up metrics usable in dynamic queries (plus hardcoded blacklist)
const auto filterPred = [](const pmapi::intro::MetricView& m) { const auto type = m.GetType();
return
- ( m.GetId() != PM_METRIC_GPU_LATENCY &&
- m.GetId() != PM_METRIC_DISPLAY_LATENCY)
+ ( m.GetId() != PM_METRIC_GPU_LATENCY)
&&
( type == PM_METRIC_TYPE_DYNAMIC ||
type == PM_METRIC_TYPE_DYNAMIC_FRAME ||
diff --git a/IntelPresentMon/AppCef/source/winmain.cpp b/IntelPresentMon/AppCef/source/winmain.cpp
index d55d7753..4948adf8 100644
--- a/IntelPresentMon/AppCef/source/winmain.cpp
+++ b/IntelPresentMon/AppCef/source/winmain.cpp
@@ -8,7 +8,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -22,6 +22,7 @@
using namespace p2c;
using namespace pmon::util;
+using namespace pmon::bid;
using p2c::cli::Options;
namespace ccef = client::cef;
using namespace std::chrono_literals;
diff --git a/IntelPresentMon/CommonUtilities/CommonUtilities.vcxproj b/IntelPresentMon/CommonUtilities/CommonUtilities.vcxproj
index bad6a5ce..28b28f3c 100644
--- a/IntelPresentMon/CommonUtilities/CommonUtilities.vcxproj
+++ b/IntelPresentMon/CommonUtilities/CommonUtilities.vcxproj
@@ -19,7 +19,6 @@
-
@@ -92,7 +91,6 @@
-
@@ -137,8 +135,6 @@
-
-
@@ -271,10 +267,7 @@
true
-
- build-scripts\pre-build.bat
- Generating build ID
-
+
@@ -304,10 +297,7 @@
true
true
-
- build-scripts\pre-build.bat
- Generating build ID
-
+
diff --git a/IntelPresentMon/CommonUtilities/CommonUtilities.vcxproj.filters b/IntelPresentMon/CommonUtilities/CommonUtilities.vcxproj.filters
index 5435184d..0bb38fe6 100644
--- a/IntelPresentMon/CommonUtilities/CommonUtilities.vcxproj.filters
+++ b/IntelPresentMon/CommonUtilities/CommonUtilities.vcxproj.filters
@@ -204,9 +204,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -347,9 +344,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -362,9 +356,5 @@
-
- Source Files
-
-
\ No newline at end of file
diff --git a/IntelPresentMon/CommonUtilities/Math.h b/IntelPresentMon/CommonUtilities/Math.h
index f57bced6..4f5a4271 100644
--- a/IntelPresentMon/CommonUtilities/Math.h
+++ b/IntelPresentMon/CommonUtilities/Math.h
@@ -21,4 +21,36 @@ namespace pmon::util
{
return (a - b) < CommonEpsilon(a, b);
}
+ enum class MagnitudePrefix
+ {
+ Base,
+ Kilo,
+ Kibi,
+ Mega,
+ Mebi,
+ Giga,
+ Gibi,
+ };
+ constexpr double GetMagnitudeFactor(MagnitudePrefix prefix)
+ {
+ switch (prefix) {
+ case MagnitudePrefix::Base: return 1.;
+ case MagnitudePrefix::Kilo: return 1'000.;
+ case MagnitudePrefix::Kibi: return 1'024.;
+ case MagnitudePrefix::Mega: return 1'000'000.;
+ case MagnitudePrefix::Mebi: return 1'048'576.;
+ case MagnitudePrefix::Giga: return 1'000'000'000.;
+ case MagnitudePrefix::Gibi: return 1'073'741'824.;
+ default: return 0.;
+ }
+ }
+ template
+ To ConvertMagnitudePrefix(From from, MagnitudePrefix fromPrefix, MagnitudePrefix toPrefix)
+ {
+ auto fromExtended = double(from);
+ const auto srcFactor = GetMagnitudeFactor(fromPrefix);
+ const auto dstFactor = GetMagnitudeFactor(toPrefix);
+ const auto conversionFactor = srcFactor / dstFactor;
+ return To(fromExtended * conversionFactor);
+ }
}
\ No newline at end of file
diff --git a/IntelPresentMon/ControlLib/ControlLib.vcxproj b/IntelPresentMon/ControlLib/ControlLib.vcxproj
index 67c061a2..8a1da172 100644
--- a/IntelPresentMon/ControlLib/ControlLib.vcxproj
+++ b/IntelPresentMon/ControlLib/ControlLib.vcxproj
@@ -200,11 +200,13 @@
+
+
@@ -227,6 +229,7 @@
+
diff --git a/IntelPresentMon/ControlLib/ControlLib.vcxproj.filters b/IntelPresentMon/ControlLib/ControlLib.vcxproj.filters
index 35e7b929..bd868610 100644
--- a/IntelPresentMon/ControlLib/ControlLib.vcxproj.filters
+++ b/IntelPresentMon/ControlLib/ControlLib.vcxproj.filters
@@ -76,6 +76,10 @@
+
+ Intel
+
+
@@ -116,5 +120,8 @@
+
+ Intel
+
\ No newline at end of file
diff --git a/IntelPresentMon/ControlLib/IntelPowerTelemetryAdapter.cpp b/IntelPresentMon/ControlLib/IntelPowerTelemetryAdapter.cpp
index 4a271048..a8a76c21 100644
--- a/IntelPresentMon/ControlLib/IntelPowerTelemetryAdapter.cpp
+++ b/IntelPresentMon/ControlLib/IntelPowerTelemetryAdapter.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: MIT
#include "IntelPowerTelemetryAdapter.h"
#include "Logging.h"
+#include "../CommonUtilities/Math.h"
namespace pwr::intel
{
@@ -18,8 +19,7 @@ namespace pwr::intel
};
if (auto result = ctlGetDeviceProperties(deviceHandle, &properties);
- result != CTL_RESULT_SUCCESS)
- {
+ result != CTL_RESULT_SUCCESS) {
throw std::runtime_error{ "Failure to get device properties" };
}
@@ -34,17 +34,51 @@ namespace pwr::intel
bool IntelPowerTelemetryAdapter::Sample() noexcept
{
+ pmlog_verb(v::gpu)("Sample called");
+
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
bool success = true;
- ctl_power_telemetry_t currentSample{};
- currentSample.Size = sizeof(ctl_power_telemetry_t);
- if (const auto result = ctlPowerTelemetryGet(deviceHandle,
- ¤tSample); result != CTL_RESULT_SUCCESS)
- {
- success = false;
- IGCL_ERR(result);
+ decltype(previousSampleVariant) currentSampleVariant;
+
+ if (useV1PowerTelemetry) {
+ currentSampleVariant = ctl_power_telemetry2_t{
+ .Size = sizeof(ctl_power_telemetry2_t),
+ .Version = 1
+ };
+ auto currentSample = std::get_if(¤tSampleVariant);
+ // sanity check; should never fail
+ if (!currentSample) {
+ success = false;
+ IGCL_ERR(CTL_RESULT_ERROR_INVALID_ARGUMENT);
+ }
+ if (const auto result = ctlPowerTelemetryGet(deviceHandle,
+ (ctl_power_telemetry_t*)currentSample); result != CTL_RESULT_SUCCESS) {
+ // treating any error as unavailability of the API version since some driver version do not correctly report
+ // version error
+ useV1PowerTelemetry = false;
+ useNewBandwidthTelemetry = false;
+ success = false;
+ pmlog_warn("Failed to access ctlPowerTelemetryGet.v1, falling back to .v0");
+ }
+ }
+ if (!useV1PowerTelemetry) {
+ currentSampleVariant = ctl_power_telemetry_t{
+ .Size = sizeof(ctl_power_telemetry_t),
+ .Version = 0
+ };
+ auto currentSample = std::get_if(¤tSampleVariant);
+ // sanity check; should never fail
+ if (!currentSample) {
+ success = false;
+ IGCL_ERR(CTL_RESULT_ERROR_INVALID_ARGUMENT);
+ }
+ if (const auto result = ctlPowerTelemetryGet(deviceHandle, currentSample);
+ result != CTL_RESULT_SUCCESS) {
+ success = false;
+ IGCL_ERR(result);
+ }
}
// Query memory state and bandwidth if supported
@@ -54,92 +88,49 @@ namespace pwr::intel
.Version = 1,
};
if (memoryModules.size() > 0) {
- if (const auto result =
- ctlMemoryGetState(memoryModules[0], &memory_state);
+ if (const auto result = ctlMemoryGetState(memoryModules[0], &memory_state);
result != CTL_RESULT_SUCCESS) {
success = false;
IGCL_ERR(result);
}
- if (const auto result =
- ctlMemoryGetBandwidth(memoryModules[0], &memory_bandwidth);
+ if (const auto result = ctlMemoryGetBandwidth(memoryModules[0], &memory_bandwidth);
result != CTL_RESULT_SUCCESS) {
success = false;
IGCL_ERR(result);
}
}
-
- if (const auto result = GetTimeDelta(currentSample);
- result != CTL_RESULT_SUCCESS)
- {
- success = false;
- IGCL_ERR(result);
- }
double gpu_sustained_power_limit_mw = 0.;
if (const auto result = ctlOverclockPowerLimitGet(
- deviceHandle, &gpu_sustained_power_limit_mw);
- result != CTL_RESULT_SUCCESS) {
+ deviceHandle, &gpu_sustained_power_limit_mw);
+ result != CTL_RESULT_SUCCESS && result != CTL_RESULT_ERROR_CORE_OVERCLOCK_DEPRECATED_API) {
success = false;
IGCL_ERR(result);
}
- PresentMonPowerTelemetryInfo pm_gpu_power_telemetry_info{ .qpc = (uint64_t)qpc.QuadPart };
-
- if (previousSample) {
-
- if (const auto result = GetGPUPowerTelemetryData(
- currentSample, pm_gpu_power_telemetry_info); result != CTL_RESULT_SUCCESS)
- {
- success = false;
- IGCL_ERR(result);
- }
-
- if (const auto result = GetVramPowerTelemetryData(
- currentSample, pm_gpu_power_telemetry_info); result != CTL_RESULT_SUCCESS)
- {
+ if (useV1PowerTelemetry) {
+ auto currentSample = std::get_if(¤tSampleVariant);
+ // sanity check; should never fail
+ if (!currentSample) {
success = false;
- IGCL_ERR(result);
+ IGCL_ERR(CTL_RESULT_ERROR_INVALID_ARGUMENT);
}
-
- if (const auto result = GetFanPowerTelemetryData(currentSample,
- pm_gpu_power_telemetry_info); result != CTL_RESULT_SUCCESS)
- {
- success = false;
- IGCL_ERR(result);
+ else {
+ success = GatherSampleData(*currentSample, memory_state,
+ memory_bandwidth, gpu_sustained_power_limit_mw, (uint64_t)qpc.QuadPart) && success;
}
-
- if (const auto result = GetPsuPowerTelemetryData(
- currentSample, pm_gpu_power_telemetry_info); result != CTL_RESULT_SUCCESS)
- {
+ }
+ else {
+ auto currentSample = std::get_if(¤tSampleVariant);
+ // sanity check; should never fail
+ if (!currentSample) {
success = false;
- IGCL_ERR(result);
+ IGCL_ERR(CTL_RESULT_ERROR_INVALID_ARGUMENT);
}
-
- // Get memory state and bandwidth data
- if (memoryModules.size() > 0) {
- GetMemStateTelemetryData(memory_state,
- pm_gpu_power_telemetry_info);
- GetMemBandwidthData(memory_bandwidth,
- pm_gpu_power_telemetry_info);
+ else {
+ success = GatherSampleData(*currentSample, memory_state,
+ memory_bandwidth, gpu_sustained_power_limit_mw, (uint64_t)qpc.QuadPart) && success;
}
-
- // Save and convert the gpu sustained power limit
- pm_gpu_power_telemetry_info.gpu_sustained_power_limit_w =
- gpu_sustained_power_limit_mw / 1000.;
- SetTelemetryCapBit(GpuTelemetryCapBits::gpu_sustained_power_limit);
-
- // Save off the calculated PresentMon power telemetry values. These are
- // saved off for clients to extrace out timing information based on QPC
- SavePmPowerTelemetryData(pm_gpu_power_telemetry_info);
- }
-
- // Save off the raw control library data for calculating time delta
- // and usage data.
- if (const auto result = SaveTelemetry(currentSample, memory_bandwidth);
- result != CTL_RESULT_SUCCESS)
- {
- success = false;
- IGCL_ERR(result);
}
return success;
@@ -148,7 +139,18 @@ namespace pwr::intel
std::optional IntelPowerTelemetryAdapter::GetClosest(uint64_t qpc) const noexcept
{
std::lock_guard lock(historyMutex);
- return history.GetNearest(qpc);
+ const auto nearest = history.GetNearest(qpc);
+ if constexpr (PMLOG_BUILD_LEVEL_ >= pmon::util::log::Level::Verbose) {
+ if (!nearest) {
+ pmlog_verb(v::gpu)("Empty telemetry info sample returned");
+ }
+ else {
+ pmlog_verb(v::gpu)(std::format("Nearest telemetry info sampled; read bw [{}] write bw [{}]",
+ nearest->gpu_mem_read_bandwidth_bps, nearest->gpu_mem_write_bandwidth_bps
+ ));
+ }
+ }
+ return nearest;
}
PM_DEVICE_VENDOR IntelPowerTelemetryAdapter::GetVendor() const noexcept
@@ -232,17 +234,97 @@ namespace pwr::intel
return CTL_RESULT_SUCCESS;
}
+ template
+ bool IntelPowerTelemetryAdapter::GatherSampleData(T& currentSample,
+ ctl_mem_state_t& memory_state,
+ ctl_mem_bandwidth_t& memory_bandwidth,
+ double gpu_sustained_power_limit_mw,
+ uint64_t qpc)
+ {
+ bool success = true;
+
+ if (const auto result = GetTimeDelta(currentSample);
+ result != CTL_RESULT_SUCCESS)
+ {
+ success = false;
+ IGCL_ERR(result);
+ }
+
+ PresentMonPowerTelemetryInfo pm_gpu_power_telemetry_info{ .qpc = qpc };
+
+ if (previousSampleVariant.index()) {
+
+ if (const auto result = GetGPUPowerTelemetryData(
+ currentSample, pm_gpu_power_telemetry_info); result != CTL_RESULT_SUCCESS)
+ {
+ success = false;
+ IGCL_ERR(result);
+ }
+
+ if (const auto result = GetVramPowerTelemetryData(
+ currentSample, pm_gpu_power_telemetry_info); result != CTL_RESULT_SUCCESS)
+ {
+ success = false;
+ IGCL_ERR(result);
+ }
+
+ if (const auto result = GetFanPowerTelemetryData(currentSample,
+ pm_gpu_power_telemetry_info); result != CTL_RESULT_SUCCESS)
+ {
+ success = false;
+ IGCL_ERR(result);
+ }
+
+ if (const auto result = GetPsuPowerTelemetryData(
+ currentSample, pm_gpu_power_telemetry_info); result != CTL_RESULT_SUCCESS)
+ {
+ success = false;
+ IGCL_ERR(result);
+ }
+
+ // Get memory state and bandwidth data
+ if (memoryModules.size() > 0) {
+ GetMemStateTelemetryData(memory_state,
+ pm_gpu_power_telemetry_info);
+ GetMemBandwidthData(memory_bandwidth,
+ pm_gpu_power_telemetry_info);
+ }
+
+ // Save and convert the gpu sustained power limit
+ pm_gpu_power_telemetry_info.gpu_sustained_power_limit_w =
+ gpu_sustained_power_limit_mw / 1000.;
+ SetTelemetryCapBit(GpuTelemetryCapBits::gpu_sustained_power_limit);
+
+ // Save off the calculated PresentMon power telemetry values. These are
+ // saved off for clients to extrace out timing information based on QPC
+ SavePmPowerTelemetryData(pm_gpu_power_telemetry_info);
+ }
+
+ // Save off the raw control library data for calculating time delta
+ // and usage data.
+ if (const auto result = SaveTelemetry(currentSample, memory_bandwidth);
+ result != CTL_RESULT_SUCCESS)
+ {
+ success = false;
+ IGCL_ERR(result);
+ }
+
+ return success;
+ }
+
// TODO: stop using CTL stuff for non-ctl logic
// TODO: better functional programming
- ctl_result_t IntelPowerTelemetryAdapter::GetTimeDelta(const ctl_power_telemetry_t& currentSample)
+ template
+ ctl_result_t IntelPowerTelemetryAdapter::GetTimeDelta(const T& currentSample)
{
- if (!previousSample) {
+ if (!previousSampleVariant.index()) {
// We do not have a previous power telemetry item to calculate time
// delta against.
time_delta_ = 0.f;
}
else {
- if (currentSample.timeStamp.type == CTL_DATA_TYPE_DOUBLE) {
+ auto previousSample = std::get_if(&previousSampleVariant);
+ if (previousSample && currentSample.timeStamp.type == CTL_DATA_TYPE_DOUBLE) {
time_delta_ = currentSample.timeStamp.value.datadouble -
previousSample->timeStamp.value.datadouble;
}
@@ -254,12 +336,14 @@ namespace pwr::intel
return CTL_RESULT_SUCCESS;
}
+ template
ctl_result_t IntelPowerTelemetryAdapter::GetGPUPowerTelemetryData(
- const ctl_power_telemetry_t& currentSample,
+ const T& currentSample,
PresentMonPowerTelemetryInfo& pm_gpu_power_telemetry_info)
{
ctl_result_t result;
+ auto previousSample = std::get_if(&previousSampleVariant);
if (!previousSample) {
return CTL_RESULT_ERROR_INVALID_ARGUMENT;
}
@@ -353,12 +437,14 @@ namespace pwr::intel
return result;
}
+ template
ctl_result_t IntelPowerTelemetryAdapter::GetVramPowerTelemetryData(
- const ctl_power_telemetry_t& currentSample,
+ const T& currentSample,
PresentMonPowerTelemetryInfo& pm_gpu_power_telemetry_info)
{
ctl_result_t result;
+ auto previousSample = std::get_if(&previousSampleVariant);
if (!previousSample) {
return CTL_RESULT_ERROR_INVALID_ARGUMENT;
}
@@ -394,22 +480,79 @@ namespace pwr::intel
return result;
}
- result = GetPowerTelemetryItemUsage(
- currentSample.vramReadBandwidthCounter,
- previousSample->vramReadBandwidthCounter,
- pm_gpu_power_telemetry_info.gpu_mem_read_bandwidth_bps,
- GpuTelemetryCapBits::gpu_mem_read_bandwidth);
- if (result != CTL_RESULT_SUCCESS) {
- return result;
+ // bandwidth telemetry has 2 possible paths for aquisition
+ if constexpr (std::same_as) {
+ using namespace pmon::util;
+ if (useNewBandwidthTelemetry) {
+ double gpuMemReadBandwidthMegabytesPerSecond = 0;
+ result = GetInstantaneousPowerTelemetryItem(
+ currentSample.vramReadBandwidth,
+ gpuMemReadBandwidthMegabytesPerSecond,
+ GpuTelemetryCapBits::gpu_mem_read_bandwidth);
+ // we need bandwidth in bits per second, IGCL V1 gives in megabytes per second
+ pm_gpu_power_telemetry_info.gpu_mem_read_bandwidth_bps = ConvertMagnitudePrefix(
+ gpuMemReadBandwidthMegabytesPerSecond * 8.,
+ MagnitudePrefix::Mega,
+ MagnitudePrefix::Base);
+ pmlog_verb(v::gpu)(std::format("VRAM read BW V1: bSupported [{}] type [{}] units [{}] data_64 [{}] data_double [{}] info []{}",
+ currentSample.vramReadBandwidth.bSupported, (int)currentSample.vramReadBandwidth.type,
+ (int)currentSample.vramReadBandwidth.units, currentSample.vramReadBandwidth.value.datau64,
+ currentSample.vramReadBandwidth.value.datadouble, pm_gpu_power_telemetry_info.gpu_mem_read_bandwidth_bps));
+ if (result != CTL_RESULT_SUCCESS ||
+ !(HasTelemetryCapBit(GpuTelemetryCapBits::gpu_mem_read_bandwidth))) {
+ useNewBandwidthTelemetry = false;
+ pmlog_info("V1 vram bandwidth not available, falling back to V0 counters")
+ .code(result).pmwatch(HasTelemetryCapBit(GpuTelemetryCapBits::gpu_mem_read_bandwidth));
+ }
+ }
+ if (useNewBandwidthTelemetry) {
+ double gpuMemWriteBandwidthMegabytesPerSecond = 0;
+ result = GetInstantaneousPowerTelemetryItem(
+ currentSample.vramWriteBandwidth,
+ gpuMemWriteBandwidthMegabytesPerSecond,
+ GpuTelemetryCapBits::gpu_mem_write_bandwidth);
+ // we need bandwidth in bits per second, IGCL V1 gives in megabytes per second
+ pm_gpu_power_telemetry_info.gpu_mem_write_bandwidth_bps = ConvertMagnitudePrefix(
+ gpuMemWriteBandwidthMegabytesPerSecond * 8.,
+ MagnitudePrefix::Mega,
+ MagnitudePrefix::Base);
+ pmlog_verb(v::gpu)(std::format("VRAM write BW V1: bSupported [{}] type [{}] units [{}] data_64 [{}] data_double [{}] info []{}",
+ currentSample.vramWriteBandwidth.bSupported, (int)currentSample.vramWriteBandwidth.type,
+ (int)currentSample.vramWriteBandwidth.units, currentSample.vramWriteBandwidth.value.datau64,
+ currentSample.vramWriteBandwidth.value.datadouble, pm_gpu_power_telemetry_info.gpu_mem_write_bandwidth_bps));
+ if (result != CTL_RESULT_SUCCESS ||
+ !(HasTelemetryCapBit(GpuTelemetryCapBits::gpu_mem_write_bandwidth))) {
+ useNewBandwidthTelemetry = false;
+ pmlog_info("V1 vram bandwidth not available, falling back to V0 counters")
+ .code(result).pmwatch(HasTelemetryCapBit(GpuTelemetryCapBits::gpu_mem_write_bandwidth));
+ }
+ }
}
-
- result = GetPowerTelemetryItemUsage(
- currentSample.vramWriteBandwidthCounter,
- previousSample->vramWriteBandwidthCounter,
- pm_gpu_power_telemetry_info.gpu_mem_write_bandwidth_bps,
- GpuTelemetryCapBits::gpu_mem_write_bandwidth);
- if (result != CTL_RESULT_SUCCESS) {
- return result;
+ if (!useNewBandwidthTelemetry) {
+ result = GetPowerTelemetryItemUsage(
+ currentSample.vramReadBandwidthCounter,
+ previousSample->vramReadBandwidthCounter,
+ pm_gpu_power_telemetry_info.gpu_mem_read_bandwidth_bps,
+ GpuTelemetryCapBits::gpu_mem_read_bandwidth);
+ pmlog_verb(v::gpu)(std::format("VRAM read BW V0: bSupported [{}] type [{}] units [{}] data_64 [{}] data_double [{}] info []{}",
+ currentSample.vramReadBandwidthCounter.bSupported, (int)currentSample.vramReadBandwidthCounter.type,
+ (int)currentSample.vramReadBandwidthCounter.units, currentSample.vramReadBandwidthCounter.value.datau64,
+ currentSample.vramReadBandwidthCounter.value.datadouble, pm_gpu_power_telemetry_info.gpu_mem_read_bandwidth_bps));
+ if (result != CTL_RESULT_SUCCESS) {
+ return result;
+ }
+ result = GetPowerTelemetryItemUsage(
+ currentSample.vramWriteBandwidthCounter,
+ previousSample->vramWriteBandwidthCounter,
+ pm_gpu_power_telemetry_info.gpu_mem_write_bandwidth_bps,
+ GpuTelemetryCapBits::gpu_mem_write_bandwidth);
+ pmlog_verb(v::gpu)(std::format("VRAM write BW V0: bSupported [{}] type [{}] units [{}] data_64 [{}] data_double [{}] info []{}",
+ currentSample.vramWriteBandwidthCounter.bSupported, (int)currentSample.vramWriteBandwidthCounter.type,
+ (int)currentSample.vramWriteBandwidthCounter.units, currentSample.vramWriteBandwidthCounter.value.datau64,
+ currentSample.vramWriteBandwidthCounter.value.datadouble, pm_gpu_power_telemetry_info.gpu_mem_write_bandwidth_bps));
+ if (result != CTL_RESULT_SUCCESS) {
+ return result;
+ }
}
result = GetPowerTelemetryItemUsage(currentSample.vramEnergyCounter,
@@ -441,8 +584,9 @@ namespace pwr::intel
return result;
}
+ template
ctl_result_t IntelPowerTelemetryAdapter::GetFanPowerTelemetryData(
- const ctl_power_telemetry_t& currentSample,
+ const T& currentSample,
PresentMonPowerTelemetryInfo& pm_gpu_power_telemetry_info)
{
ctl_result_t result = CTL_RESULT_SUCCESS;
@@ -466,12 +610,14 @@ namespace pwr::intel
return result;
}
+ template
ctl_result_t IntelPowerTelemetryAdapter::GetPsuPowerTelemetryData(
- const ctl_power_telemetry_t& currentSample,
+ const T& currentSample,
PresentMonPowerTelemetryInfo& pm_gpu_power_telemetry_info)
{
ctl_result_t result = CTL_RESULT_SUCCESS;
+ auto previousSample = std::get_if(&previousSampleVariant);
if (!previousSample) {
return CTL_RESULT_ERROR_INVALID_ARGUMENT;
}
@@ -584,6 +730,14 @@ namespace pwr::intel
previous_telemetry_item.value.datadouble;
pm_telemetry_value = (data_delta / time_delta_);
SetTelemetryCapBit(telemetry_cap_bit);
+ if (telemetry_cap_bit == GpuTelemetryCapBits::vram_power && useV1PowerTelemetry) {
+ if (current_telemetry_item.value.datadouble < previous_telemetry_item.value.datadouble) {
+ pm_telemetry_value = gpu_mem_power_cache_value_w_;
+ }
+ else {
+ gpu_mem_power_cache_value_w_ = pm_telemetry_value;
+ }
+ }
}
else if (current_telemetry_item.type == CTL_DATA_TYPE_INT64) {
auto data_delta = current_telemetry_item.value.data64 -
@@ -597,17 +751,15 @@ namespace pwr::intel
pm_telemetry_value =
static_cast(data_delta) / time_delta_;
SetTelemetryCapBit(telemetry_cap_bit);
- // TODO: File issue with control lib to determine why read bandwidth
- // occasionally returns what appears to be an invalid counter value. If the currently monotomic value
- // is less than the previous value OR the calculated bandwidth is greater then the max bandwidth
- // return back the cached value
- if (telemetry_cap_bit == GpuTelemetryCapBits::gpu_mem_read_bandwidth) {
- if ((current_telemetry_item.value.datau64 < previous_telemetry_item.value.datau64) ||
- ((current_telemetry_item.value.datau64 - previous_telemetry_item.value.datau64) > gpu_mem_max_bw_cache_value_bps_)) {
- pm_telemetry_value = gpu_mem_read_bw_cache_value_bps_;
- } else {
- gpu_mem_read_bw_cache_value_bps_ = pm_telemetry_value;
- }
+ // stopgap measure for bad vram bandwidth telemetry coming out of V0 api
+ if (telemetry_cap_bit == GpuTelemetryCapBits::gpu_mem_read_bandwidth && !useNewBandwidthTelemetry) {
+ if ((current_telemetry_item.value.datau64 < previous_telemetry_item.value.datau64) ||
+ ((current_telemetry_item.value.datau64 - previous_telemetry_item.value.datau64) > gpu_mem_max_bw_cache_value_bps_)) {
+ pm_telemetry_value = gpu_mem_read_bw_cache_value_bps_;
+ }
+ else {
+ gpu_mem_read_bw_cache_value_bps_ = pm_telemetry_value;
+ }
}
}
else {
@@ -618,24 +770,26 @@ namespace pwr::intel
return CTL_RESULT_SUCCESS;
}
+ template
ctl_result_t IntelPowerTelemetryAdapter::SaveTelemetry(
- const ctl_power_telemetry_t& currentSample,
+ const T& currentSample,
const ctl_mem_bandwidth_t& currentMemBandwidthSample)
{
if (currentSample.timeStamp.type == CTL_DATA_TYPE_DOUBLE) {
- previousSample = currentSample;
+ previousSampleVariant = currentSample;
}
else {
return CTL_RESULT_ERROR_INVALID_ARGUMENT;
}
- previousMemBwSample = currentMemBandwidthSample;
-
return CTL_RESULT_SUCCESS;
}
void IntelPowerTelemetryAdapter::SavePmPowerTelemetryData(PresentMonPowerTelemetryInfo& info)
{
+ pmlog_verb(v::gpu)(std::format("Saving gathered telemetry info to history; read bw [{}] write bw [{}]",
+ info.gpu_mem_read_bandwidth_bps, info.gpu_mem_write_bandwidth_bps
+ ));
std::lock_guard lock(historyMutex);
history.Push(info);
}
diff --git a/IntelPresentMon/ControlLib/IntelPowerTelemetryAdapter.h b/IntelPresentMon/ControlLib/IntelPowerTelemetryAdapter.h
index 8e07b662..77cd6475 100644
--- a/IntelPresentMon/ControlLib/IntelPowerTelemetryAdapter.h
+++ b/IntelPresentMon/ControlLib/IntelPowerTelemetryAdapter.h
@@ -6,8 +6,10 @@
#include "igcl_api.h"
#include "PowerTelemetryAdapter.h"
#include "TelemetryHistory.h"
+#include "ctlpvttemp_api.h"
#include
#include
+#include
namespace pwr::intel
{
@@ -27,23 +29,37 @@ namespace pwr::intel
class NonGraphicsDeviceException : public std::exception {};
private:
+ // types
+ using SampleVariantType = std::variant;
// functions
+ template
+ bool GatherSampleData(T& currentSample,
+ ctl_mem_state_t& memory_state,
+ ctl_mem_bandwidth_t& memory_bandwidth,
+ double gpu_sustained_power_limit_mw,
+ uint64_t qpc);
+
ctl_result_t EnumerateMemoryModules();
- ctl_result_t GetTimeDelta(const ctl_power_telemetry_t& power_telemetry);
+ template
+ ctl_result_t GetTimeDelta(const T& power_telemetry);
// TODO: meld these into the sample function
+ template
ctl_result_t GetGPUPowerTelemetryData(
- const ctl_power_telemetry_t& power_telemetry,
+ const T& power_telemetry,
PresentMonPowerTelemetryInfo& pm_gpu_power_telemetry_info);
+ template
ctl_result_t GetVramPowerTelemetryData(
- const ctl_power_telemetry_t& power_telemetry,
+ const T& power_telemetry,
PresentMonPowerTelemetryInfo& pm_gpu_power_telemetry_info);
+ template
ctl_result_t GetFanPowerTelemetryData(
- const ctl_power_telemetry_t& power_telemetry,
+ const T& power_telemetry,
PresentMonPowerTelemetryInfo& pm_gpu_power_telemetry_info);
+ template
ctl_result_t GetPsuPowerTelemetryData(
- const ctl_power_telemetry_t& power_telemetry,
+ const T& power_telemetry,
PresentMonPowerTelemetryInfo& pm_gpu_power_telemetry_info);
void GetMemStateTelemetryData(
@@ -54,8 +70,9 @@ namespace pwr::intel
PresentMonPowerTelemetryInfo& pm_gpu_power_telemetry_info);
void SavePmPowerTelemetryData(PresentMonPowerTelemetryInfo& pm_gpu_power_telemetry_info);
+ template
ctl_result_t SaveTelemetry(
- const ctl_power_telemetry_t& power_telemetry,
+ const T& power_telemetry,
const ctl_mem_bandwidth_t& mem_bandwidth);
// TODO: put these as part of the telemetry data object
@@ -82,12 +99,17 @@ namespace pwr::intel
std::vector memoryModules;
mutable std::mutex historyMutex;
TelemetryHistory history{ PowerTelemetryAdapter::defaultHistorySize };
- std::optional previousSample;
- std::optional previousMemBwSample;
+ SampleVariantType previousSampleVariant;
+ bool useV1PowerTelemetry = true;
+ bool useNewBandwidthTelemetry = true;
double time_delta_ = 0.f;
- // TODO: File issue with control lib to determine why readbandwidth
- // occasionally returns what appears to be an invalid counter value
+ // in V0 api readbandwidth occasionally returns what appears to be an invalid counter value
+ // this is a stopgap to cover for cases where IGCL is reporting bad data in V0 bandwidth telemetry
double gpu_mem_read_bw_cache_value_bps_ = 0.;
uint64_t gpu_mem_max_bw_cache_value_bps_ = 0;
+ // in V1 api vramEnergyCounter rolls over after hitting 1000.0 causing the current sample to be
+ // less than the previous sample. Working with IGCL to determine the correct behavior for roll
+ // over occasions
+ double gpu_mem_power_cache_value_w_ = 0;
};
}
\ No newline at end of file
diff --git a/IntelPresentMon/ControlLib/IntelPowerTelemetryProvider.cpp b/IntelPresentMon/ControlLib/IntelPowerTelemetryProvider.cpp
index 21ed2b01..6469b319 100644
--- a/IntelPresentMon/ControlLib/IntelPowerTelemetryProvider.cpp
+++ b/IntelPresentMon/ControlLib/IntelPowerTelemetryProvider.cpp
@@ -13,17 +13,23 @@ namespace pwr::intel
// to obtain a legit application Id or is default fine?
ctl_init_args_t ctl_init_args{
.Size = sizeof(ctl_init_args),
- .Version = 0,
.AppVersion = CTL_MAKE_VERSION(CTL_IMPL_MAJOR_VERSION, CTL_IMPL_MINOR_VERSION),
.flags = CTL_INIT_FLAG_USE_LEVEL_ZERO,
};
// initialize the igcl api
if (const auto result = ctlInit(&ctl_init_args, &apiHandle); result != CTL_RESULT_SUCCESS) {
- IGCL_ERR(result);
+ if (result != CTL_RESULT_ERROR_NOT_INITIALIZED) {
+ IGCL_ERR(result);
+ }
throw Except("Unable to initialize Intel Graphics Control Library");
}
+ pmlog_info(std::format("Initialized IGCL with version={}.{}",
+ CTL_MAJOR_VERSION(ctl_init_args.SupportedVersion),
+ CTL_MINOR_VERSION(ctl_init_args.SupportedVersion)
+ ));
+
// enumerate devices available via igcl (get a list of device handles)
std::vector handles;
{
diff --git a/IntelPresentMon/ControlLib/Logging.h b/IntelPresentMon/ControlLib/Logging.h
index d157ac22..311b6f26 100644
--- a/IntelPresentMon/ControlLib/Logging.h
+++ b/IntelPresentMon/ControlLib/Logging.h
@@ -4,6 +4,8 @@
#include
#include
#include "igcl_api.h"
+#include "../CommonUtilities/log/Log.h"
+#include "LoggingVerbose.h"
namespace pwr::log
{
@@ -29,5 +31,5 @@ namespace pwr::log
}
}
-#define IGCL_ERR(code) OutputDebugStringA(pwr::log::MakeIgclDebugErrorString((code), __LINE__, __FILE__, __FUNCTION__).c_str())
+#define IGCL_ERR(ec) pmlog_error("IGCL").code((unsigned int)ec);
#define TELE_ERR(msg) OutputDebugStringA(pwr::log::MakeTelemetryDebugErrorString((msg), __LINE__, __FILE__, __FUNCTION__).c_str())
\ No newline at end of file
diff --git a/IntelPresentMon/ControlLib/LoggingVerbose.h b/IntelPresentMon/ControlLib/LoggingVerbose.h
new file mode 100644
index 00000000..d914518c
--- /dev/null
+++ b/IntelPresentMon/ControlLib/LoggingVerbose.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace pwr::v
+{
+#ifndef VVV_GPU_TELEMETRY // system that reads power, temperature, etc. telemetry of graphics adapter devices
+ inline constexpr bool gpu = false;
+#else
+ inline constexpr bool gpu = true;
+#endif
+}
\ No newline at end of file
diff --git a/IntelPresentMon/ControlLib/PowerTelemetryAdapter.h b/IntelPresentMon/ControlLib/PowerTelemetryAdapter.h
index f5d5f65f..531c1c5c 100644
--- a/IntelPresentMon/ControlLib/PowerTelemetryAdapter.h
+++ b/IntelPresentMon/ControlLib/PowerTelemetryAdapter.h
@@ -27,12 +27,15 @@ namespace pwr
{
gpuTelemetryCapBits_.set(static_cast(telemetryCapBit));
}
- std::bitset<
- static_cast(GpuTelemetryCapBits::gpu_telemetry_count)>
+ std::bitset(GpuTelemetryCapBits::gpu_telemetry_count)>
GetPowerTelemetryCapBits()
{
return gpuTelemetryCapBits_;
}
+ bool HasTelemetryCapBit(GpuTelemetryCapBits bit) const
+ {
+ return gpuTelemetryCapBits_.test(size_t(bit));
+ }
// constants
static constexpr size_t defaultHistorySize = 300;
diff --git a/IntelPresentMon/ControlLib/cApiWrapper.cpp b/IntelPresentMon/ControlLib/cApiWrapper.cpp
index 13ea795f..c881441a 100644
--- a/IntelPresentMon/ControlLib/cApiWrapper.cpp
+++ b/IntelPresentMon/ControlLib/cApiWrapper.cpp
@@ -19,6 +19,7 @@
#include
#include
+#include
//#define CTL_APIEXPORT
@@ -31,10 +32,16 @@
static HINSTANCE hinstLib = NULL;
static ctl_runtime_path_args_t* pRuntimeArgs = NULL;
+HINSTANCE GetLoaderHandle(void)
+{
+ return hinstLib;
+}
+
/**
* @brief Function to get DLL name based on app version
*
*/
+
#if defined(_WIN64)
#define CTL_DLL_NAME L"ControlLib"
#else
@@ -54,10 +61,15 @@ ctl_result_t GetControlAPIDLLPath(ctl_init_args_t* pInitArgs, wchar_t* pwcDLLPat
if (majorVersion > CTL_IMPL_MAJOR_VERSION)
return CTL_RESULT_ERROR_UNSUPPORTED_VERSION;
+#if (CTL_IMPL_MAJOR_VERSION > 1)
if (majorVersion > 1)
StringCbPrintfW(pwcDLLPath,CTL_DLL_PATH_LEN,L"%s%d.dll", CTL_DLL_NAME, majorVersion);
else // just control_api.dll
StringCbPrintfW(pwcDLLPath,CTL_DLL_PATH_LEN,L"%s.dll", CTL_DLL_NAME);
+#else
+ StringCbPrintfW(pwcDLLPath,CTL_DLL_PATH_LEN,L"%s.dll", CTL_DLL_NAME);
+#endif
+
}
else if (pRuntimeArgs->pRuntimePath)
{
@@ -68,6 +80,7 @@ ctl_result_t GetControlAPIDLLPath(ctl_init_args_t* pInitArgs, wchar_t* pwcDLLPat
}
+
/**
* @brief Control Api Init
*
@@ -94,18 +107,27 @@ ctlInit(
// special code - only for ctlInit()
if (NULL == hinstLib)
{
- wchar_t strDLLPath[CTL_DLL_PATH_LEN];
- result = GetControlAPIDLLPath(pInitDesc, strDLLPath);
+ std::vector strDLLPath;
+ try
+ {
+ strDLLPath.resize(CTL_DLL_PATH_LEN);
+ }
+ catch (std::bad_alloc&)
+ {
+ return CTL_RESULT_ERROR_OUT_OF_DEVICE_MEMORY;
+ }
+
+ result = GetControlAPIDLLPath(pInitDesc, strDLLPath.data());
if (result == CTL_RESULT_SUCCESS)
{
#ifdef WINDOWS_UWP
- hinstLib = LoadPackagedLibrary(strDLLPath, 0);
+ hinstLib = LoadPackagedLibrary(strDLLPath.data(), 0);
#else
DWORD dwFlags = LOAD_LIBRARY_SEARCH_SYSTEM32;
#ifdef _DEBUG
dwFlags = dwFlags | LOAD_LIBRARY_SEARCH_APPLICATION_DIR;
#endif
- hinstLib = LoadLibraryExW(strDLLPath, NULL, dwFlags);
+ hinstLib = LoadLibraryExW(strDLLPath.data(), NULL, dwFlags);
#endif
if (NULL == hinstLib)
{
@@ -114,13 +136,15 @@ ctlInit(
else if (pRuntimeArgs)
{
ctlSetRuntimePath(pRuntimeArgs);
- }
- }
+ }
+ }
}
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnInit_t pfnInit = (ctl_pfnInit_t)GetProcAddress(hinstLib, "ctlInit");
+ ctl_pfnInit_t pfnInit = (ctl_pfnInit_t)GetProcAddress(hinstLibPtr, "ctlInit");
if (pfnInit)
{
result = pfnInit(pInitDesc, phAPIHandle);
@@ -154,9 +178,11 @@ ctlClose(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnClose_t pfnClose = (ctl_pfnClose_t)GetProcAddress(hinstLib, "ctlClose");
+ ctl_pfnClose_t pfnClose = (ctl_pfnClose_t)GetProcAddress(hinstLibPtr, "ctlClose");
if (pfnClose)
{
result = pfnClose(hAPIHandle);
@@ -171,7 +197,7 @@ ctlClose(
if (NULL != hinstLib)
{
FreeLibrary(hinstLib);
- hinstLib = NULL;
+ hinstLib = NULL;
}
}
// set runtime args back to NULL
@@ -207,9 +233,11 @@ ctlSetRuntimePath(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnSetRuntimePath_t pfnSetRuntimePath = (ctl_pfnSetRuntimePath_t)GetProcAddress(hinstLib, "ctlSetRuntimePath");
+ ctl_pfnSetRuntimePath_t pfnSetRuntimePath = (ctl_pfnSetRuntimePath_t)GetProcAddress(hinstLibPtr, "ctlSetRuntimePath");
if (pfnSetRuntimePath)
{
result = pfnSetRuntimePath(pArgs);
@@ -256,9 +284,11 @@ ctlWaitForPropertyChange(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnWaitForPropertyChange_t pfnWaitForPropertyChange = (ctl_pfnWaitForPropertyChange_t)GetProcAddress(hinstLib, "ctlWaitForPropertyChange");
+ ctl_pfnWaitForPropertyChange_t pfnWaitForPropertyChange = (ctl_pfnWaitForPropertyChange_t)GetProcAddress(hinstLibPtr, "ctlWaitForPropertyChange");
if (pfnWaitForPropertyChange)
{
result = pfnWaitForPropertyChange(hDeviceAdapter, pArgs);
@@ -294,9 +324,11 @@ ctlReservedCall(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnReservedCall_t pfnReservedCall = (ctl_pfnReservedCall_t)GetProcAddress(hinstLib, "ctlReservedCall");
+ ctl_pfnReservedCall_t pfnReservedCall = (ctl_pfnReservedCall_t)GetProcAddress(hinstLibPtr, "ctlReservedCall");
if (pfnReservedCall)
{
result = pfnReservedCall(hDeviceAdapter, pArgs);
@@ -332,9 +364,11 @@ ctlGetSupported3DCapabilities(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSupported3DCapabilities_t pfnGetSupported3DCapabilities = (ctl_pfnGetSupported3DCapabilities_t)GetProcAddress(hinstLib, "ctlGetSupported3DCapabilities");
+ ctl_pfnGetSupported3DCapabilities_t pfnGetSupported3DCapabilities = (ctl_pfnGetSupported3DCapabilities_t)GetProcAddress(hinstLibPtr, "ctlGetSupported3DCapabilities");
if (pfnGetSupported3DCapabilities)
{
result = pfnGetSupported3DCapabilities(hDAhandle, pFeatureCaps);
@@ -370,9 +404,11 @@ ctlGetSet3DFeature(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSet3DFeature_t pfnGetSet3DFeature = (ctl_pfnGetSet3DFeature_t)GetProcAddress(hinstLib, "ctlGetSet3DFeature");
+ ctl_pfnGetSet3DFeature_t pfnGetSet3DFeature = (ctl_pfnGetSet3DFeature_t)GetProcAddress(hinstLibPtr, "ctlGetSet3DFeature");
if (pfnGetSet3DFeature)
{
result = pfnGetSet3DFeature(hDAhandle, pFeature);
@@ -406,9 +442,11 @@ ctlCheckDriverVersion(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnCheckDriverVersion_t pfnCheckDriverVersion = (ctl_pfnCheckDriverVersion_t)GetProcAddress(hinstLib, "ctlCheckDriverVersion");
+ ctl_pfnCheckDriverVersion_t pfnCheckDriverVersion = (ctl_pfnCheckDriverVersion_t)GetProcAddress(hinstLibPtr, "ctlCheckDriverVersion");
if (pfnCheckDriverVersion)
{
result = pfnCheckDriverVersion(hDeviceAdapter, version_info);
@@ -452,9 +490,11 @@ ctlEnumerateDevices(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEnumerateDevices_t pfnEnumerateDevices = (ctl_pfnEnumerateDevices_t)GetProcAddress(hinstLib, "ctlEnumerateDevices");
+ ctl_pfnEnumerateDevices_t pfnEnumerateDevices = (ctl_pfnEnumerateDevices_t)GetProcAddress(hinstLibPtr, "ctlEnumerateDevices");
if (pfnEnumerateDevices)
{
result = pfnEnumerateDevices(hAPIHandle, pCount, phDevices);
@@ -497,9 +537,11 @@ ctlEnumerateDisplayOutputs(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEnumerateDisplayOutputs_t pfnEnumerateDisplayOutputs = (ctl_pfnEnumerateDisplayOutputs_t)GetProcAddress(hinstLib, "ctlEnumerateDisplayOutputs");
+ ctl_pfnEnumerateDisplayOutputs_t pfnEnumerateDisplayOutputs = (ctl_pfnEnumerateDisplayOutputs_t)GetProcAddress(hinstLibPtr, "ctlEnumerateDisplayOutputs");
if (pfnEnumerateDisplayOutputs)
{
result = pfnEnumerateDisplayOutputs(hDeviceAdapter, pCount, phDisplayOutputs);
@@ -510,6 +552,57 @@ ctlEnumerateDisplayOutputs(
}
+/**
+* @brief Enumerate I2C Pin Pairs
+*
+* @details
+* - Returns available list of I2C Pin-Pairs on a requested adapter
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceAdapter`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pCount`
+* - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+* - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "The incoming pointer pCount is null"
+* - ::CTL_RESULT_ERROR_INVALID_SIZE - "The supplied Count is not equal to actual number of i2c pin-pair instances"
+*/
+ctl_result_t CTL_APICALL
+ctlEnumerateI2CPinPairs(
+ ctl_device_adapter_handle_t hDeviceAdapter, ///< [in][release] handle to device adapter
+ uint32_t* pCount, ///< [in,out][release] pointer to the number of i2c pin-pair instances. If
+ ///< count is zero, then the api will update the value with the total
+ ///< number of i2c pin-pair instances available. If count is non-zero and
+ ///< matches the avaialble number of pin-pairs, then the api will only
+ ///< return the avaialble number of i2c pin-pair instances in phI2cPinPairs.
+ ctl_i2c_pin_pair_handle_t* phI2cPinPairs ///< [out][optional][release][range(0, *pCount)] array of i2c pin pair
+ ///< instance handles. Need to be allocated by Caller when supplying the
+ ///< *pCount > 0.
+ ///< If Count is not equal to actual number of i2c pin-pair instances, it
+ ///< will return CTL_RESULT_ERROR_INVALID_SIZE.
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctl_pfnEnumerateI2CPinPairs_t pfnEnumerateI2CPinPairs = (ctl_pfnEnumerateI2CPinPairs_t)GetProcAddress(hinstLibPtr, "ctlEnumerateI2CPinPairs");
+ if (pfnEnumerateI2CPinPairs)
+ {
+ result = pfnEnumerateI2CPinPairs(hDeviceAdapter, pCount, phI2cPinPairs);
+ }
+ }
+
+ return result;
+}
+
+
/**
* @brief Get Device Properties
*
@@ -535,9 +628,11 @@ ctlGetDeviceProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetDeviceProperties_t pfnGetDeviceProperties = (ctl_pfnGetDeviceProperties_t)GetProcAddress(hinstLib, "ctlGetDeviceProperties");
+ ctl_pfnGetDeviceProperties_t pfnGetDeviceProperties = (ctl_pfnGetDeviceProperties_t)GetProcAddress(hinstLibPtr, "ctlGetDeviceProperties");
if (pfnGetDeviceProperties)
{
result = pfnGetDeviceProperties(hDAhandle, pProperties);
@@ -573,9 +668,11 @@ ctlGetDisplayProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetDisplayProperties_t pfnGetDisplayProperties = (ctl_pfnGetDisplayProperties_t)GetProcAddress(hinstLib, "ctlGetDisplayProperties");
+ ctl_pfnGetDisplayProperties_t pfnGetDisplayProperties = (ctl_pfnGetDisplayProperties_t)GetProcAddress(hinstLibPtr, "ctlGetDisplayProperties");
if (pfnGetDisplayProperties)
{
result = pfnGetDisplayProperties(hDisplayOutput, pProperties);
@@ -611,9 +708,11 @@ ctlGetAdaperDisplayEncoderProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetAdaperDisplayEncoderProperties_t pfnGetAdaperDisplayEncoderProperties = (ctl_pfnGetAdaperDisplayEncoderProperties_t)GetProcAddress(hinstLib, "ctlGetAdaperDisplayEncoderProperties");
+ ctl_pfnGetAdaperDisplayEncoderProperties_t pfnGetAdaperDisplayEncoderProperties = (ctl_pfnGetAdaperDisplayEncoderProperties_t)GetProcAddress(hinstLibPtr, "ctlGetAdaperDisplayEncoderProperties");
if (pfnGetAdaperDisplayEncoderProperties)
{
result = pfnGetAdaperDisplayEncoderProperties(hDisplayOutput, pProperties);
@@ -652,9 +751,11 @@ ctlGetZeDevice(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetZeDevice_t pfnGetZeDevice = (ctl_pfnGetZeDevice_t)GetProcAddress(hinstLib, "ctlGetZeDevice");
+ ctl_pfnGetZeDevice_t pfnGetZeDevice = (ctl_pfnGetZeDevice_t)GetProcAddress(hinstLibPtr, "ctlGetZeDevice");
if (pfnGetZeDevice)
{
result = pfnGetZeDevice(hDAhandle, pZeDevice, hInstance);
@@ -690,9 +791,11 @@ ctlGetSharpnessCaps(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSharpnessCaps_t pfnGetSharpnessCaps = (ctl_pfnGetSharpnessCaps_t)GetProcAddress(hinstLib, "ctlGetSharpnessCaps");
+ ctl_pfnGetSharpnessCaps_t pfnGetSharpnessCaps = (ctl_pfnGetSharpnessCaps_t)GetProcAddress(hinstLibPtr, "ctlGetSharpnessCaps");
if (pfnGetSharpnessCaps)
{
result = pfnGetSharpnessCaps(hDisplayOutput, pSharpnessCaps);
@@ -728,9 +831,11 @@ ctlGetCurrentSharpness(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetCurrentSharpness_t pfnGetCurrentSharpness = (ctl_pfnGetCurrentSharpness_t)GetProcAddress(hinstLib, "ctlGetCurrentSharpness");
+ ctl_pfnGetCurrentSharpness_t pfnGetCurrentSharpness = (ctl_pfnGetCurrentSharpness_t)GetProcAddress(hinstLibPtr, "ctlGetCurrentSharpness");
if (pfnGetCurrentSharpness)
{
result = pfnGetCurrentSharpness(hDisplayOutput, pSharpnessSettings);
@@ -766,9 +871,11 @@ ctlSetCurrentSharpness(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnSetCurrentSharpness_t pfnSetCurrentSharpness = (ctl_pfnSetCurrentSharpness_t)GetProcAddress(hinstLib, "ctlSetCurrentSharpness");
+ ctl_pfnSetCurrentSharpness_t pfnSetCurrentSharpness = (ctl_pfnSetCurrentSharpness_t)GetProcAddress(hinstLibPtr, "ctlSetCurrentSharpness");
if (pfnSetCurrentSharpness)
{
result = pfnSetCurrentSharpness(hDisplayOutput, pSharpnessSettings);
@@ -783,7 +890,7 @@ ctlSetCurrentSharpness(
* @brief I2C Access
*
* @details
-* - The application does I2C aceess
+* - Interface to access I2C using display handle as identifier.
*
* @returns
* - CTL_RESULT_SUCCESS
@@ -812,9 +919,11 @@ ctlI2CAccess(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnI2CAccess_t pfnI2CAccess = (ctl_pfnI2CAccess_t)GetProcAddress(hinstLib, "ctlI2CAccess");
+ ctl_pfnI2CAccess_t pfnI2CAccess = (ctl_pfnI2CAccess_t)GetProcAddress(hinstLibPtr, "ctlI2CAccess");
if (pfnI2CAccess)
{
result = pfnI2CAccess(hDisplayOutput, pI2cAccessArgs);
@@ -825,11 +934,62 @@ ctlI2CAccess(
}
+/**
+* @brief I2C Access On Pin Pair
+*
+* @details
+* - Interface to access I2C using pin-pair handle as identifier.
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hI2cPinPair`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pI2cAccessArgs`
+* - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+* - ::CTL_RESULT_ERROR_INVALID_OPERATION_TYPE - "Invalid operation type"
+* - ::CTL_RESULT_ERROR_INVALID_SIZE - "Invalid I2C data size"
+* - ::CTL_RESULT_ERROR_INVALID_ARGUMENT - "Invalid Args passed"
+* - ::CTL_RESULT_ERROR_INSUFFICIENT_PERMISSIONS - "Insufficient permissions"
+* - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
+* - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
+* - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+* - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+* - ::CTL_RESULT_ERROR_KMD_CALL - "Kernal mode driver call failure"
+* - ::CTL_RESULT_ERROR_INVALID_NULL_HANDLE - "Invalid or Null handle passed"
+* - ::CTL_RESULT_ERROR_EXTERNAL_DISPLAY_ATTACHED - "Write to Address not allowed when Display is connected"
+*/
+ctl_result_t CTL_APICALL
+ctlI2CAccessOnPinPair(
+ ctl_i2c_pin_pair_handle_t hI2cPinPair, ///< [in] Handle to I2C pin pair.
+ ctl_i2c_access_pinpair_args_t* pI2cAccessArgs ///< [in,out] I2c access arguments.
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctl_pfnI2CAccessOnPinPair_t pfnI2CAccessOnPinPair = (ctl_pfnI2CAccessOnPinPair_t)GetProcAddress(hinstLibPtr, "ctlI2CAccessOnPinPair");
+ if (pfnI2CAccessOnPinPair)
+ {
+ result = pfnI2CAccessOnPinPair(hI2cPinPair, pI2cAccessArgs);
+ }
+ }
+
+ return result;
+}
+
+
/**
* @brief Aux Access
*
* @details
-* - The application does Aux aceess, PSR needs to be disabled for AUX
+* - The application does Aux access, PSR needs to be disabled for AUX
* call.
*
* @returns
@@ -860,9 +1020,11 @@ ctlAUXAccess(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnAUXAccess_t pfnAUXAccess = (ctl_pfnAUXAccess_t)GetProcAddress(hinstLib, "ctlAUXAccess");
+ ctl_pfnAUXAccess_t pfnAUXAccess = (ctl_pfnAUXAccess_t)GetProcAddress(hinstLibPtr, "ctlAUXAccess");
if (pfnAUXAccess)
{
result = pfnAUXAccess(hDisplayOutput, pAuxAccessArgs);
@@ -898,9 +1060,11 @@ ctlGetPowerOptimizationCaps(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetPowerOptimizationCaps_t pfnGetPowerOptimizationCaps = (ctl_pfnGetPowerOptimizationCaps_t)GetProcAddress(hinstLib, "ctlGetPowerOptimizationCaps");
+ ctl_pfnGetPowerOptimizationCaps_t pfnGetPowerOptimizationCaps = (ctl_pfnGetPowerOptimizationCaps_t)GetProcAddress(hinstLibPtr, "ctlGetPowerOptimizationCaps");
if (pfnGetPowerOptimizationCaps)
{
result = pfnGetPowerOptimizationCaps(hDisplayOutput, pPowerOptimizationCaps);
@@ -938,9 +1102,11 @@ ctlGetPowerOptimizationSetting(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetPowerOptimizationSetting_t pfnGetPowerOptimizationSetting = (ctl_pfnGetPowerOptimizationSetting_t)GetProcAddress(hinstLib, "ctlGetPowerOptimizationSetting");
+ ctl_pfnGetPowerOptimizationSetting_t pfnGetPowerOptimizationSetting = (ctl_pfnGetPowerOptimizationSetting_t)GetProcAddress(hinstLibPtr, "ctlGetPowerOptimizationSetting");
if (pfnGetPowerOptimizationSetting)
{
result = pfnGetPowerOptimizationSetting(hDisplayOutput, pPowerOptimizationSettings);
@@ -968,6 +1134,7 @@ ctlGetPowerOptimizationSetting(
* - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
* - ::CTL_RESULT_ERROR_INVALID_POWERFEATURE_OPTIMIZATION_FLAG - "Unsupported PowerOptimizationFeature"
* - ::CTL_RESULT_ERROR_INVALID_POWERSOURCE_TYPE_FOR_DPST - "DPST is supported only in DC Mode"
+* - ::CTL_RESULT_ERROR_SET_FBC_FEATURE_NOT_SUPPORTED - "Set FBC Feature not supported"
*/
ctl_result_t CTL_APICALL
ctlSetPowerOptimizationSetting(
@@ -978,9 +1145,11 @@ ctlSetPowerOptimizationSetting(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnSetPowerOptimizationSetting_t pfnSetPowerOptimizationSetting = (ctl_pfnSetPowerOptimizationSetting_t)GetProcAddress(hinstLib, "ctlSetPowerOptimizationSetting");
+ ctl_pfnSetPowerOptimizationSetting_t pfnSetPowerOptimizationSetting = (ctl_pfnSetPowerOptimizationSetting_t)GetProcAddress(hinstLibPtr, "ctlSetPowerOptimizationSetting");
if (pfnSetPowerOptimizationSetting)
{
result = pfnSetPowerOptimizationSetting(hDisplayOutput, pPowerOptimizationSettings);
@@ -1020,9 +1189,11 @@ ctlSetBrightnessSetting(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnSetBrightnessSetting_t pfnSetBrightnessSetting = (ctl_pfnSetBrightnessSetting_t)GetProcAddress(hinstLib, "ctlSetBrightnessSetting");
+ ctl_pfnSetBrightnessSetting_t pfnSetBrightnessSetting = (ctl_pfnSetBrightnessSetting_t)GetProcAddress(hinstLibPtr, "ctlSetBrightnessSetting");
if (pfnSetBrightnessSetting)
{
result = pfnSetBrightnessSetting(hDisplayOutput, pSetBrightnessSetting);
@@ -1061,9 +1232,11 @@ ctlGetBrightnessSetting(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetBrightnessSetting_t pfnGetBrightnessSetting = (ctl_pfnGetBrightnessSetting_t)GetProcAddress(hinstLib, "ctlGetBrightnessSetting");
+ ctl_pfnGetBrightnessSetting_t pfnGetBrightnessSetting = (ctl_pfnGetBrightnessSetting_t)GetProcAddress(hinstLibPtr, "ctlGetBrightnessSetting");
if (pfnGetBrightnessSetting)
{
result = pfnGetBrightnessSetting(hDisplayOutput, pGetBrightnessSetting);
@@ -1113,9 +1286,11 @@ ctlPixelTransformationGetConfig(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnPixelTransformationGetConfig_t pfnPixelTransformationGetConfig = (ctl_pfnPixelTransformationGetConfig_t)GetProcAddress(hinstLib, "ctlPixelTransformationGetConfig");
+ ctl_pfnPixelTransformationGetConfig_t pfnPixelTransformationGetConfig = (ctl_pfnPixelTransformationGetConfig_t)GetProcAddress(hinstLibPtr, "ctlPixelTransformationGetConfig");
if (pfnPixelTransformationGetConfig)
{
result = pfnPixelTransformationGetConfig(hDisplayOutput, pPixTxGetConfigArgs);
@@ -1166,9 +1341,11 @@ ctlPixelTransformationSetConfig(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnPixelTransformationSetConfig_t pfnPixelTransformationSetConfig = (ctl_pfnPixelTransformationSetConfig_t)GetProcAddress(hinstLib, "ctlPixelTransformationSetConfig");
+ ctl_pfnPixelTransformationSetConfig_t pfnPixelTransformationSetConfig = (ctl_pfnPixelTransformationSetConfig_t)GetProcAddress(hinstLibPtr, "ctlPixelTransformationSetConfig");
if (pfnPixelTransformationSetConfig)
{
result = pfnPixelTransformationSetConfig(hDisplayOutput, pPixTxSetConfigArgs);
@@ -1211,9 +1388,11 @@ ctlPanelDescriptorAccess(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnPanelDescriptorAccess_t pfnPanelDescriptorAccess = (ctl_pfnPanelDescriptorAccess_t)GetProcAddress(hinstLib, "ctlPanelDescriptorAccess");
+ ctl_pfnPanelDescriptorAccess_t pfnPanelDescriptorAccess = (ctl_pfnPanelDescriptorAccess_t)GetProcAddress(hinstLibPtr, "ctlPanelDescriptorAccess");
if (pfnPanelDescriptorAccess)
{
result = pfnPanelDescriptorAccess(hDisplayOutput, pPanelDescriptorAccessArgs);
@@ -1249,9 +1428,11 @@ ctlGetSupportedRetroScalingCapability(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSupportedRetroScalingCapability_t pfnGetSupportedRetroScalingCapability = (ctl_pfnGetSupportedRetroScalingCapability_t)GetProcAddress(hinstLib, "ctlGetSupportedRetroScalingCapability");
+ ctl_pfnGetSupportedRetroScalingCapability_t pfnGetSupportedRetroScalingCapability = (ctl_pfnGetSupportedRetroScalingCapability_t)GetProcAddress(hinstLibPtr, "ctlGetSupportedRetroScalingCapability");
if (pfnGetSupportedRetroScalingCapability)
{
result = pfnGetSupportedRetroScalingCapability(hDAhandle, pRetroScalingCaps);
@@ -1288,9 +1469,11 @@ ctlGetSetRetroScaling(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSetRetroScaling_t pfnGetSetRetroScaling = (ctl_pfnGetSetRetroScaling_t)GetProcAddress(hinstLib, "ctlGetSetRetroScaling");
+ ctl_pfnGetSetRetroScaling_t pfnGetSetRetroScaling = (ctl_pfnGetSetRetroScaling_t)GetProcAddress(hinstLibPtr, "ctlGetSetRetroScaling");
if (pfnGetSetRetroScaling)
{
result = pfnGetSetRetroScaling(hDAhandle, pGetSetRetroScalingType);
@@ -1326,9 +1509,11 @@ ctlGetSupportedScalingCapability(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSupportedScalingCapability_t pfnGetSupportedScalingCapability = (ctl_pfnGetSupportedScalingCapability_t)GetProcAddress(hinstLib, "ctlGetSupportedScalingCapability");
+ ctl_pfnGetSupportedScalingCapability_t pfnGetSupportedScalingCapability = (ctl_pfnGetSupportedScalingCapability_t)GetProcAddress(hinstLibPtr, "ctlGetSupportedScalingCapability");
if (pfnGetSupportedScalingCapability)
{
result = pfnGetSupportedScalingCapability(hDisplayOutput, pScalingCaps);
@@ -1364,9 +1549,11 @@ ctlGetCurrentScaling(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetCurrentScaling_t pfnGetCurrentScaling = (ctl_pfnGetCurrentScaling_t)GetProcAddress(hinstLib, "ctlGetCurrentScaling");
+ ctl_pfnGetCurrentScaling_t pfnGetCurrentScaling = (ctl_pfnGetCurrentScaling_t)GetProcAddress(hinstLibPtr, "ctlGetCurrentScaling");
if (pfnGetCurrentScaling)
{
result = pfnGetCurrentScaling(hDisplayOutput, pGetCurrentScalingType);
@@ -1402,9 +1589,11 @@ ctlSetCurrentScaling(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnSetCurrentScaling_t pfnSetCurrentScaling = (ctl_pfnSetCurrentScaling_t)GetProcAddress(hinstLib, "ctlSetCurrentScaling");
+ ctl_pfnSetCurrentScaling_t pfnSetCurrentScaling = (ctl_pfnSetCurrentScaling_t)GetProcAddress(hinstLibPtr, "ctlSetCurrentScaling");
if (pfnSetCurrentScaling)
{
result = pfnSetCurrentScaling(hDisplayOutput, pSetScalingType);
@@ -1441,9 +1630,11 @@ ctlGetLACEConfig(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetLACEConfig_t pfnGetLACEConfig = (ctl_pfnGetLACEConfig_t)GetProcAddress(hinstLib, "ctlGetLACEConfig");
+ ctl_pfnGetLACEConfig_t pfnGetLACEConfig = (ctl_pfnGetLACEConfig_t)GetProcAddress(hinstLibPtr, "ctlGetLACEConfig");
if (pfnGetLACEConfig)
{
result = pfnGetLACEConfig(hDisplayOutput, pLaceConfig);
@@ -1480,9 +1671,11 @@ ctlSetLACEConfig(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnSetLACEConfig_t pfnSetLACEConfig = (ctl_pfnSetLACEConfig_t)GetProcAddress(hinstLib, "ctlSetLACEConfig");
+ ctl_pfnSetLACEConfig_t pfnSetLACEConfig = (ctl_pfnSetLACEConfig_t)GetProcAddress(hinstLibPtr, "ctlSetLACEConfig");
if (pfnSetLACEConfig)
{
result = pfnSetLACEConfig(hDisplayOutput, pLaceConfig);
@@ -1522,9 +1715,11 @@ ctlSoftwarePSR(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnSoftwarePSR_t pfnSoftwarePSR = (ctl_pfnSoftwarePSR_t)GetProcAddress(hinstLib, "ctlSoftwarePSR");
+ ctl_pfnSoftwarePSR_t pfnSoftwarePSR = (ctl_pfnSoftwarePSR_t)GetProcAddress(hinstLibPtr, "ctlSoftwarePSR");
if (pfnSoftwarePSR)
{
result = pfnSoftwarePSR(hDisplayOutput, pSoftwarePsrSetting);
@@ -1560,9 +1755,11 @@ ctlGetIntelArcSyncInfoForMonitor(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetIntelArcSyncInfoForMonitor_t pfnGetIntelArcSyncInfoForMonitor = (ctl_pfnGetIntelArcSyncInfoForMonitor_t)GetProcAddress(hinstLib, "ctlGetIntelArcSyncInfoForMonitor");
+ ctl_pfnGetIntelArcSyncInfoForMonitor_t pfnGetIntelArcSyncInfoForMonitor = (ctl_pfnGetIntelArcSyncInfoForMonitor_t)GetProcAddress(hinstLibPtr, "ctlGetIntelArcSyncInfoForMonitor");
if (pfnGetIntelArcSyncInfoForMonitor)
{
result = pfnGetIntelArcSyncInfoForMonitor(hDisplayOutput, pIntelArcSyncMonitorParams);
@@ -1606,9 +1803,11 @@ ctlEnumerateMuxDevices(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEnumerateMuxDevices_t pfnEnumerateMuxDevices = (ctl_pfnEnumerateMuxDevices_t)GetProcAddress(hinstLib, "ctlEnumerateMuxDevices");
+ ctl_pfnEnumerateMuxDevices_t pfnEnumerateMuxDevices = (ctl_pfnEnumerateMuxDevices_t)GetProcAddress(hinstLibPtr, "ctlEnumerateMuxDevices");
if (pfnEnumerateMuxDevices)
{
result = pfnEnumerateMuxDevices(hAPIHandle, pCount, phMuxDevices);
@@ -1644,9 +1843,11 @@ ctlGetMuxProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetMuxProperties_t pfnGetMuxProperties = (ctl_pfnGetMuxProperties_t)GetProcAddress(hinstLib, "ctlGetMuxProperties");
+ ctl_pfnGetMuxProperties_t pfnGetMuxProperties = (ctl_pfnGetMuxProperties_t)GetProcAddress(hinstLibPtr, "ctlGetMuxProperties");
if (pfnGetMuxProperties)
{
result = pfnGetMuxProperties(hMuxDevice, pMuxProperties);
@@ -1683,9 +1884,11 @@ ctlSwitchMux(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnSwitchMux_t pfnSwitchMux = (ctl_pfnSwitchMux_t)GetProcAddress(hinstLib, "ctlSwitchMux");
+ ctl_pfnSwitchMux_t pfnSwitchMux = (ctl_pfnSwitchMux_t)GetProcAddress(hinstLibPtr, "ctlSwitchMux");
if (pfnSwitchMux)
{
result = pfnSwitchMux(hMuxDevice, hInactiveDisplayOutput);
@@ -1721,9 +1924,11 @@ ctlGetIntelArcSyncProfile(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetIntelArcSyncProfile_t pfnGetIntelArcSyncProfile = (ctl_pfnGetIntelArcSyncProfile_t)GetProcAddress(hinstLib, "ctlGetIntelArcSyncProfile");
+ ctl_pfnGetIntelArcSyncProfile_t pfnGetIntelArcSyncProfile = (ctl_pfnGetIntelArcSyncProfile_t)GetProcAddress(hinstLibPtr, "ctlGetIntelArcSyncProfile");
if (pfnGetIntelArcSyncProfile)
{
result = pfnGetIntelArcSyncProfile(hDisplayOutput, pIntelArcSyncProfileParams);
@@ -1761,9 +1966,11 @@ ctlSetIntelArcSyncProfile(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnSetIntelArcSyncProfile_t pfnSetIntelArcSyncProfile = (ctl_pfnSetIntelArcSyncProfile_t)GetProcAddress(hinstLib, "ctlSetIntelArcSyncProfile");
+ ctl_pfnSetIntelArcSyncProfile_t pfnSetIntelArcSyncProfile = (ctl_pfnSetIntelArcSyncProfile_t)GetProcAddress(hinstLibPtr, "ctlSetIntelArcSyncProfile");
if (pfnSetIntelArcSyncProfile)
{
result = pfnSetIntelArcSyncProfile(hDisplayOutput, pIntelArcSyncProfileParams);
@@ -1810,9 +2017,11 @@ ctlEdidManagement(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEdidManagement_t pfnEdidManagement = (ctl_pfnEdidManagement_t)GetProcAddress(hinstLib, "ctlEdidManagement");
+ ctl_pfnEdidManagement_t pfnEdidManagement = (ctl_pfnEdidManagement_t)GetProcAddress(hinstLibPtr, "ctlEdidManagement");
if (pfnEdidManagement)
{
result = pfnEdidManagement(hDisplayOutput, pEdidManagementArgs);
@@ -1862,9 +2071,11 @@ ctlGetSetCustomMode(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSetCustomMode_t pfnGetSetCustomMode = (ctl_pfnGetSetCustomMode_t)GetProcAddress(hinstLib, "ctlGetSetCustomMode");
+ ctl_pfnGetSetCustomMode_t pfnGetSetCustomMode = (ctl_pfnGetSetCustomMode_t)GetProcAddress(hinstLibPtr, "ctlGetSetCustomMode");
if (pfnGetSetCustomMode)
{
result = pfnGetSetCustomMode(hDisplayOutput, pCustomModeArgs);
@@ -1879,7 +2090,16 @@ ctlGetSetCustomMode(
* @brief Get/Set Combined Display
*
* @details
-* - To get or set combined display.
+* - To get or set combined display with given Child Targets on a Single
+* GPU or across identical GPUs. Multi-GPU(MGPU) combined display is
+* reserved i.e. it is not public and requires special application GUID.
+* MGPU Combined Display will get activated or deactivated in next boot.
+* MGPU scenario will internally link the associated adapters via Linked
+* Display Adapter Call, with supplied hDeviceAdapter being the LDA
+* Primary. If Genlock and enabled in Driver registry and supported by
+* given Display Config, MGPU Combined Display will enable MGPU Genlock
+* with supplied hDeviceAdapter being the Genlock Primary Adapter and the
+* First Child Display being the Primary Display.
*
* @returns
* - CTL_RESULT_SUCCESS
@@ -1898,6 +2118,7 @@ ctlGetSetCustomMode(
* - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
* - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
* - ::CTL_RESULT_ERROR_FEATURE_NOT_SUPPORTED - "Combined Display feature is not supported in this platform"
+* - ::CTL_RESULT_ERROR_ADAPTER_NOT_SUPPORTED_ON_LDA_SECONDARY - "Unsupported (secondary) adapter handle passed"
*/
ctl_result_t CTL_APICALL
ctlGetSetCombinedDisplay(
@@ -1908,9 +2129,11 @@ ctlGetSetCombinedDisplay(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSetCombinedDisplay_t pfnGetSetCombinedDisplay = (ctl_pfnGetSetCombinedDisplay_t)GetProcAddress(hinstLib, "ctlGetSetCombinedDisplay");
+ ctl_pfnGetSetCombinedDisplay_t pfnGetSetCombinedDisplay = (ctl_pfnGetSetCombinedDisplay_t)GetProcAddress(hinstLibPtr, "ctlGetSetCombinedDisplay");
if (pfnGetSetCombinedDisplay)
{
result = pfnGetSetCombinedDisplay(hDeviceAdapter, pCombinedDisplayArgs);
@@ -1946,7 +2169,7 @@ ctlGetSetCombinedDisplay(
ctl_result_t CTL_APICALL
ctlGetSetDisplayGenlock(
ctl_device_adapter_handle_t* hDeviceAdapter, ///< [in][release] Handle to control device adapter
- ctl_genlock_args_t** pGenlockArgs, ///< [in,out] Display Genlock operation and information
+ ctl_genlock_args_t* pGenlockArgs, ///< [in,out] Display Genlock operation and information
uint32_t AdapterCount, ///< [in] Number of device adapters
ctl_device_adapter_handle_t* hFailureDeviceAdapter ///< [out] Handle to address the failure device adapter in an error case
)
@@ -1954,9 +2177,11 @@ ctlGetSetDisplayGenlock(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSetDisplayGenlock_t pfnGetSetDisplayGenlock = (ctl_pfnGetSetDisplayGenlock_t)GetProcAddress(hinstLib, "ctlGetSetDisplayGenlock");
+ ctl_pfnGetSetDisplayGenlock_t pfnGetSetDisplayGenlock = (ctl_pfnGetSetDisplayGenlock_t)GetProcAddress(hinstLibPtr, "ctlGetSetDisplayGenlock");
if (pfnGetSetDisplayGenlock)
{
result = pfnGetSetDisplayGenlock(hDeviceAdapter, pGenlockArgs, AdapterCount, hFailureDeviceAdapter);
@@ -1967,6 +2192,327 @@ ctlGetSetDisplayGenlock(
}
+/**
+* @brief Get Vblank Timestamp
+*
+* @details
+* - To get a list of vblank timestamps in microseconds for each child
+* target of a display.
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDisplayOutput`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pVblankTSArgs`
+* - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+* - ::CTL_RESULT_ERROR_INSUFFICIENT_PERMISSIONS - "Insufficient permissions"
+* - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
+* - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+* - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+* - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+*/
+ctl_result_t CTL_APICALL
+ctlGetVblankTimestamp(
+ ctl_display_output_handle_t hDisplayOutput, ///< [in] Handle to display output
+ ctl_vblank_ts_args_t* pVblankTSArgs ///< [out] Get vblank timestamp arguments
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctl_pfnGetVblankTimestamp_t pfnGetVblankTimestamp = (ctl_pfnGetVblankTimestamp_t)GetProcAddress(hinstLibPtr, "ctlGetVblankTimestamp");
+ if (pfnGetVblankTimestamp)
+ {
+ result = pfnGetVblankTimestamp(hDisplayOutput, pVblankTSArgs);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Link Display Adapters
+*
+* @details
+* - To Link Display Adapters.
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hPrimaryAdapter`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pLdaArgs`
+* - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+* - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
+* - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+* - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+* - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+* - ::CTL_RESULT_ERROR_ADAPTER_ALREADY_LINKED - "Adapter is already linked"
+*/
+ctl_result_t CTL_APICALL
+ctlLinkDisplayAdapters(
+ ctl_device_adapter_handle_t hPrimaryAdapter, ///< [in][release] Handle to Primary adapter in LDA chain
+ ctl_lda_args_t* pLdaArgs ///< [in] Link Display Adapters Arguments
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctl_pfnLinkDisplayAdapters_t pfnLinkDisplayAdapters = (ctl_pfnLinkDisplayAdapters_t)GetProcAddress(hinstLibPtr, "ctlLinkDisplayAdapters");
+ if (pfnLinkDisplayAdapters)
+ {
+ result = pfnLinkDisplayAdapters(hPrimaryAdapter, pLdaArgs);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Unlink Display Adapters
+*
+* @details
+* - To Unlink Display Adapters
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hPrimaryAdapter`
+* - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+* - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+* - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+* - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+* - ::CTL_RESULT_ERROR_ADAPTER_NOT_SUPPORTED_ON_LDA_SECONDARY - "Unsupported (secondary) adapter handle passed"
+*/
+ctl_result_t CTL_APICALL
+ctlUnlinkDisplayAdapters(
+ ctl_device_adapter_handle_t hPrimaryAdapter ///< [in][release] Handle to Primary adapter in LDA chain
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctl_pfnUnlinkDisplayAdapters_t pfnUnlinkDisplayAdapters = (ctl_pfnUnlinkDisplayAdapters_t)GetProcAddress(hinstLibPtr, "ctlUnlinkDisplayAdapters");
+ if (pfnUnlinkDisplayAdapters)
+ {
+ result = pfnUnlinkDisplayAdapters(hPrimaryAdapter);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Get Linked Display Adapters
+*
+* @details
+* - To return list of Linked Display Adapters.
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hPrimaryAdapter`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pLdaArgs`
+* - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+* - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
+* - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+* - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+* - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+* - ::CTL_RESULT_ERROR_ADAPTER_NOT_SUPPORTED_ON_LDA_SECONDARY - "Unsupported (secondary) adapter handle passed"
+*/
+ctl_result_t CTL_APICALL
+ctlGetLinkedDisplayAdapters(
+ ctl_device_adapter_handle_t hPrimaryAdapter, ///< [in][release] Handle to Primary adapter in LDA chain
+ ctl_lda_args_t* pLdaArgs ///< [out] Link Display Adapters Arguments
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctl_pfnGetLinkedDisplayAdapters_t pfnGetLinkedDisplayAdapters = (ctl_pfnGetLinkedDisplayAdapters_t)GetProcAddress(hinstLibPtr, "ctlGetLinkedDisplayAdapters");
+ if (pfnGetLinkedDisplayAdapters)
+ {
+ result = pfnGetLinkedDisplayAdapters(hPrimaryAdapter, pLdaArgs);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Get/Set Dynamic Contrast Enhancement
+*
+* @details
+* - To get the DCE feature status and, if feature is enabled, returns the
+* current histogram, or to set the brightness at the phase-in speed
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDisplayOutput`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pDceArgs`
+* - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+* - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
+* - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+* - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+* - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+* - ::CTL_RESULT_ERROR_INVALID_NULL_HANDLE - "Invalid or Null handle passed"
+* - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
+* - ::CTL_RESULT_ERROR_INVALID_OPERATION_TYPE - "Invalid operation type"
+* - ::CTL_RESULT_ERROR_INVALID_ARGUMENT - "Invalid combination of parameters"
+*/
+ctl_result_t CTL_APICALL
+ctlGetSetDynamicContrastEnhancement(
+ ctl_display_output_handle_t hDisplayOutput, ///< [in] Handle to display output
+ ctl_dce_args_t* pDceArgs ///< [in,out] Dynamic Contrast Enhancement arguments
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctl_pfnGetSetDynamicContrastEnhancement_t pfnGetSetDynamicContrastEnhancement = (ctl_pfnGetSetDynamicContrastEnhancement_t)GetProcAddress(hinstLibPtr, "ctlGetSetDynamicContrastEnhancement");
+ if (pfnGetSetDynamicContrastEnhancement)
+ {
+ result = pfnGetSetDynamicContrastEnhancement(hDisplayOutput, pDceArgs);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Get/Set Color Format and Color Depth
+*
+* @details
+* - Get and Set the Color Format and Color Depth of a target
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDisplayOutput`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pGetSetWireFormatSetting`
+* - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+* - ::CTL_RESULT_ERROR_INVALID_ARGUMENT - "Invalid data passed as argument, WireFormat is not supported"
+* - ::CTL_RESULT_ERROR_DISPLAY_NOT_ACTIVE - "Display not active"
+* - ::CTL_RESULT_ERROR_INVALID_OPERATION_TYPE - "Invalid operation type"
+* - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
+* - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+* - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+*/
+ctl_result_t CTL_APICALL
+ctlGetSetWireFormat(
+ ctl_display_output_handle_t hDisplayOutput, ///< [in][release] Handle to display output
+ ctl_get_set_wire_format_config_t* pGetSetWireFormatSetting ///< [in][release] Get/Set Wire Format settings to be fetched/applied
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctl_pfnGetSetWireFormat_t pfnGetSetWireFormat = (ctl_pfnGetSetWireFormat_t)GetProcAddress(hinstLibPtr, "ctlGetSetWireFormat");
+ if (pfnGetSetWireFormat)
+ {
+ result = pfnGetSetWireFormat(hDisplayOutput, pGetSetWireFormatSetting);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Get/Set Display settings
+*
+* @details
+* - To get/set end display settings like low latency, HDR10+ signaling
+* etc. which are controlled via info-frames/secondary data packets
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDisplayOutput`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pDisplaySettings`
+* - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+* - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
+* - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+* - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+* - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+* - ::CTL_RESULT_ERROR_INVALID_NULL_HANDLE - "Invalid or Null handle passed"
+* - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
+* - ::CTL_RESULT_ERROR_INVALID_OPERATION_TYPE - "Invalid operation type"
+* - ::CTL_RESULT_ERROR_INVALID_ARGUMENT - "Invalid combination of parameters"
+*/
+ctl_result_t CTL_APICALL
+ctlGetSetDisplaySettings(
+ ctl_display_output_handle_t hDisplayOutput, ///< [in] Handle to display output
+ ctl_display_settings_t* pDisplaySettings ///< [in,out] End display capabilities
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctl_pfnGetSetDisplaySettings_t pfnGetSetDisplaySettings = (ctl_pfnGetSetDisplaySettings_t)GetProcAddress(hinstLibPtr, "ctlGetSetDisplaySettings");
+ if (pfnGetSetDisplaySettings)
+ {
+ result = pfnGetSetDisplaySettings(hDisplayOutput, pDisplaySettings);
+ }
+ }
+
+ return result;
+}
+
+
/**
* @brief Get handle of engine groups
*
@@ -2002,9 +2548,11 @@ ctlEnumEngineGroups(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEnumEngineGroups_t pfnEnumEngineGroups = (ctl_pfnEnumEngineGroups_t)GetProcAddress(hinstLib, "ctlEnumEngineGroups");
+ ctl_pfnEnumEngineGroups_t pfnEnumEngineGroups = (ctl_pfnEnumEngineGroups_t)GetProcAddress(hinstLibPtr, "ctlEnumEngineGroups");
if (pfnEnumEngineGroups)
{
result = pfnEnumEngineGroups(hDAhandle, pCount, phEngine);
@@ -2040,9 +2588,11 @@ ctlEngineGetProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEngineGetProperties_t pfnEngineGetProperties = (ctl_pfnEngineGetProperties_t)GetProcAddress(hinstLib, "ctlEngineGetProperties");
+ ctl_pfnEngineGetProperties_t pfnEngineGetProperties = (ctl_pfnEngineGetProperties_t)GetProcAddress(hinstLibPtr, "ctlEngineGetProperties");
if (pfnEngineGetProperties)
{
result = pfnEngineGetProperties(hEngine, pProperties);
@@ -2079,9 +2629,11 @@ ctlEngineGetActivity(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEngineGetActivity_t pfnEngineGetActivity = (ctl_pfnEngineGetActivity_t)GetProcAddress(hinstLib, "ctlEngineGetActivity");
+ ctl_pfnEngineGetActivity_t pfnEngineGetActivity = (ctl_pfnEngineGetActivity_t)GetProcAddress(hinstLibPtr, "ctlEngineGetActivity");
if (pfnEngineGetActivity)
{
result = pfnEngineGetActivity(hEngine, pStats);
@@ -2127,9 +2679,11 @@ ctlEnumFans(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEnumFans_t pfnEnumFans = (ctl_pfnEnumFans_t)GetProcAddress(hinstLib, "ctlEnumFans");
+ ctl_pfnEnumFans_t pfnEnumFans = (ctl_pfnEnumFans_t)GetProcAddress(hinstLibPtr, "ctlEnumFans");
if (pfnEnumFans)
{
result = pfnEnumFans(hDAhandle, pCount, phFan);
@@ -2165,9 +2719,11 @@ ctlFanGetProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFanGetProperties_t pfnFanGetProperties = (ctl_pfnFanGetProperties_t)GetProcAddress(hinstLib, "ctlFanGetProperties");
+ ctl_pfnFanGetProperties_t pfnFanGetProperties = (ctl_pfnFanGetProperties_t)GetProcAddress(hinstLibPtr, "ctlFanGetProperties");
if (pfnFanGetProperties)
{
result = pfnFanGetProperties(hFan, pProperties);
@@ -2204,9 +2760,11 @@ ctlFanGetConfig(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFanGetConfig_t pfnFanGetConfig = (ctl_pfnFanGetConfig_t)GetProcAddress(hinstLib, "ctlFanGetConfig");
+ ctl_pfnFanGetConfig_t pfnFanGetConfig = (ctl_pfnFanGetConfig_t)GetProcAddress(hinstLibPtr, "ctlFanGetConfig");
if (pfnFanGetConfig)
{
result = pfnFanGetConfig(hFan, pConfig);
@@ -2242,9 +2800,11 @@ ctlFanSetDefaultMode(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFanSetDefaultMode_t pfnFanSetDefaultMode = (ctl_pfnFanSetDefaultMode_t)GetProcAddress(hinstLib, "ctlFanSetDefaultMode");
+ ctl_pfnFanSetDefaultMode_t pfnFanSetDefaultMode = (ctl_pfnFanSetDefaultMode_t)GetProcAddress(hinstLibPtr, "ctlFanSetDefaultMode");
if (pfnFanSetDefaultMode)
{
result = pfnFanSetDefaultMode(hFan);
@@ -2285,9 +2845,11 @@ ctlFanSetFixedSpeedMode(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFanSetFixedSpeedMode_t pfnFanSetFixedSpeedMode = (ctl_pfnFanSetFixedSpeedMode_t)GetProcAddress(hinstLib, "ctlFanSetFixedSpeedMode");
+ ctl_pfnFanSetFixedSpeedMode_t pfnFanSetFixedSpeedMode = (ctl_pfnFanSetFixedSpeedMode_t)GetProcAddress(hinstLibPtr, "ctlFanSetFixedSpeedMode");
if (pfnFanSetFixedSpeedMode)
{
result = pfnFanSetFixedSpeedMode(hFan, speed);
@@ -2330,9 +2892,11 @@ ctlFanSetSpeedTableMode(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFanSetSpeedTableMode_t pfnFanSetSpeedTableMode = (ctl_pfnFanSetSpeedTableMode_t)GetProcAddress(hinstLib, "ctlFanSetSpeedTableMode");
+ ctl_pfnFanSetSpeedTableMode_t pfnFanSetSpeedTableMode = (ctl_pfnFanSetSpeedTableMode_t)GetProcAddress(hinstLibPtr, "ctlFanSetSpeedTableMode");
if (pfnFanSetSpeedTableMode)
{
result = pfnFanSetSpeedTableMode(hFan, speedTable);
@@ -2375,9 +2939,11 @@ ctlFanGetState(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFanGetState_t pfnFanGetState = (ctl_pfnFanGetState_t)GetProcAddress(hinstLib, "ctlFanGetState");
+ ctl_pfnFanGetState_t pfnFanGetState = (ctl_pfnFanGetState_t)GetProcAddress(hinstLibPtr, "ctlFanGetState");
if (pfnFanGetState)
{
result = pfnFanGetState(hFan, units, pSpeed);
@@ -2423,9 +2989,11 @@ ctlEnumFrequencyDomains(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEnumFrequencyDomains_t pfnEnumFrequencyDomains = (ctl_pfnEnumFrequencyDomains_t)GetProcAddress(hinstLib, "ctlEnumFrequencyDomains");
+ ctl_pfnEnumFrequencyDomains_t pfnEnumFrequencyDomains = (ctl_pfnEnumFrequencyDomains_t)GetProcAddress(hinstLibPtr, "ctlEnumFrequencyDomains");
if (pfnEnumFrequencyDomains)
{
result = pfnEnumFrequencyDomains(hDAhandle, pCount, phFrequency);
@@ -2461,9 +3029,11 @@ ctlFrequencyGetProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFrequencyGetProperties_t pfnFrequencyGetProperties = (ctl_pfnFrequencyGetProperties_t)GetProcAddress(hinstLib, "ctlFrequencyGetProperties");
+ ctl_pfnFrequencyGetProperties_t pfnFrequencyGetProperties = (ctl_pfnFrequencyGetProperties_t)GetProcAddress(hinstLibPtr, "ctlFrequencyGetProperties");
if (pfnFrequencyGetProperties)
{
result = pfnFrequencyGetProperties(hFrequency, pProperties);
@@ -2510,9 +3080,11 @@ ctlFrequencyGetAvailableClocks(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFrequencyGetAvailableClocks_t pfnFrequencyGetAvailableClocks = (ctl_pfnFrequencyGetAvailableClocks_t)GetProcAddress(hinstLib, "ctlFrequencyGetAvailableClocks");
+ ctl_pfnFrequencyGetAvailableClocks_t pfnFrequencyGetAvailableClocks = (ctl_pfnFrequencyGetAvailableClocks_t)GetProcAddress(hinstLibPtr, "ctlFrequencyGetAvailableClocks");
if (pfnFrequencyGetAvailableClocks)
{
result = pfnFrequencyGetAvailableClocks(hFrequency, pCount, phFrequency);
@@ -2549,9 +3121,11 @@ ctlFrequencyGetRange(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFrequencyGetRange_t pfnFrequencyGetRange = (ctl_pfnFrequencyGetRange_t)GetProcAddress(hinstLib, "ctlFrequencyGetRange");
+ ctl_pfnFrequencyGetRange_t pfnFrequencyGetRange = (ctl_pfnFrequencyGetRange_t)GetProcAddress(hinstLibPtr, "ctlFrequencyGetRange");
if (pfnFrequencyGetRange)
{
result = pfnFrequencyGetRange(hFrequency, pLimits);
@@ -2590,9 +3164,11 @@ ctlFrequencySetRange(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFrequencySetRange_t pfnFrequencySetRange = (ctl_pfnFrequencySetRange_t)GetProcAddress(hinstLib, "ctlFrequencySetRange");
+ ctl_pfnFrequencySetRange_t pfnFrequencySetRange = (ctl_pfnFrequencySetRange_t)GetProcAddress(hinstLibPtr, "ctlFrequencySetRange");
if (pfnFrequencySetRange)
{
result = pfnFrequencySetRange(hFrequency, pLimits);
@@ -2629,9 +3205,11 @@ ctlFrequencyGetState(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFrequencyGetState_t pfnFrequencyGetState = (ctl_pfnFrequencyGetState_t)GetProcAddress(hinstLib, "ctlFrequencyGetState");
+ ctl_pfnFrequencyGetState_t pfnFrequencyGetState = (ctl_pfnFrequencyGetState_t)GetProcAddress(hinstLibPtr, "ctlFrequencyGetState");
if (pfnFrequencyGetState)
{
result = pfnFrequencyGetState(hFrequency, pState);
@@ -2668,9 +3246,11 @@ ctlFrequencyGetThrottleTime(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnFrequencyGetThrottleTime_t pfnFrequencyGetThrottleTime = (ctl_pfnFrequencyGetThrottleTime_t)GetProcAddress(hinstLib, "ctlFrequencyGetThrottleTime");
+ ctl_pfnFrequencyGetThrottleTime_t pfnFrequencyGetThrottleTime = (ctl_pfnFrequencyGetThrottleTime_t)GetProcAddress(hinstLibPtr, "ctlFrequencyGetThrottleTime");
if (pfnFrequencyGetThrottleTime)
{
result = pfnFrequencyGetThrottleTime(hFrequency, pThrottleTime);
@@ -2706,9 +3286,11 @@ ctlGetSupportedVideoProcessingCapabilities(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSupportedVideoProcessingCapabilities_t pfnGetSupportedVideoProcessingCapabilities = (ctl_pfnGetSupportedVideoProcessingCapabilities_t)GetProcAddress(hinstLib, "ctlGetSupportedVideoProcessingCapabilities");
+ ctl_pfnGetSupportedVideoProcessingCapabilities_t pfnGetSupportedVideoProcessingCapabilities = (ctl_pfnGetSupportedVideoProcessingCapabilities_t)GetProcAddress(hinstLibPtr, "ctlGetSupportedVideoProcessingCapabilities");
if (pfnGetSupportedVideoProcessingCapabilities)
{
result = pfnGetSupportedVideoProcessingCapabilities(hDAhandle, pFeatureCaps);
@@ -2744,9 +3326,11 @@ ctlGetSetVideoProcessingFeature(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnGetSetVideoProcessingFeature_t pfnGetSetVideoProcessingFeature = (ctl_pfnGetSetVideoProcessingFeature_t)GetProcAddress(hinstLib, "ctlGetSetVideoProcessingFeature");
+ ctl_pfnGetSetVideoProcessingFeature_t pfnGetSetVideoProcessingFeature = (ctl_pfnGetSetVideoProcessingFeature_t)GetProcAddress(hinstLibPtr, "ctlGetSetVideoProcessingFeature");
if (pfnGetSetVideoProcessingFeature)
{
result = pfnGetSetVideoProcessingFeature(hDAhandle, pFeature);
@@ -2792,9 +3376,11 @@ ctlEnumMemoryModules(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEnumMemoryModules_t pfnEnumMemoryModules = (ctl_pfnEnumMemoryModules_t)GetProcAddress(hinstLib, "ctlEnumMemoryModules");
+ ctl_pfnEnumMemoryModules_t pfnEnumMemoryModules = (ctl_pfnEnumMemoryModules_t)GetProcAddress(hinstLibPtr, "ctlEnumMemoryModules");
if (pfnEnumMemoryModules)
{
result = pfnEnumMemoryModules(hDAhandle, pCount, phMemory);
@@ -2830,9 +3416,11 @@ ctlMemoryGetProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnMemoryGetProperties_t pfnMemoryGetProperties = (ctl_pfnMemoryGetProperties_t)GetProcAddress(hinstLib, "ctlMemoryGetProperties");
+ ctl_pfnMemoryGetProperties_t pfnMemoryGetProperties = (ctl_pfnMemoryGetProperties_t)GetProcAddress(hinstLibPtr, "ctlMemoryGetProperties");
if (pfnMemoryGetProperties)
{
result = pfnMemoryGetProperties(hMemory, pProperties);
@@ -2868,9 +3456,11 @@ ctlMemoryGetState(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnMemoryGetState_t pfnMemoryGetState = (ctl_pfnMemoryGetState_t)GetProcAddress(hinstLib, "ctlMemoryGetState");
+ ctl_pfnMemoryGetState_t pfnMemoryGetState = (ctl_pfnMemoryGetState_t)GetProcAddress(hinstLibPtr, "ctlMemoryGetState");
if (pfnMemoryGetState)
{
result = pfnMemoryGetState(hMemory, pState);
@@ -2909,9 +3499,11 @@ ctlMemoryGetBandwidth(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnMemoryGetBandwidth_t pfnMemoryGetBandwidth = (ctl_pfnMemoryGetBandwidth_t)GetProcAddress(hinstLib, "ctlMemoryGetBandwidth");
+ ctl_pfnMemoryGetBandwidth_t pfnMemoryGetBandwidth = (ctl_pfnMemoryGetBandwidth_t)GetProcAddress(hinstLibPtr, "ctlMemoryGetBandwidth");
if (pfnMemoryGetBandwidth)
{
result = pfnMemoryGetBandwidth(hMemory, pBandwidth);
@@ -2943,9 +3535,11 @@ ctlOverclockGetProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockGetProperties_t pfnOverclockGetProperties = (ctl_pfnOverclockGetProperties_t)GetProcAddress(hinstLib, "ctlOverclockGetProperties");
+ ctl_pfnOverclockGetProperties_t pfnOverclockGetProperties = (ctl_pfnOverclockGetProperties_t)GetProcAddress(hinstLibPtr, "ctlOverclockGetProperties");
if (pfnOverclockGetProperties)
{
result = pfnOverclockGetProperties(hDeviceHandle, pOcProperties);
@@ -2987,9 +3581,11 @@ ctlOverclockWaiverSet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockWaiverSet_t pfnOverclockWaiverSet = (ctl_pfnOverclockWaiverSet_t)GetProcAddress(hinstLib, "ctlOverclockWaiverSet");
+ ctl_pfnOverclockWaiverSet_t pfnOverclockWaiverSet = (ctl_pfnOverclockWaiverSet_t)GetProcAddress(hinstLibPtr, "ctlOverclockWaiverSet");
if (pfnOverclockWaiverSet)
{
result = pfnOverclockWaiverSet(hDeviceHandle);
@@ -3029,9 +3625,11 @@ ctlOverclockGpuFrequencyOffsetGet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockGpuFrequencyOffsetGet_t pfnOverclockGpuFrequencyOffsetGet = (ctl_pfnOverclockGpuFrequencyOffsetGet_t)GetProcAddress(hinstLib, "ctlOverclockGpuFrequencyOffsetGet");
+ ctl_pfnOverclockGpuFrequencyOffsetGet_t pfnOverclockGpuFrequencyOffsetGet = (ctl_pfnOverclockGpuFrequencyOffsetGet_t)GetProcAddress(hinstLibPtr, "ctlOverclockGpuFrequencyOffsetGet");
if (pfnOverclockGpuFrequencyOffsetGet)
{
result = pfnOverclockGpuFrequencyOffsetGet(hDeviceHandle, pOcFrequencyOffset);
@@ -3087,9 +3685,11 @@ ctlOverclockGpuFrequencyOffsetSet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockGpuFrequencyOffsetSet_t pfnOverclockGpuFrequencyOffsetSet = (ctl_pfnOverclockGpuFrequencyOffsetSet_t)GetProcAddress(hinstLib, "ctlOverclockGpuFrequencyOffsetSet");
+ ctl_pfnOverclockGpuFrequencyOffsetSet_t pfnOverclockGpuFrequencyOffsetSet = (ctl_pfnOverclockGpuFrequencyOffsetSet_t)GetProcAddress(hinstLibPtr, "ctlOverclockGpuFrequencyOffsetSet");
if (pfnOverclockGpuFrequencyOffsetSet)
{
result = pfnOverclockGpuFrequencyOffsetSet(hDeviceHandle, ocFrequencyOffset);
@@ -3129,9 +3729,11 @@ ctlOverclockGpuVoltageOffsetGet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockGpuVoltageOffsetGet_t pfnOverclockGpuVoltageOffsetGet = (ctl_pfnOverclockGpuVoltageOffsetGet_t)GetProcAddress(hinstLib, "ctlOverclockGpuVoltageOffsetGet");
+ ctl_pfnOverclockGpuVoltageOffsetGet_t pfnOverclockGpuVoltageOffsetGet = (ctl_pfnOverclockGpuVoltageOffsetGet_t)GetProcAddress(hinstLibPtr, "ctlOverclockGpuVoltageOffsetGet");
if (pfnOverclockGpuVoltageOffsetGet)
{
result = pfnOverclockGpuVoltageOffsetGet(hDeviceHandle, pOcVoltageOffset);
@@ -3175,9 +3777,11 @@ ctlOverclockGpuVoltageOffsetSet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockGpuVoltageOffsetSet_t pfnOverclockGpuVoltageOffsetSet = (ctl_pfnOverclockGpuVoltageOffsetSet_t)GetProcAddress(hinstLib, "ctlOverclockGpuVoltageOffsetSet");
+ ctl_pfnOverclockGpuVoltageOffsetSet_t pfnOverclockGpuVoltageOffsetSet = (ctl_pfnOverclockGpuVoltageOffsetSet_t)GetProcAddress(hinstLibPtr, "ctlOverclockGpuVoltageOffsetSet");
if (pfnOverclockGpuVoltageOffsetSet)
{
result = pfnOverclockGpuVoltageOffsetSet(hDeviceHandle, ocVoltageOffset);
@@ -3217,9 +3821,11 @@ ctlOverclockGpuLockGet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockGpuLockGet_t pfnOverclockGpuLockGet = (ctl_pfnOverclockGpuLockGet_t)GetProcAddress(hinstLib, "ctlOverclockGpuLockGet");
+ ctl_pfnOverclockGpuLockGet_t pfnOverclockGpuLockGet = (ctl_pfnOverclockGpuLockGet_t)GetProcAddress(hinstLibPtr, "ctlOverclockGpuLockGet");
if (pfnOverclockGpuLockGet)
{
result = pfnOverclockGpuLockGet(hDeviceHandle, pVfPair);
@@ -3263,9 +3869,11 @@ ctlOverclockGpuLockSet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockGpuLockSet_t pfnOverclockGpuLockSet = (ctl_pfnOverclockGpuLockSet_t)GetProcAddress(hinstLib, "ctlOverclockGpuLockSet");
+ ctl_pfnOverclockGpuLockSet_t pfnOverclockGpuLockSet = (ctl_pfnOverclockGpuLockSet_t)GetProcAddress(hinstLibPtr, "ctlOverclockGpuLockSet");
if (pfnOverclockGpuLockSet)
{
result = pfnOverclockGpuLockSet(hDeviceHandle, vFPair);
@@ -3301,9 +3909,11 @@ ctlOverclockVramFrequencyOffsetGet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockVramFrequencyOffsetGet_t pfnOverclockVramFrequencyOffsetGet = (ctl_pfnOverclockVramFrequencyOffsetGet_t)GetProcAddress(hinstLib, "ctlOverclockVramFrequencyOffsetGet");
+ ctl_pfnOverclockVramFrequencyOffsetGet_t pfnOverclockVramFrequencyOffsetGet = (ctl_pfnOverclockVramFrequencyOffsetGet_t)GetProcAddress(hinstLibPtr, "ctlOverclockVramFrequencyOffsetGet");
if (pfnOverclockVramFrequencyOffsetGet)
{
result = pfnOverclockVramFrequencyOffsetGet(hDeviceHandle, pOcFrequencyOffset);
@@ -3374,9 +3984,11 @@ ctlOverclockVramFrequencyOffsetSet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockVramFrequencyOffsetSet_t pfnOverclockVramFrequencyOffsetSet = (ctl_pfnOverclockVramFrequencyOffsetSet_t)GetProcAddress(hinstLib, "ctlOverclockVramFrequencyOffsetSet");
+ ctl_pfnOverclockVramFrequencyOffsetSet_t pfnOverclockVramFrequencyOffsetSet = (ctl_pfnOverclockVramFrequencyOffsetSet_t)GetProcAddress(hinstLibPtr, "ctlOverclockVramFrequencyOffsetSet");
if (pfnOverclockVramFrequencyOffsetSet)
{
result = pfnOverclockVramFrequencyOffsetSet(hDeviceHandle, ocFrequencyOffset);
@@ -3447,9 +4059,11 @@ ctlOverclockVramVoltageOffsetGet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockVramVoltageOffsetGet_t pfnOverclockVramVoltageOffsetGet = (ctl_pfnOverclockVramVoltageOffsetGet_t)GetProcAddress(hinstLib, "ctlOverclockVramVoltageOffsetGet");
+ ctl_pfnOverclockVramVoltageOffsetGet_t pfnOverclockVramVoltageOffsetGet = (ctl_pfnOverclockVramVoltageOffsetGet_t)GetProcAddress(hinstLibPtr, "ctlOverclockVramVoltageOffsetGet");
if (pfnOverclockVramVoltageOffsetGet)
{
result = pfnOverclockVramVoltageOffsetGet(hDeviceHandle, pVoltage);
@@ -3487,9 +4101,11 @@ ctlOverclockVramVoltageOffsetSet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockVramVoltageOffsetSet_t pfnOverclockVramVoltageOffsetSet = (ctl_pfnOverclockVramVoltageOffsetSet_t)GetProcAddress(hinstLib, "ctlOverclockVramVoltageOffsetSet");
+ ctl_pfnOverclockVramVoltageOffsetSet_t pfnOverclockVramVoltageOffsetSet = (ctl_pfnOverclockVramVoltageOffsetSet_t)GetProcAddress(hinstLibPtr, "ctlOverclockVramVoltageOffsetSet");
if (pfnOverclockVramVoltageOffsetSet)
{
result = pfnOverclockVramVoltageOffsetSet(hDeviceHandle, voltage);
@@ -3527,9 +4143,11 @@ ctlOverclockPowerLimitGet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockPowerLimitGet_t pfnOverclockPowerLimitGet = (ctl_pfnOverclockPowerLimitGet_t)GetProcAddress(hinstLib, "ctlOverclockPowerLimitGet");
+ ctl_pfnOverclockPowerLimitGet_t pfnOverclockPowerLimitGet = (ctl_pfnOverclockPowerLimitGet_t)GetProcAddress(hinstLibPtr, "ctlOverclockPowerLimitGet");
if (pfnOverclockPowerLimitGet)
{
result = pfnOverclockPowerLimitGet(hDeviceHandle, pSustainedPowerLimit);
@@ -3567,9 +4185,11 @@ ctlOverclockPowerLimitSet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockPowerLimitSet_t pfnOverclockPowerLimitSet = (ctl_pfnOverclockPowerLimitSet_t)GetProcAddress(hinstLib, "ctlOverclockPowerLimitSet");
+ ctl_pfnOverclockPowerLimitSet_t pfnOverclockPowerLimitSet = (ctl_pfnOverclockPowerLimitSet_t)GetProcAddress(hinstLibPtr, "ctlOverclockPowerLimitSet");
if (pfnOverclockPowerLimitSet)
{
result = pfnOverclockPowerLimitSet(hDeviceHandle, sustainedPowerLimit);
@@ -3604,9 +4224,11 @@ ctlOverclockTemperatureLimitGet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockTemperatureLimitGet_t pfnOverclockTemperatureLimitGet = (ctl_pfnOverclockTemperatureLimitGet_t)GetProcAddress(hinstLib, "ctlOverclockTemperatureLimitGet");
+ ctl_pfnOverclockTemperatureLimitGet_t pfnOverclockTemperatureLimitGet = (ctl_pfnOverclockTemperatureLimitGet_t)GetProcAddress(hinstLibPtr, "ctlOverclockTemperatureLimitGet");
if (pfnOverclockTemperatureLimitGet)
{
result = pfnOverclockTemperatureLimitGet(hDeviceHandle, pTemperatureLimit);
@@ -3641,9 +4263,11 @@ ctlOverclockTemperatureLimitSet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnOverclockTemperatureLimitSet_t pfnOverclockTemperatureLimitSet = (ctl_pfnOverclockTemperatureLimitSet_t)GetProcAddress(hinstLib, "ctlOverclockTemperatureLimitSet");
+ ctl_pfnOverclockTemperatureLimitSet_t pfnOverclockTemperatureLimitSet = (ctl_pfnOverclockTemperatureLimitSet_t)GetProcAddress(hinstLibPtr, "ctlOverclockTemperatureLimitSet");
if (pfnOverclockTemperatureLimitSet)
{
result = pfnOverclockTemperatureLimitSet(hDeviceHandle, temperatureLimit);
@@ -3679,9 +4303,11 @@ ctlPowerTelemetryGet(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnPowerTelemetryGet_t pfnPowerTelemetryGet = (ctl_pfnPowerTelemetryGet_t)GetProcAddress(hinstLib, "ctlPowerTelemetryGet");
+ ctl_pfnPowerTelemetryGet_t pfnPowerTelemetryGet = (ctl_pfnPowerTelemetryGet_t)GetProcAddress(hinstLibPtr, "ctlPowerTelemetryGet");
if (pfnPowerTelemetryGet)
{
result = pfnPowerTelemetryGet(hDeviceHandle, pTelemetryInfo);
@@ -3692,6 +4318,46 @@ ctlPowerTelemetryGet(
}
+/**
+* @brief Reset all Overclock Settings to stock
+*
+* @details
+* - Reset all Overclock setting to default using single API call
+* - This request resets any changes made to GpuFrequencyOffset,
+* GpuVoltageOffset, PowerLimit, TemperatureLimit, GpuLock
+* - This Doesn't reset any Fan Curve Changes. It can be reset using
+* ctlFanSetDefaultMode
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockResetToDefault(
+ ctl_device_adapter_handle_t hDeviceHandle ///< [in][release] Handle to display adapter
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctl_pfnOverclockResetToDefault_t pfnOverclockResetToDefault = (ctl_pfnOverclockResetToDefault_t)GetProcAddress(hinstLibPtr, "ctlOverclockResetToDefault");
+ if (pfnOverclockResetToDefault)
+ {
+ result = pfnOverclockResetToDefault(hDeviceHandle);
+ }
+ }
+
+ return result;
+}
+
+
/**
* @brief Get PCI properties - address, max speed
*
@@ -3717,9 +4383,11 @@ ctlPciGetProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnPciGetProperties_t pfnPciGetProperties = (ctl_pfnPciGetProperties_t)GetProcAddress(hinstLib, "ctlPciGetProperties");
+ ctl_pfnPciGetProperties_t pfnPciGetProperties = (ctl_pfnPciGetProperties_t)GetProcAddress(hinstLibPtr, "ctlPciGetProperties");
if (pfnPciGetProperties)
{
result = pfnPciGetProperties(hDAhandle, pProperties);
@@ -3755,9 +4423,11 @@ ctlPciGetState(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnPciGetState_t pfnPciGetState = (ctl_pfnPciGetState_t)GetProcAddress(hinstLib, "ctlPciGetState");
+ ctl_pfnPciGetState_t pfnPciGetState = (ctl_pfnPciGetState_t)GetProcAddress(hinstLibPtr, "ctlPciGetState");
if (pfnPciGetState)
{
result = pfnPciGetState(hDAhandle, pState);
@@ -3803,9 +4473,11 @@ ctlEnumPowerDomains(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEnumPowerDomains_t pfnEnumPowerDomains = (ctl_pfnEnumPowerDomains_t)GetProcAddress(hinstLib, "ctlEnumPowerDomains");
+ ctl_pfnEnumPowerDomains_t pfnEnumPowerDomains = (ctl_pfnEnumPowerDomains_t)GetProcAddress(hinstLibPtr, "ctlEnumPowerDomains");
if (pfnEnumPowerDomains)
{
result = pfnEnumPowerDomains(hDAhandle, pCount, phPower);
@@ -3841,9 +4513,11 @@ ctlPowerGetProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnPowerGetProperties_t pfnPowerGetProperties = (ctl_pfnPowerGetProperties_t)GetProcAddress(hinstLib, "ctlPowerGetProperties");
+ ctl_pfnPowerGetProperties_t pfnPowerGetProperties = (ctl_pfnPowerGetProperties_t)GetProcAddress(hinstLibPtr, "ctlPowerGetProperties");
if (pfnPowerGetProperties)
{
result = pfnPowerGetProperties(hPower, pProperties);
@@ -3880,9 +4554,11 @@ ctlPowerGetEnergyCounter(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnPowerGetEnergyCounter_t pfnPowerGetEnergyCounter = (ctl_pfnPowerGetEnergyCounter_t)GetProcAddress(hinstLib, "ctlPowerGetEnergyCounter");
+ ctl_pfnPowerGetEnergyCounter_t pfnPowerGetEnergyCounter = (ctl_pfnPowerGetEnergyCounter_t)GetProcAddress(hinstLibPtr, "ctlPowerGetEnergyCounter");
if (pfnPowerGetEnergyCounter)
{
result = pfnPowerGetEnergyCounter(hPower, pEnergy);
@@ -3916,9 +4592,11 @@ ctlPowerGetLimits(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnPowerGetLimits_t pfnPowerGetLimits = (ctl_pfnPowerGetLimits_t)GetProcAddress(hinstLib, "ctlPowerGetLimits");
+ ctl_pfnPowerGetLimits_t pfnPowerGetLimits = (ctl_pfnPowerGetLimits_t)GetProcAddress(hinstLibPtr, "ctlPowerGetLimits");
if (pfnPowerGetLimits)
{
result = pfnPowerGetLimits(hPower, pPowerLimits);
@@ -3956,9 +4634,11 @@ ctlPowerSetLimits(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnPowerSetLimits_t pfnPowerSetLimits = (ctl_pfnPowerSetLimits_t)GetProcAddress(hinstLib, "ctlPowerSetLimits");
+ ctl_pfnPowerSetLimits_t pfnPowerSetLimits = (ctl_pfnPowerSetLimits_t)GetProcAddress(hinstLibPtr, "ctlPowerSetLimits");
if (pfnPowerSetLimits)
{
result = pfnPowerSetLimits(hPower, pPowerLimits);
@@ -4004,9 +4684,11 @@ ctlEnumTemperatureSensors(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnEnumTemperatureSensors_t pfnEnumTemperatureSensors = (ctl_pfnEnumTemperatureSensors_t)GetProcAddress(hinstLib, "ctlEnumTemperatureSensors");
+ ctl_pfnEnumTemperatureSensors_t pfnEnumTemperatureSensors = (ctl_pfnEnumTemperatureSensors_t)GetProcAddress(hinstLibPtr, "ctlEnumTemperatureSensors");
if (pfnEnumTemperatureSensors)
{
result = pfnEnumTemperatureSensors(hDAhandle, pCount, phTemperature);
@@ -4042,9 +4724,11 @@ ctlTemperatureGetProperties(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnTemperatureGetProperties_t pfnTemperatureGetProperties = (ctl_pfnTemperatureGetProperties_t)GetProcAddress(hinstLib, "ctlTemperatureGetProperties");
+ ctl_pfnTemperatureGetProperties_t pfnTemperatureGetProperties = (ctl_pfnTemperatureGetProperties_t)GetProcAddress(hinstLibPtr, "ctlTemperatureGetProperties");
if (pfnTemperatureGetProperties)
{
result = pfnTemperatureGetProperties(hTemperature, pProperties);
@@ -4081,9 +4765,11 @@ ctlTemperatureGetState(
ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
- if (NULL != hinstLib)
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
{
- ctl_pfnTemperatureGetState_t pfnTemperatureGetState = (ctl_pfnTemperatureGetState_t)GetProcAddress(hinstLib, "ctlTemperatureGetState");
+ ctl_pfnTemperatureGetState_t pfnTemperatureGetState = (ctl_pfnTemperatureGetState_t)GetProcAddress(hinstLibPtr, "ctlTemperatureGetState");
if (pfnTemperatureGetState)
{
result = pfnTemperatureGetState(hTemperature, pTemperature);
diff --git a/IntelPresentMon/ControlLib/ctlpvttempWrapper.cpp b/IntelPresentMon/ControlLib/ctlpvttempWrapper.cpp
new file mode 100644
index 00000000..f543502b
--- /dev/null
+++ b/IntelPresentMon/ControlLib/ctlpvttempWrapper.cpp
@@ -0,0 +1,659 @@
+//===========================================================================
+//Copyright (C) 2022-23 Intel Corporation
+//
+//
+//
+//SPDX-License-Identifier: MIT
+//--------------------------------------------------------------------------
+
+/**
+ *
+ * @file ctlpvttemp_api.cpp
+ * @version v1-r1
+ *
+ */
+
+// Note: UWP applications should have defined WINDOWS_UWP in their compiler settings
+// Also at this point, it's easier by not enabling pre-compiled option to compile this file
+// Not all functionalities are tested for a UWP application
+
+#include
+#include
+#include
+
+//#define CTL_APIEXPORT
+
+#include "igcl_api.h"
+#include "ctlpvttemp_api.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Implementation of wrapper functions
+//
+HINSTANCE GetLoaderHandle(void);
+
+
+/**
+* @brief Get the Current Overclock GPU Frequency Offset
+*
+* @details
+* - Determine the current frequency offset in effect (refer to
+* ::ctlOverclockGpuFrequencyOffsetSetV2() for details).
+* - The unit of the value returned is given in
+* ::ctl_oc_properties_t::gpuFrequencyOffset::units returned from
+* ::ctlOverclockGetProperties()
+* - The unit of the value returned can be different for different
+* generation of graphics product
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pOcFrequencyOffset`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockGpuFrequencyOffsetGetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double* pOcFrequencyOffset ///< [in,out] Current GPU Overclock Frequency Offset in units given in
+ ///< ::ctl_oc_properties_t::gpuFrequencyOffset::units returned from
+ ///< ::ctlOverclockGetProperties()
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockGpuFrequencyOffsetGetV2_t pfnOverclockGpuFrequencyOffsetGetV2 = (ctlpvttemp_$xOverclockGpuFrequencyOffsetGetV2_t)GetProcAddress(hinstLibPtr, "ctlOverclockGpuFrequencyOffsetGetV2");
+ if (pfnOverclockGpuFrequencyOffsetGetV2)
+ {
+ result = pfnOverclockGpuFrequencyOffsetGetV2(hDeviceHandle, pOcFrequencyOffset);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Set the Overclock Frequency Offset for the GPU
+*
+* @details
+* - The purpose of this function is to increase/decrease the frequency
+* offset at which typical workloads will run within the same thermal
+* budget.
+* - The frequency offset is expressed in units given in
+* ::ctl_oc_properties_t::gpuFrequencyOffset::units returned from
+* ::ctlOverclockGetProperties()
+* - The actual operating frequency for each workload is not guaranteed to
+* change exactly by the specified offset.
+* - For positive frequency offsets, the factory maximum frequency may
+* increase by up to the specified amount.
+* - Specifying large values for the frequency offset can lead to
+* instability. It is recommended that changes are made in small
+* increments and stability/performance measured running intense GPU
+* workloads before increasing further.
+* - This setting is not persistent through system reboots or driver
+* resets/hangs. It is up to the overclock application to reapply the
+* settings in those cases.
+* - This setting can cause system/device instability. It is up to the
+* overclock application to detect if the system has rebooted
+* unexpectedly or the device was restarted. When this occurs, the
+* application should not reapply the overclock settings automatically
+* but instead return to previously known good settings or notify the
+* user that the settings are not being applied.
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockGpuFrequencyOffsetSetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double ocFrequencyOffset ///< [in] The GPU Overclocking Frequency Offset Desired in units given in
+ ///< ::ctl_oc_properties_t::gpuFrequencyOffset::units returned from
+ ///< ::ctlOverclockGetProperties()
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockGpuFrequencyOffsetSetV2_t pfnOverclockGpuFrequencyOffsetSetV2 = (ctlpvttemp_$xOverclockGpuFrequencyOffsetSetV2_t)GetProcAddress(hinstLibPtr, "ctlOverclockGpuFrequencyOffsetSetV2");
+ if (pfnOverclockGpuFrequencyOffsetSetV2)
+ {
+ result = pfnOverclockGpuFrequencyOffsetSetV2(hDeviceHandle, ocFrequencyOffset);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Get the Current Overclock Voltage Offset for the GPU
+*
+* @details
+* - Determine the current maximum voltage offset in effect on the hardware
+* (refer to ::ctlOverclockGpuMaxVoltageOffsetSetV2 for details).
+* - The unit of the value returned is given in
+* ::ctl_oc_properties_t::gpuVoltageOffset::units returned from
+* ::ctlOverclockGetProperties()
+* - The unit of the value returned can be different for different
+* generation of graphics product
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pOcMaxVoltageOffset`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockGpuMaxVoltageOffsetGetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double* pOcMaxVoltageOffset ///< [in,out] Current Overclock GPU Voltage Offset in Units given in
+ ///< ::ctl_oc_properties_t::gpuVoltageOffset::units returned from
+ ///< ::ctlOverclockGetProperties()
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockGpuMaxVoltageOffsetGetV2_t pfnOverclockGpuMaxVoltageOffsetGetV2 = (ctlpvttemp_$xOverclockGpuMaxVoltageOffsetGetV2_t)GetProcAddress(hinstLibPtr, "ctlOverclockGpuMaxVoltageOffsetGetV2");
+ if (pfnOverclockGpuMaxVoltageOffsetGetV2)
+ {
+ result = pfnOverclockGpuMaxVoltageOffsetGetV2(hDeviceHandle, pOcMaxVoltageOffset);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Set the Overclock Voltage Offset for the GPU
+*
+* @details
+* - The purpose of this function is to attempt to run the GPU up to higher
+* voltages beyond the part warrantee limits. This can permit running at
+* even higher frequencies than can be obtained using the frequency
+* offset setting, but at the risk of reducing the lifetime of the part.
+* - The voltage offset is expressed in units given in
+* ::ctl_oc_properties_t::gpuVoltageOffset::units returned from
+* ::ctlOverclockGetProperties()
+* - The overclock waiver must be set before calling this function
+* otherwise error will be returned.
+* - There is no guarantee that a workload can operate at the higher
+* frequencies permitted by this setting. Significantly more heat will be
+* generated at these high frequencies/voltages which will necessitate a
+* good cooling solution.
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockGpuMaxVoltageOffsetSetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double ocMaxVoltageOffset ///< [in] The Overclocking Maximum Voltage Desired in units given in
+ ///< ::ctl_oc_properties_t::gpuVoltageOffset::units returned from
+ ///< ::ctlOverclockGetProperties()
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockGpuMaxVoltageOffsetSetV2_t pfnOverclockGpuMaxVoltageOffsetSetV2 = (ctlpvttemp_$xOverclockGpuMaxVoltageOffsetSetV2_t)GetProcAddress(hinstLibPtr, "ctlOverclockGpuMaxVoltageOffsetSetV2");
+ if (pfnOverclockGpuMaxVoltageOffsetSetV2)
+ {
+ result = pfnOverclockGpuMaxVoltageOffsetSetV2(hDeviceHandle, ocMaxVoltageOffset);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Get the current Overclock Vram Memory Speed
+*
+* @details
+* - The purpose of this function is to return the current VRAM Memory
+* Speed
+* - The unit of the value returned is given in
+* ctl_oc_properties_t::vramMemSpeedLimit::units returned from
+* ::ctlOverclockGetProperties()
+* - The unit of the value returned can be different for different
+* generation of graphics product
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pOcVramMemSpeedLimit`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockVramMemSpeedLimitGetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double* pOcVramMemSpeedLimit ///< [in,out] The current VRAM Memory Speed in units given in
+ ///< ctl_oc_properties_t::vramMemSpeedLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockVramMemSpeedLimitGetV2_t pfnOverclockVramMemSpeedLimitGetV2 = (ctlpvttemp_$xOverclockVramMemSpeedLimitGetV2_t)GetProcAddress(hinstLibPtr, "ctlOverclockVramMemSpeedLimitGetV2");
+ if (pfnOverclockVramMemSpeedLimitGetV2)
+ {
+ result = pfnOverclockVramMemSpeedLimitGetV2(hDeviceHandle, pOcVramMemSpeedLimit);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Set the desired Overclock Vram Memory Speed
+*
+* @details
+* - The purpose of this function is to increase/decrease the Speed of
+* VRAM.
+* - The Memory Speed is expressed in units given in
+* ctl_oc_properties_t::vramMemSpeedLimit::units returned from
+* ::ctlOverclockGetProperties() with a minimum step size given by
+* ::ctlOverclockGetProperties().
+* - The actual Memory Speed for each workload is not guaranteed to change
+* exactly by the specified offset.
+* - This setting is not persistent through system reboots or driver
+* resets/hangs. It is up to the overclock application to reapply the
+* settings in those cases.
+* - This setting can cause system/device instability. It is up to the
+* overclock application to detect if the system has rebooted
+* unexpectedly or the device was restarted. When this occurs, the
+* application should not reapply the overclock settings automatically
+* but instead return to previously known good settings or notify the
+* user that the settings are not being applied.
+* - If the memory controller doesn't support changes to memory speed on
+* the fly, one of the following return codes will be given:
+* - CTL_RESULT_ERROR_RESET_DEVICE_REQUIRED: The requested memory overclock
+* will be applied when the device is reset or the system is rebooted. In
+* this case, the overclock software should check if the overclock
+* request was applied after the reset/reboot. If it was and when the
+* overclock application shuts down gracefully and if the overclock
+* application wants the setting to be persistent, the application should
+* request the same overclock settings again so that they will be applied
+* on the next reset/reboot. If this is not done, then every time the
+* device is reset and overclock is requested, the device needs to be
+* reset a second time.
+* - CTL_RESULT_ERROR_FULL_REBOOT_REQUIRED: The requested memory overclock
+* will be applied when the system is rebooted. In this case, the
+* overclock software should check if the overclock request was applied
+* after the reboot. If it was and when the overclock application shuts
+* down gracefully and if the overclock application wants the setting to
+* be persistent, the application should request the same overclock
+* settings again so that they will be applied on the next reset/reboot.
+* If this is not done and the overclock setting is requested after the
+* reboot has occurred, a second reboot will be required.
+* - CTL_RESULT_ERROR_UNSUPPORTED_FEATURE: The Memory Speed Get / Set
+* Feature is currently not available or Unsupported in current platform
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockVramMemSpeedLimitSetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double ocVramMemSpeedLimit ///< [in] The desired Memory Speed in units given in
+ ///< ctl_oc_properties_t::vramMemSpeedLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockVramMemSpeedLimitSetV2_t pfnOverclockVramMemSpeedLimitSetV2 = (ctlpvttemp_$xOverclockVramMemSpeedLimitSetV2_t)GetProcAddress(hinstLibPtr, "ctlOverclockVramMemSpeedLimitSetV2");
+ if (pfnOverclockVramMemSpeedLimitSetV2)
+ {
+ result = pfnOverclockVramMemSpeedLimitSetV2(hDeviceHandle, ocVramMemSpeedLimit);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Get the Current Sustained power limit
+*
+* @details
+* - The purpose of this function is to read the current sustained power
+* limit.
+* - The unit of the value returned is given in
+* ::ctl_oc_properties_t::powerLimit::units returned from
+* ::ctlOverclockGetProperties()
+* - The unit of the value returned can be different for different
+* generation of graphics product
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pSustainedPowerLimit`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockPowerLimitGetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double* pSustainedPowerLimit ///< [in,out] The current Sustained Power limit in Units given in
+ ///< ::ctl_oc_properties_t::powerLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockPowerLimitGetV2_t pfnOverclockPowerLimitGetV2 = (ctlpvttemp_$xOverclockPowerLimitGetV2_t)GetProcAddress(hinstLibPtr, "ctlOverclockPowerLimitGetV2");
+ if (pfnOverclockPowerLimitGetV2)
+ {
+ result = pfnOverclockPowerLimitGetV2(hDeviceHandle, pSustainedPowerLimit);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Set the Sustained power limit
+*
+* @details
+* - The purpose of this function is to set the maximum sustained power
+* limit. If the average GPU power averaged over a few seconds exceeds
+* this value, the frequency of the GPU will be throttled.
+* - Set a value of 0 to disable this power limit. In this case, the GPU
+* frequency will not throttle due to average power but may hit other
+* limits.
+* - The unit of the PowerLimit to be set is given in
+* ::ctl_oc_properties_t::powerLimit::units returned from
+* ::ctlOverclockGetProperties()
+* - The unit of the value returned can be different for different
+* generation of graphics product
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockPowerLimitSetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double sustainedPowerLimit ///< [in] The desired sustained power limit in Units given in
+ ///< ::ctl_oc_properties_t::powerLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockPowerLimitSetV2_t pfnOverclockPowerLimitSetV2 = (ctlpvttemp_$xOverclockPowerLimitSetV2_t)GetProcAddress(hinstLibPtr, "ctlOverclockPowerLimitSetV2");
+ if (pfnOverclockPowerLimitSetV2)
+ {
+ result = pfnOverclockPowerLimitSetV2(hDeviceHandle, sustainedPowerLimit);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Get the current temperature limit
+*
+* @details
+* - The purpose of this function is to read the current thermal limit used
+* for Overclocking
+* - The unit of the value returned is given in
+* ::ctl_oc_properties_t::temperatureLimit::units returned from
+* ::ctlOverclockGetProperties()
+* - The unit of the value returned can be different for different
+* generation of graphics product
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pTemperatureLimit`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockTemperatureLimitGetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double* pTemperatureLimit ///< [in,out] The current temperature limit in Units given in
+ ///< ::ctl_oc_properties_t::temperatureLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockTemperatureLimitGetV2_t pfnOverclockTemperatureLimitGetV2 = (ctlpvttemp_$xOverclockTemperatureLimitGetV2_t)GetProcAddress(hinstLibPtr, "ctlOverclockTemperatureLimitGetV2");
+ if (pfnOverclockTemperatureLimitGetV2)
+ {
+ result = pfnOverclockTemperatureLimitGetV2(hDeviceHandle, pTemperatureLimit);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Set the temperature limit
+*
+* @details
+* - The purpose of this function is to change the maximum thermal limit.
+* When the GPU temperature exceeds this value, the GPU frequency will be
+* throttled.
+* - The unit of the value to be set is given in
+* ::ctl_oc_properties_t::temperatureLimit::units returned from
+* ::ctlOverclockGetProperties()
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceHandle`
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockTemperatureLimitSetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double temperatureLimit ///< [in] The desired temperature limit in Units given in
+ ///< ctl_oc_properties_t::temperatureLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockTemperatureLimitSetV2_t pfnOverclockTemperatureLimitSetV2 = (ctlpvttemp_$xOverclockTemperatureLimitSetV2_t)GetProcAddress(hinstLibPtr, "ctlOverclockTemperatureLimitSetV2");
+ if (pfnOverclockTemperatureLimitSetV2)
+ {
+ result = pfnOverclockTemperatureLimitSetV2(hDeviceHandle, temperatureLimit);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Read VF Curve
+*
+* @details
+* - Read the Voltage-Frequency Curve
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceAdapter`
+* - CTL_RESULT_ERROR_INVALID_ENUMERATION
+* + `::CTL_VF_CURVE_TYPE_LIVE < VFCurveType`
+* + `::CTL_VF_CURVE_DETAILS_ELABORATE < VFCurveDetail`
+* - CTL_RESULT_ERROR_UNKNOWN - "Unknown Error"
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockReadVFCurve(
+ ctl_device_adapter_handle_t hDeviceAdapter, ///< [in][release] Handle to control device adapter
+ ctl_vf_curve_type_t VFCurveType, ///< [in] Type of Curve to read
+ ctl_vf_curve_details_t VFCurveDetail, ///< [in] Detail of Curve to read
+ uint32_t * pNumPoints, ///< [in][out] Number of points in the custom VF curve. If the NumPoints is
+ ///< zero, then the api will update the value with total number of Points
+ ///< based on requested VFCurveType and VFCurveDetail. If the NumPoints is
+ ///< non-zero, then the api will read and update the VF points in
+ ///< pVFCurveTable buffer provided. If the NumPoints doesn't match what the
+ ///< api returned in the first call, it will return an error.
+ ctl_voltage_frequency_point_t * pVFCurveTable ///< [in][out] Pointer to array of VF points, to copy the VF curve being
+ ///< read
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockReadVFCurve_t pfnOverclockReadVFCurve = (ctlpvttemp_$xOverclockReadVFCurve_t)GetProcAddress(hinstLibPtr, "ctlOverclockReadVFCurve");
+ if (pfnOverclockReadVFCurve)
+ {
+ result = pfnOverclockReadVFCurve(hDeviceAdapter, VFCurveType, VFCurveDetail, pNumPoints, pVFCurveTable);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Write Custom VF curve
+*
+* @details
+* - Modify the Voltage-Frequency Curve used by GPU
+* - Valid Voltage-Frequency Curve shall have Voltage and Frequency Points
+* in increasing order
+* - Recommended to create Custom V-F Curve from reading Current V-F Curve
+* using ::ctlOverclockReadVFCurve (Read-Modify-Write)
+* - If Custom V-F curve write request is Successful, the Applied VF Curve
+* might be slightly different than what is originally requested,
+* recommended to update the UI by reading the V-F curve again using
+* ctlOverclockReadVFCurve (with ctl_vf_curve_type_t::LIVE as input)
+* - The overclock waiver must be set before calling this function
+* otherwise error will be returned.
+*
+* @returns
+* - CTL_RESULT_SUCCESS
+* - CTL_RESULT_ERROR_UNINITIALIZED
+* - CTL_RESULT_ERROR_DEVICE_LOST
+* - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+* + `nullptr == hDeviceAdapter`
+* - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+* + `nullptr == pCustomVFCurveTable`
+* - CTL_RESULT_ERROR_UNKNOWN - "Unknown Error"
+*/
+ctl_result_t CTL_APICALL
+ctlOverclockWriteCustomVFCurve(
+ ctl_device_adapter_handle_t hDeviceAdapter, ///< [in][release] Handle to control device adapter
+ uint32_t NumPoints, ///< [in] Number of points in the custom VF curve
+ ctl_voltage_frequency_point_t* pCustomVFCurveTable ///< [in] Pointer to an array of VF Points containing 'NumPoints' Custom VF
+ ///< points
+ )
+{
+ ctl_result_t result = CTL_RESULT_ERROR_NOT_INITIALIZED;
+
+
+ HINSTANCE hinstLibPtr = GetLoaderHandle();
+
+ if (NULL != hinstLibPtr)
+ {
+ ctlpvttemp_$xOverclockWriteCustomVFCurve_t pfnOverclockWriteCustomVFCurve = (ctlpvttemp_$xOverclockWriteCustomVFCurve_t)GetProcAddress(hinstLibPtr, "ctlOverclockWriteCustomVFCurve");
+ if (pfnOverclockWriteCustomVFCurve)
+ {
+ result = pfnOverclockWriteCustomVFCurve(hDeviceAdapter, NumPoints, pCustomVFCurveTable);
+ }
+ }
+
+ return result;
+}
+
+
+//
+// End of wrapper function implementation
+//
+/////////////////////////////////////////////////////////////////////////////////
diff --git a/IntelPresentMon/ControlLib/ctlpvttemp_api.h b/IntelPresentMon/ControlLib/ctlpvttemp_api.h
new file mode 100644
index 00000000..f506bc66
--- /dev/null
+++ b/IntelPresentMon/ControlLib/ctlpvttemp_api.h
@@ -0,0 +1,758 @@
+//===========================================================================
+// Copyright (C) 2022-23 Intel Corporation
+// This software and the related documents are Intel copyrighted materials, and
+// your use of them is governed by the express license under which they were
+// provided to you ("License"). Unless the License provides otherwise, you may
+// not use, modify, copy, publish, distribute, disclose or transmit this software
+// or the related documents without Intel's prior written permission. This software
+// and the related documents are provided as is, with no express or implied
+// warranties, other than those that are expressly stated in the License.
+//--------------------------------------------------------------------------
+
+/**
+ *
+ * @file ctlpvttemp_api.h
+ * @version v1-r1
+ *
+ */
+#ifndef _CTLPVTTEMP_API_H
+#define _CTLPVTTEMP_API_H
+#if defined(__cplusplus)
+#pragma once
+#endif
+
+// 'core' API headers
+#include "igcl_api.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+// Intel 'ctlApi'Pvt private common types
+#if !defined(__GNUC__)
+#pragma region common_private_temp
+#endif
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Reuse ctl_result_t as the only type of return error
+typedef ctl_result_t ctl_result_t;
+
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CTL_APICALL
+#if defined(_WIN32)
+/// @brief Calling convention for all API functions
+#define CTL_APICALL __cdecl
+#else
+#define CTL_APICALL
+#endif // defined(_WIN32)
+#endif // CTL_APICALL
+
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CTL_APIEXPORT
+#if defined(_WIN32)
+/// @brief Microsoft-specific dllexport storage-class attribute
+#define CTL_APIEXPORT __declspec(dllexport)
+#else
+#define CTL_APIEXPORT
+#endif // defined(_WIN32)
+#endif // CTL_APIEXPORT
+
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CTL_DLLEXPORT
+#if defined(_WIN32)
+/// @brief Microsoft-specific dllexport storage-class attribute
+#define CTL_DLLEXPORT __declspec(dllexport)
+#endif // defined(_WIN32)
+#endif // CTL_DLLEXPORT
+
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CTL_DLLEXPORT
+#if __GNUC__ >= 4
+/// @brief GCC-specific dllexport storage-class attribute
+#define CTL_DLLEXPORT __attribute__ ((visibility ("default")))
+#else
+#define CTL_DLLEXPORT
+#endif // __GNUC__ >= 4
+#endif // CTL_DLLEXPORT
+
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CTL_MAKE_VERSION
+/// @brief Test private macro
+#define CTL_MAKE_VERSION( _major, _minor ) (( _major << 16 )|( _minor & 0x0000ffff))
+#endif // CTL_MAKE_VERSION
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief VF Curve Detail
+typedef enum _ctl_vf_curve_details_t
+{
+ CTL_VF_CURVE_DETAILS_SIMPLIFIED = 0, ///< Read minimum num of VF points for simplified VF curve view
+ CTL_VF_CURVE_DETAILS_MEDIUM = 1, ///< Read medium num of VF points for more points than simplified view
+ CTL_VF_CURVE_DETAILS_ELABORATE = 2, ///< Read Maximum num of VF points for detailed VF curve View
+ CTL_VF_CURVE_DETAILS_MAX
+
+} ctl_vf_curve_details_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief VF Curve type
+typedef enum _ctl_vf_curve_type_t
+{
+ CTL_VF_CURVE_TYPE_STOCK = 0, ///< Read default VF curve
+ CTL_VF_CURVE_TYPE_LIVE = 1, ///< Read Live VF Curve
+ CTL_VF_CURVE_TYPE_MAX
+
+} ctl_vf_curve_type_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Overclock Voltage Frequency Point
+typedef struct _ctl_voltage_frequency_point_t
+{
+ uint32_t Voltage; ///< [in][out] in milliVolts
+ uint32_t Frequency; ///< [in][out] in MHz
+
+} ctl_voltage_frequency_point_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Overclock properties
+typedef struct _ctl_oc_properties2_t
+{
+ uint32_t Size; ///< [in] size of this structure
+ uint8_t Version; ///< [in] version of this structure
+ bool bSupported; ///< [out] Indicates if the adapter supports overclocking.
+ ctl_oc_control_info_t gpuFrequencyOffset; ///< [out] related to function ::ctlOverclockGpuFrequencyOffsetSetV2
+ ctl_oc_control_info_t gpuVoltageOffset; ///< [out] related to function ::ctlOverclockGpuMaxVoltageOffsetSetV2
+ ctl_oc_control_info_t vramFrequencyOffset; ///< [out] Property Field Deprecated / No Longer Supported
+ ctl_oc_control_info_t vramVoltageOffset; ///< [out] Property Field Deprecated / No Longer Supported
+ ctl_oc_control_info_t powerLimit; ///< [out] related to function ::ctlOverclockPowerLimitSetV2
+ ctl_oc_control_info_t temperatureLimit; ///< [out] related to function ::ctlOverclockTemperatureLimitSetV2
+ ctl_oc_control_info_t vramMemSpeedLimit; ///< [out] related to function ::ctlOverclockVramMemSpeedLimitSetV2
+ ///< Supported only for Version > 0
+ ctl_oc_control_info_t gpuVFCurveVoltageLimit; ///< [out] related to function ::ctlOverclockWriteCustomVFCurve Supported
+ ///< only for Version > 0
+ ctl_oc_control_info_t gpuVFCurveFrequencyLimit; ///< [out] related to function ::ctlOverclockWriteCustomVFCurve Supported
+ ///< only for Version > 0
+
+} ctl_oc_properties2_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get the Current Overclock GPU Frequency Offset
+///
+/// @details
+/// - Determine the current frequency offset in effect (refer to
+/// ::ctlOverclockGpuFrequencyOffsetSetV2() for details).
+/// - The unit of the value returned is given in
+/// ::ctl_oc_properties_t::gpuFrequencyOffset::units returned from
+/// ::ctlOverclockGetProperties()
+/// - The unit of the value returned can be different for different
+/// generation of graphics product
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pOcFrequencyOffset`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockGpuFrequencyOffsetGetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double* pOcFrequencyOffset ///< [in,out] Current GPU Overclock Frequency Offset in units given in
+ ///< ::ctl_oc_properties_t::gpuFrequencyOffset::units returned from
+ ///< ::ctlOverclockGetProperties()
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Set the Overclock Frequency Offset for the GPU
+///
+/// @details
+/// - The purpose of this function is to increase/decrease the frequency
+/// offset at which typical workloads will run within the same thermal
+/// budget.
+/// - The frequency offset is expressed in units given in
+/// ::ctl_oc_properties_t::gpuFrequencyOffset::units returned from
+/// ::ctlOverclockGetProperties()
+/// - The actual operating frequency for each workload is not guaranteed to
+/// change exactly by the specified offset.
+/// - For positive frequency offsets, the factory maximum frequency may
+/// increase by up to the specified amount.
+/// - Specifying large values for the frequency offset can lead to
+/// instability. It is recommended that changes are made in small
+/// increments and stability/performance measured running intense GPU
+/// workloads before increasing further.
+/// - This setting is not persistent through system reboots or driver
+/// resets/hangs. It is up to the overclock application to reapply the
+/// settings in those cases.
+/// - This setting can cause system/device instability. It is up to the
+/// overclock application to detect if the system has rebooted
+/// unexpectedly or the device was restarted. When this occurs, the
+/// application should not reapply the overclock settings automatically
+/// but instead return to previously known good settings or notify the
+/// user that the settings are not being applied.
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockGpuFrequencyOffsetSetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double ocFrequencyOffset ///< [in] The GPU Overclocking Frequency Offset Desired in units given in
+ ///< ::ctl_oc_properties_t::gpuFrequencyOffset::units returned from
+ ///< ::ctlOverclockGetProperties()
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get the Current Overclock Voltage Offset for the GPU
+///
+/// @details
+/// - Determine the current maximum voltage offset in effect on the hardware
+/// (refer to ::ctlOverclockGpuMaxVoltageOffsetSetV2 for details).
+/// - The unit of the value returned is given in
+/// ::ctl_oc_properties_t::gpuVoltageOffset::units returned from
+/// ::ctlOverclockGetProperties()
+/// - The unit of the value returned can be different for different
+/// generation of graphics product
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pOcMaxVoltageOffset`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockGpuMaxVoltageOffsetGetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double* pOcMaxVoltageOffset ///< [in,out] Current Overclock GPU Voltage Offset in Units given in
+ ///< ::ctl_oc_properties_t::gpuVoltageOffset::units returned from
+ ///< ::ctlOverclockGetProperties()
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Set the Overclock Voltage Offset for the GPU
+///
+/// @details
+/// - The purpose of this function is to attempt to run the GPU up to higher
+/// voltages beyond the part warrantee limits. This can permit running at
+/// even higher frequencies than can be obtained using the frequency
+/// offset setting, but at the risk of reducing the lifetime of the part.
+/// - The voltage offset is expressed in units given in
+/// ::ctl_oc_properties_t::gpuVoltageOffset::units returned from
+/// ::ctlOverclockGetProperties()
+/// - The overclock waiver must be set before calling this function
+/// otherwise error will be returned.
+/// - There is no guarantee that a workload can operate at the higher
+/// frequencies permitted by this setting. Significantly more heat will be
+/// generated at these high frequencies/voltages which will necessitate a
+/// good cooling solution.
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockGpuMaxVoltageOffsetSetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double ocMaxVoltageOffset ///< [in] The Overclocking Maximum Voltage Desired in units given in
+ ///< ::ctl_oc_properties_t::gpuVoltageOffset::units returned from
+ ///< ::ctlOverclockGetProperties()
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get the current Overclock Vram Memory Speed
+///
+/// @details
+/// - The purpose of this function is to return the current VRAM Memory
+/// Speed
+/// - The unit of the value returned is given in
+/// ctl_oc_properties_t::vramMemSpeedLimit::units returned from
+/// ::ctlOverclockGetProperties()
+/// - The unit of the value returned can be different for different
+/// generation of graphics product
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pOcVramMemSpeedLimit`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockVramMemSpeedLimitGetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double* pOcVramMemSpeedLimit ///< [in,out] The current VRAM Memory Speed in units given in
+ ///< ctl_oc_properties_t::vramMemSpeedLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Set the desired Overclock Vram Memory Speed
+///
+/// @details
+/// - The purpose of this function is to increase/decrease the Speed of
+/// VRAM.
+/// - The Memory Speed is expressed in units given in
+/// ctl_oc_properties_t::vramMemSpeedLimit::units returned from
+/// ::ctlOverclockGetProperties() with a minimum step size given by
+/// ::ctlOverclockGetProperties().
+/// - The actual Memory Speed for each workload is not guaranteed to change
+/// exactly by the specified offset.
+/// - This setting is not persistent through system reboots or driver
+/// resets/hangs. It is up to the overclock application to reapply the
+/// settings in those cases.
+/// - This setting can cause system/device instability. It is up to the
+/// overclock application to detect if the system has rebooted
+/// unexpectedly or the device was restarted. When this occurs, the
+/// application should not reapply the overclock settings automatically
+/// but instead return to previously known good settings or notify the
+/// user that the settings are not being applied.
+/// - If the memory controller doesn't support changes to memory speed on
+/// the fly, one of the following return codes will be given:
+/// - CTL_RESULT_ERROR_RESET_DEVICE_REQUIRED: The requested memory overclock
+/// will be applied when the device is reset or the system is rebooted. In
+/// this case, the overclock software should check if the overclock
+/// request was applied after the reset/reboot. If it was and when the
+/// overclock application shuts down gracefully and if the overclock
+/// application wants the setting to be persistent, the application should
+/// request the same overclock settings again so that they will be applied
+/// on the next reset/reboot. If this is not done, then every time the
+/// device is reset and overclock is requested, the device needs to be
+/// reset a second time.
+/// - CTL_RESULT_ERROR_FULL_REBOOT_REQUIRED: The requested memory overclock
+/// will be applied when the system is rebooted. In this case, the
+/// overclock software should check if the overclock request was applied
+/// after the reboot. If it was and when the overclock application shuts
+/// down gracefully and if the overclock application wants the setting to
+/// be persistent, the application should request the same overclock
+/// settings again so that they will be applied on the next reset/reboot.
+/// If this is not done and the overclock setting is requested after the
+/// reboot has occurred, a second reboot will be required.
+/// - CTL_RESULT_ERROR_UNSUPPORTED_FEATURE: The Memory Speed Get / Set
+/// Feature is currently not available or Unsupported in current platform
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockVramMemSpeedLimitSetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double ocVramMemSpeedLimit ///< [in] The desired Memory Speed in units given in
+ ///< ctl_oc_properties_t::vramMemSpeedLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get the Current Sustained power limit
+///
+/// @details
+/// - The purpose of this function is to read the current sustained power
+/// limit.
+/// - The unit of the value returned is given in
+/// ::ctl_oc_properties_t::powerLimit::units returned from
+/// ::ctlOverclockGetProperties()
+/// - The unit of the value returned can be different for different
+/// generation of graphics product
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pSustainedPowerLimit`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockPowerLimitGetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double* pSustainedPowerLimit ///< [in,out] The current Sustained Power limit in Units given in
+ ///< ::ctl_oc_properties_t::powerLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Set the Sustained power limit
+///
+/// @details
+/// - The purpose of this function is to set the maximum sustained power
+/// limit. If the average GPU power averaged over a few seconds exceeds
+/// this value, the frequency of the GPU will be throttled.
+/// - Set a value of 0 to disable this power limit. In this case, the GPU
+/// frequency will not throttle due to average power but may hit other
+/// limits.
+/// - The unit of the PowerLimit to be set is given in
+/// ::ctl_oc_properties_t::powerLimit::units returned from
+/// ::ctlOverclockGetProperties()
+/// - The unit of the value returned can be different for different
+/// generation of graphics product
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockPowerLimitSetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double sustainedPowerLimit ///< [in] The desired sustained power limit in Units given in
+ ///< ::ctl_oc_properties_t::powerLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get the current temperature limit
+///
+/// @details
+/// - The purpose of this function is to read the current thermal limit used
+/// for Overclocking
+/// - The unit of the value returned is given in
+/// ::ctl_oc_properties_t::temperatureLimit::units returned from
+/// ::ctlOverclockGetProperties()
+/// - The unit of the value returned can be different for different
+/// generation of graphics product
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pTemperatureLimit`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockTemperatureLimitGetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double* pTemperatureLimit ///< [in,out] The current temperature limit in Units given in
+ ///< ::ctl_oc_properties_t::temperatureLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Set the temperature limit
+///
+/// @details
+/// - The purpose of this function is to change the maximum thermal limit.
+/// When the GPU temperature exceeds this value, the GPU frequency will be
+/// throttled.
+/// - The unit of the value to be set is given in
+/// ::ctl_oc_properties_t::temperatureLimit::units returned from
+/// ::ctlOverclockGetProperties()
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockTemperatureLimitSetV2(
+ ctl_device_adapter_handle_t hDeviceHandle, ///< [in][release] Handle to display adapter
+ double temperatureLimit ///< [in] The desired temperature limit in Units given in
+ ///< ctl_oc_properties_t::temperatureLimit::units returned from
+ ///< ::ctlOverclockGetProperties()
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Read VF Curve
+///
+/// @details
+/// - Read the Voltage-Frequency Curve
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceAdapter`
+/// - CTL_RESULT_ERROR_INVALID_ENUMERATION
+/// + `::CTL_VF_CURVE_TYPE_LIVE < VFCurveType`
+/// + `::CTL_VF_CURVE_DETAILS_ELABORATE < VFCurveDetail`
+/// - CTL_RESULT_ERROR_UNKNOWN - "Unknown Error"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockReadVFCurve(
+ ctl_device_adapter_handle_t hDeviceAdapter, ///< [in][release] Handle to control device adapter
+ ctl_vf_curve_type_t VFCurveType, ///< [in] Type of Curve to read
+ ctl_vf_curve_details_t VFCurveDetail, ///< [in] Detail of Curve to read
+ uint32_t * pNumPoints, ///< [in][out] Number of points in the custom VF curve. If the NumPoints is
+ ///< zero, then the api will update the value with total number of Points
+ ///< based on requested VFCurveType and VFCurveDetail. If the NumPoints is
+ ///< non-zero, then the api will read and update the VF points in
+ ///< pVFCurveTable buffer provided. If the NumPoints doesn't match what the
+ ///< api returned in the first call, it will return an error.
+ ctl_voltage_frequency_point_t * pVFCurveTable ///< [in][out] Pointer to array of VF points, to copy the VF curve being
+ ///< read
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Write Custom VF curve
+///
+/// @details
+/// - Modify the Voltage-Frequency Curve used by GPU
+/// - Valid Voltage-Frequency Curve shall have Voltage and Frequency Points
+/// in increasing order
+/// - Recommended to create Custom V-F Curve from reading Current V-F Curve
+/// using ::ctlOverclockReadVFCurve (Read-Modify-Write)
+/// - If Custom V-F curve write request is Successful, the Applied VF Curve
+/// might be slightly different than what is originally requested,
+/// recommended to update the UI by reading the V-F curve again using
+/// ctlOverclockReadVFCurve (with ctl_vf_curve_type_t::LIVE as input)
+/// - The overclock waiver must be set before calling this function
+/// otherwise error will be returned.
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceAdapter`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pCustomVFCurveTable`
+/// - CTL_RESULT_ERROR_UNKNOWN - "Unknown Error"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockWriteCustomVFCurve(
+ ctl_device_adapter_handle_t hDeviceAdapter, ///< [in][release] Handle to control device adapter
+ uint32_t NumPoints, ///< [in] Number of points in the custom VF curve
+ ctl_voltage_frequency_point_t* pCustomVFCurveTable ///< [in] Pointer to an array of VF Points containing 'NumPoints' Custom VF
+ ///< points
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Power Telemetry
+typedef struct _ctl_power_telemetry2_t
+{
+ uint32_t Size; ///< [in] size of this structure
+ uint8_t Version; ///< [in] version of this structure
+ ctl_oc_telemetry_item_t timeStamp; ///< [out] Snapshot of the timestamp counter that measures the total time
+ ///< since Jan 1, 1970 UTC. It is a decimal value in seconds with a minimum
+ ///< accuracy of 1 millisecond.
+ ctl_oc_telemetry_item_t gpuEnergyCounter; ///< [out] Snapshot of the monotonic energy counter maintained by hardware.
+ ///< It measures the total energy consumed by the GPU chip. By taking the
+ ///< delta between two snapshots and dividing by the delta time in seconds,
+ ///< an application can compute the average power.
+ ctl_oc_telemetry_item_t gpuVoltage; ///< [out] Instantaneous snapshot of the voltage feeding the GPU chip. It
+ ///< is measured at the power supply output - chip input will be lower.
+ ctl_oc_telemetry_item_t gpuCurrentClockFrequency; ///< [out] Instantaneous snapshot of the GPU chip frequency.
+ ctl_oc_telemetry_item_t gpuCurrentTemperature; ///< [out] Instantaneous snapshot of the GPU chip temperature, read from
+ ///< the sensor reporting the highest value.
+ ctl_oc_telemetry_item_t globalActivityCounter; ///< [out] Snapshot of the monotonic global activity counter. It measures
+ ///< the time in seconds (accurate down to 1 millisecond) that any GPU
+ ///< engine is busy. By taking the delta between two snapshots and dividing
+ ///< by the delta time in seconds, an application can compute the average
+ ///< percentage utilization of the GPU..
+ ctl_oc_telemetry_item_t renderComputeActivityCounter; ///< [out] Snapshot of the monotonic 3D/compute activity counter. It
+ ///< measures the time in seconds (accurate down to 1 millisecond) that any
+ ///< 3D render/compute engine is busy. By taking the delta between two
+ ///< snapshots and dividing by the delta time in seconds, an application
+ ///< can compute the average percentage utilization of all 3D
+ ///< render/compute blocks in the GPU.
+ ctl_oc_telemetry_item_t mediaActivityCounter; ///< [out] Snapshot of the monotonic media activity counter. It measures
+ ///< the time in seconds (accurate down to 1 millisecond) that any media
+ ///< engine is busy. By taking the delta between two snapshots and dividing
+ ///< by the delta time in seconds, an application can compute the average
+ ///< percentage utilization of all media blocks in the GPU.
+ bool gpuPowerLimited; ///< [out] Instantaneous indication that the desired GPU frequency is being
+ ///< throttled because the GPU chip is exceeding the maximum power limits.
+ ///< Increasing the power limits using ::ctlOverclockPowerLimitSet() is one
+ ///< way to remove this limitation.
+ bool gpuTemperatureLimited; ///< [out] Instantaneous indication that the desired GPU frequency is being
+ ///< throttled because the GPU chip is exceeding the temperature limits.
+ ///< Increasing the temperature limits using
+ ///< ::ctlOverclockTemperatureLimitSet() is one way to reduce this
+ ///< limitation. Improving the cooling solution is another way.
+ bool gpuCurrentLimited; ///< [out] Instantaneous indication that the desired GPU frequency is being
+ ///< throttled because the GPU chip has exceeded the power supply current
+ ///< limits. A better power supply is required to reduce this limitation.
+ bool gpuVoltageLimited; ///< [out] Instantaneous indication that the GPU frequency cannot be
+ ///< increased because the voltage limits have been reached. Increase the
+ ///< voltage offset using ::ctlOverclockGpuVoltageOffsetSet() is one way to
+ ///< reduce this limitation.
+ bool gpuUtilizationLimited; ///< [out] Instantaneous indication that due to lower GPU utilization, the
+ ///< hardware has lowered the GPU frequency.
+ ctl_oc_telemetry_item_t vramEnergyCounter; ///< [out] Snapshot of the monotonic energy counter maintained by hardware.
+ ///< It measures the total energy consumed by the local memory modules. By
+ ///< taking the delta between two snapshots and dividing by the delta time
+ ///< in seconds, an application can compute the average power.
+ ctl_oc_telemetry_item_t vramVoltage; ///< [out] Instantaneous snapshot of the voltage feeding the memory
+ ///< modules.
+ ctl_oc_telemetry_item_t vramCurrentClockFrequency; ///< [out] Instantaneous snapshot of the raw clock frequency driving the
+ ///< memory modules.
+ ctl_oc_telemetry_item_t vramCurrentEffectiveFrequency; ///< [out] Instantaneous snapshot of the effective data transfer rate that
+ ///< the memory modules can sustain based on the current clock frequency..
+ ctl_oc_telemetry_item_t vramReadBandwidthCounter; ///< [out] Instantaneous snapshot of the monotonic counter that measures
+ ///< the read traffic from the memory modules. By taking the delta between
+ ///< two snapshots and dividing by the delta time in seconds, an
+ ///< application can compute the average read bandwidth.
+ ctl_oc_telemetry_item_t vramWriteBandwidthCounter; ///< [out] Instantaneous snapshot of the monotonic counter that measures
+ ///< the write traffic to the memory modules. By taking the delta between
+ ///< two snapshots and dividing by the delta time in seconds, an
+ ///< application can compute the average write bandwidth.
+ ctl_oc_telemetry_item_t vramCurrentTemperature; ///< [out] Instantaneous snapshot of the GPU chip temperature, read from
+ ///< the sensor reporting the highest value.
+ bool vramPowerLimited; ///< [out] Instantaneous indication that the memory frequency is being
+ ///< throttled because the memory modules are exceeding the maximum power
+ ///< limits.
+ bool vramTemperatureLimited; ///< [out] Instantaneous indication that the memory frequency is being
+ ///< throttled because the memory modules are exceeding the temperature
+ ///< limits.
+ bool vramCurrentLimited; ///< [out] Instantaneous indication that the memory frequency is being
+ ///< throttled because the memory modules have exceeded the power supply
+ ///< current limits.
+ bool vramVoltageLimited; ///< [out] Instantaneous indication that the memory frequency cannot be
+ ///< increased because the voltage limits have been reached.
+ bool vramUtilizationLimited; ///< [out] Instantaneous indication that due to lower memory traffic, the
+ ///< hardware has lowered the memory frequency.
+ ctl_oc_telemetry_item_t totalCardEnergyCounter; ///< [out] Total Card Energy Counter.
+ ctl_psu_info_t psu[CTL_PSU_COUNT]; ///< [out] PSU voltage and power.
+ ctl_oc_telemetry_item_t fanSpeed[CTL_FAN_COUNT];///< [out] Fan speed.
+ ctl_oc_telemetry_item_t gpuVrTemp; ///< [out] GPU VR temperature. Supported for Version > 0.
+ ctl_oc_telemetry_item_t vramVrTemp; ///< [out] VRAM VR temperature. Supported for Version > 0.
+ ctl_oc_telemetry_item_t saVrTemp; ///< [out] SA VR temperature. Supported for Version > 0.
+ ctl_oc_telemetry_item_t gpuEffectiveClock; ///< [out] Effective frequency of the GPU. Supported for Version > 0.
+ ctl_oc_telemetry_item_t gpuOverVoltagePercent; ///< [out] OverVoltage as a percent between 0 and 100. Positive values
+ ///< represent fraction of the maximum over-voltage increment being
+ ///< currently applied. Zero indicates operation at or below default
+ ///< maximum frequency. Supported for Version > 0.
+ ctl_oc_telemetry_item_t gpuPowerPercent; ///< [out] GPUPower expressed as a percent representing the fraction of the
+ ///< default maximum power being drawn currently. Values greater than 100
+ ///< indicate power draw beyond default limits. Values above OC Power limit
+ ///< imply throttling due to power. Supported for Version > 0.
+ ctl_oc_telemetry_item_t gpuTemperaturePercent; ///< [out] GPUTemperature expressed as a percent of the thermal margin.
+ ///< Values of 100 or greater indicate thermal throttling and 0 indicates
+ ///< device at 0 degree Celcius. Supported for Version > 0.
+ ctl_oc_telemetry_item_t vramReadBandwidth; ///< [out] Vram Read Bandwidth. Supported for Version > 0.
+ ctl_oc_telemetry_item_t vramWriteBandwidth; ///< [out] Vram Write Bandwidth. Supported for Version > 0.
+
+} ctl_power_telemetry2_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_voltage_frequency_point_t
+typedef struct _ctl_voltage_frequency_point_t ctl_voltage_frequency_point_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_oc_properties2_t
+typedef struct _ctl_oc_properties2_t ctl_oc_properties2_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_power_telemetry2_t
+typedef struct _ctl_power_telemetry2_t ctl_power_telemetry2_t;
+
+
+
+#if !defined(__GNUC__)
+#pragma endregion // common_private_temp
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockGpuFrequencyOffsetGetV2
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockGpuFrequencyOffsetGetV2_t)(
+ ctl_device_adapter_handle_t,
+ double*
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockGpuFrequencyOffsetSetV2
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockGpuFrequencyOffsetSetV2_t)(
+ ctl_device_adapter_handle_t,
+ double
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockGpuMaxVoltageOffsetGetV2
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockGpuMaxVoltageOffsetGetV2_t)(
+ ctl_device_adapter_handle_t,
+ double*
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockGpuMaxVoltageOffsetSetV2
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockGpuMaxVoltageOffsetSetV2_t)(
+ ctl_device_adapter_handle_t,
+ double
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockVramMemSpeedLimitGetV2
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockVramMemSpeedLimitGetV2_t)(
+ ctl_device_adapter_handle_t,
+ double*
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockVramMemSpeedLimitSetV2
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockVramMemSpeedLimitSetV2_t)(
+ ctl_device_adapter_handle_t,
+ double
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockPowerLimitGetV2
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockPowerLimitGetV2_t)(
+ ctl_device_adapter_handle_t,
+ double*
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockPowerLimitSetV2
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockPowerLimitSetV2_t)(
+ ctl_device_adapter_handle_t,
+ double
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockTemperatureLimitGetV2
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockTemperatureLimitGetV2_t)(
+ ctl_device_adapter_handle_t,
+ double*
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockTemperatureLimitSetV2
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockTemperatureLimitSetV2_t)(
+ ctl_device_adapter_handle_t,
+ double
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockReadVFCurve
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockReadVFCurve_t)(
+ ctl_device_adapter_handle_t,
+ ctl_vf_curve_type_t,
+ ctl_vf_curve_details_t,
+ uint32_t *,
+ ctl_voltage_frequency_point_t *
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockWriteCustomVFCurve
+typedef ctl_result_t (CTL_APICALL *ctlpvttemp_$xOverclockWriteCustomVFCurve_t)(
+ ctl_device_adapter_handle_t,
+ uint32_t,
+ ctl_voltage_frequency_point_t*
+ );
+
+
+#if defined(__cplusplus)
+} // extern "C"
+#endif
+
+#endif // _CTLPVTTEMP_API_H
\ No newline at end of file
diff --git a/IntelPresentMon/ControlLib/igcl_api.h b/IntelPresentMon/ControlLib/igcl_api.h
index be602596..7916c878 100644
--- a/IntelPresentMon/ControlLib/igcl_api.h
+++ b/IntelPresentMon/ControlLib/igcl_api.h
@@ -394,11 +394,12 @@ typedef enum _ctl_result_t
CTL_RESULT_ERROR_CORE_OVERCLOCK_VOLTAGE_OUTSIDE_RANGE = 0x44000002, ///< The Voltage exceeds the acceptable min/max.
CTL_RESULT_ERROR_CORE_OVERCLOCK_FREQUENCY_OUTSIDE_RANGE = 0x44000003, ///< The Frequency exceeds the acceptable min/max.
CTL_RESULT_ERROR_CORE_OVERCLOCK_POWER_OUTSIDE_RANGE = 0x44000004, ///< The Power exceeds the acceptable min/max.
- CTL_RESULT_ERROR_CORE_OVERCLOCK_TEMPERATURE_OUTSIDE_RANGE = 0x44000005, ///< The Power exceeds the acceptable min/max.
+ CTL_RESULT_ERROR_CORE_OVERCLOCK_TEMPERATURE_OUTSIDE_RANGE = 0x44000005, ///< The Temperature exceeds the acceptable min/max.
CTL_RESULT_ERROR_CORE_OVERCLOCK_IN_VOLTAGE_LOCKED_MODE = 0x44000006,///< The Overclock is in voltage locked mode.
CTL_RESULT_ERROR_CORE_OVERCLOCK_RESET_REQUIRED = 0x44000007,///< It indicates that the requested change will not be applied until the
///< device is reset.
CTL_RESULT_ERROR_CORE_OVERCLOCK_WAIVER_NOT_SET = 0x44000008,///< The $OverclockWaiverSet function has not been called.
+ CTL_RESULT_ERROR_CORE_OVERCLOCK_DEPRECATED_API = 0x44000009,///< The error indicates to switch to newer API version if applicable.
CTL_RESULT_ERROR_CORE_END = 0x0440FFFF, ///< "Core error code end value, not to be used
///< "
CTL_RESULT_ERROR_3D_START = 0x60000000, ///< 3D error code starting value, not to be used
@@ -437,6 +438,10 @@ typedef enum _ctl_result_t
CTL_RESULT_ERROR_CUSTOM_MODE_STANDARD_CUSTOM_MODE_EXISTS = 0x4800001a, ///< Standard custom mode exists
CTL_RESULT_ERROR_CUSTOM_MODE_NON_CUSTOM_MATCHING_MODE_EXISTS = 0x4800001b, ///< Non custom matching mode exists
CTL_RESULT_ERROR_CUSTOM_MODE_INSUFFICIENT_MEMORY = 0x4800001c, ///< Custom mode insufficent memory
+ CTL_RESULT_ERROR_ADAPTER_ALREADY_LINKED = 0x4800001d, ///< Adapter is already linked
+ CTL_RESULT_ERROR_ADAPTER_NOT_IDENTICAL = 0x4800001e,///< Adapter is not identical for linking
+ CTL_RESULT_ERROR_ADAPTER_NOT_SUPPORTED_ON_LDA_SECONDARY = 0x4800001f, ///< Adapter is LDA Secondary, so not supporting requested operation
+ CTL_RESULT_ERROR_SET_FBC_FEATURE_NOT_SUPPORTED = 0x48000020,///< Set FBC Feature not supported
CTL_RESULT_ERROR_DISPLAY_END = 0x4800FFFF, ///< "Display error code end value, not to be used
///< "
CTL_RESULT_MAX
@@ -452,7 +457,7 @@ typedef enum _ctl_result_t
///////////////////////////////////////////////////////////////////////////////
#ifndef CTL_MAX_RESERVED_SIZE
/// @brief Maximum reserved size for future members.
-#define CTL_MAX_RESERVED_SIZE 120
+#define CTL_MAX_RESERVED_SIZE 112
#endif // CTL_MAX_RESERVED_SIZE
///////////////////////////////////////////////////////////////////////////////
@@ -469,6 +474,10 @@ typedef enum _ctl_units_t
CTL_UNITS_TIME_SECONDS = 7, ///< Type is Time with units in Seconds.
CTL_UNITS_MEMORY_BYTES = 8, ///< Type is Memory with units in Bytes.
CTL_UNITS_ANGULAR_SPEED_RPM = 9, ///< Type is Angular Speed with units in Revolutions per Minute.
+ CTL_UNITS_POWER_MILLIWATTS = 10, ///< Type is Power with units in MilliWatts.
+ CTL_UNITS_PERCENT = 11, ///< Type is Percentage.
+ CTL_UNITS_MEM_SPEED_GBPS = 12, ///< Type is Memory Speed in Gigabyte per Seconds (Gbps)
+ CTL_UNITS_VOLTAGE_MILLIVOLTS = 13, ///< Type is Voltage with units in milliVolts.
CTL_UNITS_UNKNOWN = 0x4800FFFF, ///< Type of units unknown.
CTL_UNITS_MAX
@@ -692,10 +701,24 @@ typedef uint32_t ctl_adapter_properties_flags_t;
typedef enum _ctl_adapter_properties_flag_t
{
CTL_ADAPTER_PROPERTIES_FLAG_INTEGRATED = CTL_BIT(0),///< [out] Is Integrated Graphics adapter
+ CTL_ADAPTER_PROPERTIES_FLAG_LDA_PRIMARY = CTL_BIT(1), ///< [out] Is Primary (Lead) adapter in a Linked Display Adapter (LDA)
+ ///< chain
+ CTL_ADAPTER_PROPERTIES_FLAG_LDA_SECONDARY = CTL_BIT(2), ///< [out] Is Secondary (Linked) adapter in a Linked Display Adapter (LDA)
+ ///< chain
CTL_ADAPTER_PROPERTIES_FLAG_MAX = 0x80000000
} ctl_adapter_properties_flag_t;
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Adapter Pci Bus, Device, Function
+typedef struct _ctl_adapter_bdf_t
+{
+ uint8_t bus; ///< [out] PCI Bus Number
+ uint8_t device; ///< [out] PCI device number
+ uint8_t function; ///< [out] PCI function
+
+} ctl_adapter_bdf_t;
+
///////////////////////////////////////////////////////////////////////////////
/// @brief Device Adapter properties
typedef struct _ctl_device_adapter_properties_t
@@ -717,6 +740,9 @@ typedef struct _ctl_device_adapter_properties_t
char name[CTL_MAX_DEVICE_NAME_LEN]; ///< [out] Device name
ctl_adapter_properties_flags_t graphics_adapter_properties; ///< [out] Graphics Adapter Properties
uint32_t Frequency; ///< [out] Clock frequency for this device. Supported only for Version > 0
+ uint16_t pci_subsys_id; ///< [out] PCI SubSys ID, Supported only for Version > 1
+ uint16_t pci_subsys_vendor_id; ///< [out] PCI SubSys Vendor ID, Supported only for Version > 1
+ ctl_adapter_bdf_t adapter_bdf; ///< [out] Pci Bus, Device, Function. Supported only for Version > 1
char reserved[CTL_MAX_RESERVED_SIZE]; ///< [out] Reserved
} ctl_device_adapter_properties_t;
@@ -932,6 +958,10 @@ typedef struct _ctl_runtime_path_args_t ctl_runtime_path_args_t;
/// @brief Forward-declare ctl_firmware_version_t
typedef struct _ctl_firmware_version_t ctl_firmware_version_t;
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_adapter_bdf_t
+typedef struct _ctl_adapter_bdf_t ctl_adapter_bdf_t;
+
///////////////////////////////////////////////////////////////////////////////
/// @brief Forward-declare ctl_device_adapter_properties_t
typedef struct _ctl_device_adapter_properties_t ctl_device_adapter_properties_t;
@@ -1028,6 +1058,10 @@ typedef struct _ctl_sharpness_settings_t ctl_sharpness_settings_t;
/// @brief Forward-declare ctl_i2c_access_args_t
typedef struct _ctl_i2c_access_args_t ctl_i2c_access_args_t;
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_i2c_access_pinpair_args_t
+typedef struct _ctl_i2c_access_pinpair_args_t ctl_i2c_access_pinpair_args_t;
+
///////////////////////////////////////////////////////////////////////////////
/// @brief Forward-declare ctl_aux_access_args_t
typedef struct _ctl_aux_access_args_t ctl_aux_access_args_t;
@@ -1184,6 +1218,30 @@ typedef struct _ctl_genlock_topology_t ctl_genlock_topology_t;
/// @brief Forward-declare ctl_genlock_args_t
typedef struct _ctl_genlock_args_t ctl_genlock_args_t;
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_vblank_ts_args_t
+typedef struct _ctl_vblank_ts_args_t ctl_vblank_ts_args_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_lda_args_t
+typedef struct _ctl_lda_args_t ctl_lda_args_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_dce_args_t
+typedef struct _ctl_dce_args_t ctl_dce_args_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_wire_format_t
+typedef struct _ctl_wire_format_t ctl_wire_format_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_get_set_wire_format_config_t
+typedef struct _ctl_get_set_wire_format_config_t ctl_get_set_wire_format_config_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Forward-declare ctl_display_settings_t
+typedef struct _ctl_display_settings_t ctl_display_settings_t;
+
///////////////////////////////////////////////////////////////////////////////
/// @brief Forward-declare ctl_engine_properties_t
typedef struct _ctl_engine_properties_t ctl_engine_properties_t;
@@ -1371,7 +1429,7 @@ typedef struct _ctl_temp_properties_t ctl_temp_properties_t;
#endif
// Intel 'ctlApi' for Device Adapter
#if !defined(__GNUC__)
-#pragma region 3D
+#pragma region _3D
#endif
///////////////////////////////////////////////////////////////////////////////
/// @brief Feature type
@@ -1398,6 +1456,9 @@ typedef enum _ctl_3d_feature_t
///< ::ctl_3d_app_profiles_caps_t & ::ctl_3d_app_profiles_t
CTL_3D_FEATURE_APP_PROFILE_DETAILS = 12, ///< Game Profile Customization. Refer custom field ::ctl_3d_tier_details_t
CTL_3D_FEATURE_EMULATED_TYPED_64BIT_ATOMICS = 13, ///< Emulated Typed 64bit Atomics support in DG2
+ CTL_3D_FEATURE_VRR_WINDOWED_BLT = 14, ///< VRR windowed blt. Control VRR for windowed mode game
+ CTL_3D_FEATURE_GLOBAL_OR_PER_APP = 15, ///< Set global settings or per application settings
+ CTL_3D_FEATURE_LOW_LATENCY = 16, ///< Low latency mode. Contains generic enum type fields
CTL_3D_FEATURE_MAX
} ctl_3d_feature_t;
@@ -1473,6 +1534,17 @@ typedef enum _ctl_3d_endurance_gaming_mode_t
} ctl_3d_endurance_gaming_mode_t;
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Low latency mode values possible
+typedef enum _ctl_3d_low_latency_types_t
+{
+ CTL_3D_LOW_LATENCY_TYPES_TURN_OFF = 0, ///< Low latency mode disable
+ CTL_3D_LOW_LATENCY_TYPES_TURN_ON = 1, ///< Low latency mode enable
+ CTL_3D_LOW_LATENCY_TYPES_TURN_ON_BOOST_MODE_ON = 2, ///< Low latency mode enable with boost
+ CTL_3D_LOW_LATENCY_TYPES_MAX
+
+} ctl_3d_low_latency_types_t;
+
///////////////////////////////////////////////////////////////////////////////
/// @brief Cmaa values possible
typedef enum _ctl_3d_cmaa_types_t
@@ -1561,6 +1633,7 @@ typedef struct _ctl_endurance_gaming2_t
///< Battery
bool IsFPRequired; ///< [out] Is frame pacing required, dynamic state
double TargetFPS; ///< [out] Target FPS for frame pacing
+ double RefreshRate; ///< [out] Refresh rate used to calculate target fps
uint32_t Reserved[4]; ///< [out] Reserved fields
} ctl_endurance_gaming2_t;
@@ -1658,6 +1731,28 @@ typedef enum _ctl_emulated_typed_64bit_atomics_types_t
} ctl_emulated_typed_64bit_atomics_types_t;
+///////////////////////////////////////////////////////////////////////////////
+/// @brief VRR windowed BLT control possible. Reserved functionality
+typedef enum _ctl_3d_vrr_windowed_blt_reserved_t
+{
+ CTL_3D_VRR_WINDOWED_BLT_RESERVED_AUTO = 0, ///< VRR windowed BLT auto
+ CTL_3D_VRR_WINDOWED_BLT_RESERVED_TURN_ON = 1, ///< VRR windowed BLT enable
+ CTL_3D_VRR_WINDOWED_BLT_RESERVED_TURN_OFF = 2, ///< VRR windowed BLT disable
+ CTL_3D_VRR_WINDOWED_BLT_RESERVED_MAX
+
+} ctl_3d_vrr_windowed_blt_reserved_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Global or per app values possible
+typedef enum _ctl_3d_global_or_per_app_types_t
+{
+ CTL_3D_GLOBAL_OR_PER_APP_TYPES_NONE = 0, ///< none
+ CTL_3D_GLOBAL_OR_PER_APP_TYPES_PER_APP = 1, ///< Opt for per app settings
+ CTL_3D_GLOBAL_OR_PER_APP_TYPES_GLOBAL = 2, ///< Opt for global settings
+ CTL_3D_GLOBAL_OR_PER_APP_TYPES_MAX
+
+} ctl_3d_global_or_per_app_types_t;
+
///////////////////////////////////////////////////////////////////////////////
/// @brief 3D feature capability details which will have range/supported and
/// default values
@@ -1739,6 +1834,8 @@ typedef struct _ctl_kmd_load_features_t
///< given adapter. Note that this should contain only the name of the
///< application and not the system specific path
int8_t ApplicationNameLength; ///< [in] Length of ApplicationName string
+ int8_t CallerComponent; ///< [in] Caller component
+ int64_t Reserved[4]; ///< [in] Reserved field
} ctl_kmd_load_features_t;
@@ -1786,7 +1883,7 @@ ctlGetSet3DFeature(
#if !defined(__GNUC__)
-#pragma endregion // 3D
+#pragma endregion // _3D
#endif
// Intel 'ctlApi' for Device Adapter
#if !defined(__GNUC__)
@@ -1796,6 +1893,10 @@ ctlGetSet3DFeature(
/// @brief Handle of a display output instance
typedef struct _ctl_display_output_handle_t *ctl_display_output_handle_t;
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Handle of a i2c pin-pair instance
+typedef struct _ctl_i2c_pin_pair_handle_t *ctl_i2c_pin_pair_handle_t;
+
///////////////////////////////////////////////////////////////////////////////
/// @brief Check Driver version
///
@@ -1872,6 +1973,38 @@ ctlEnumerateDisplayOutputs(
///< instance handles
);
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Enumerate I2C Pin Pairs
+///
+/// @details
+/// - Returns available list of I2C Pin-Pairs on a requested adapter
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceAdapter`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pCount`
+/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+/// - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "The incoming pointer pCount is null"
+/// - ::CTL_RESULT_ERROR_INVALID_SIZE - "The supplied Count is not equal to actual number of i2c pin-pair instances"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlEnumerateI2CPinPairs(
+ ctl_device_adapter_handle_t hDeviceAdapter, ///< [in][release] handle to device adapter
+ uint32_t* pCount, ///< [in,out][release] pointer to the number of i2c pin-pair instances. If
+ ///< count is zero, then the api will update the value with the total
+ ///< number of i2c pin-pair instances available. If count is non-zero and
+ ///< matches the avaialble number of pin-pairs, then the api will only
+ ///< return the avaialble number of i2c pin-pair instances in phI2cPinPairs.
+ ctl_i2c_pin_pair_handle_t* phI2cPinPairs ///< [out][optional][release][range(0, *pCount)] array of i2c pin pair
+ ///< instance handles. Need to be allocated by Caller when supplying the
+ ///< *pCount > 0.
+ ///< If Count is not equal to actual number of i2c pin-pair instances, it
+ ///< will return CTL_RESULT_ERROR_INVALID_SIZE.
+ );
+
///////////////////////////////////////////////////////////////////////////////
/// @brief OS specific Display identifiers
typedef union _ctl_os_display_encoder_identifier_t
@@ -1921,6 +2054,8 @@ typedef enum _ctl_std_display_feature_flag_t
CTL_STD_DISPLAY_FEATURE_FLAG_VESA_COMPRESSION = CTL_BIT(4), ///< [out] Is display compression (VESA DSC) supported
CTL_STD_DISPLAY_FEATURE_FLAG_HDR = CTL_BIT(5), ///< [out] Is HDR supported
CTL_STD_DISPLAY_FEATURE_FLAG_HDMI_QMS = CTL_BIT(6), ///< [out] Is HDMI QMS supported
+ CTL_STD_DISPLAY_FEATURE_FLAG_HDR10_PLUS_CERTIFIED = CTL_BIT(7), ///< [out] Is HDR10+ certified
+ CTL_STD_DISPLAY_FEATURE_FLAG_VESA_HDR_CERTIFIED = CTL_BIT(8), ///< [out] Is VESA HDR certified - for future use
CTL_STD_DISPLAY_FEATURE_FLAG_MAX = 0x80000000
} ctl_std_display_feature_flag_t;
@@ -1934,6 +2069,7 @@ typedef enum _ctl_intel_display_feature_flag_t
CTL_INTEL_DISPLAY_FEATURE_FLAG_DPST = CTL_BIT(0), ///< [out] Is DPST supported
CTL_INTEL_DISPLAY_FEATURE_FLAG_LACE = CTL_BIT(1), ///< [out] Is LACE supported
CTL_INTEL_DISPLAY_FEATURE_FLAG_DRRS = CTL_BIT(2), ///< [out] Is DRRS supported
+ CTL_INTEL_DISPLAY_FEATURE_FLAG_ARC_ADAPTIVE_SYNC_CERTIFIED = CTL_BIT(3),///< [out] Is Intel Arc certified adaptive sync display
CTL_INTEL_DISPLAY_FEATURE_FLAG_MAX = 0x80000000
} ctl_intel_display_feature_flag_t;
@@ -2013,6 +2149,7 @@ typedef enum _ctl_encoder_config_flag_t
CTL_ENCODER_CONFIG_FLAG_COLLAGE_DISPLAY = CTL_BIT(7), ///< [out] This BIT will be set if this is a collage display
CTL_ENCODER_CONFIG_FLAG_SPLIT_DISPLAY = CTL_BIT(8), ///< [out] This BIT will be set if this is a split display
CTL_ENCODER_CONFIG_FLAG_COMPANION_DISPLAY = CTL_BIT(9), ///< [out] This BIT will be set if this is a companion display
+ CTL_ENCODER_CONFIG_FLAG_MGPU_COLLAGE_DISPLAY = CTL_BIT(10), ///< [out] This BIT will be set if this is a Multi GPU collage display
CTL_ENCODER_CONFIG_FLAG_MAX = 0x80000000
} ctl_encoder_config_flag_t;
@@ -2107,12 +2244,19 @@ typedef struct _ctl_adapter_display_encoder_properties_t
///< driver which occupies a portion of a real physical display
///< Split=1,Virtual=0 : Indicates the physical display which got split
///< to form multiple split displays
- ///< Split=1,Collage=1 : Invalid combination
+ ///< Split=1,Collage=1 : Invalid combination
+ ///< MgpuCollage=1,Collage=1,Virtual=1: Indicates the fake display
+ ///< output created by driver which has the combined resolution of multiple
+ ///< physical displays spread across multiple GPUs involved in Multi-GPU
+ ///< collage configuration
+ ///< MgpuCollage=1,Collage=1,Virtual=0: Indicates the child physical
+ ///< displays involved in a Multi-GPU collage configuration. These are real
+ ///< physical outputs
ctl_std_display_feature_flags_t FeatureSupportedFlags; ///< [out] Adapter Supported feature flags. Refer
///< ::ctl_std_display_feature_flag_t
ctl_intel_display_feature_flags_t AdvancedFeatureSupportedFlags;///< [out] Advanced Features Supported by the Adapter. Refer
///< ::ctl_intel_display_feature_flag_t
- uint32_t ReservedFields[16]; ///< [out] Reserved field of 64 bytes
+ uint32_t ReservedFields[16]; ///< [out] Reserved field of 60 bytes
} ctl_adapter_display_encoder_properties_t;
@@ -2321,11 +2465,21 @@ ctlSetCurrentSharpness(
#endif // CTL_I2C_MAX_DATA_SIZE
///////////////////////////////////////////////////////////////////////////////
-/// @brief I2CFlags bitmasks
+/// @brief I2C Access Args input Flags bitmasks
typedef uint32_t ctl_i2c_flags_t;
typedef enum _ctl_i2c_flag_t
{
- CTL_I2C_FLAG_ATOMICI2C = CTL_BIT(0), ///< Force Atomic I2C
+ CTL_I2C_FLAG_ATOMICI2C = CTL_BIT(0), ///< Force Atomic I2C.
+ CTL_I2C_FLAG_1BYTE_INDEX = CTL_BIT(1), ///< 1-byte Indexed operation. If no Index Size flag set, decided based on
+ ///< Offset Value.
+ CTL_I2C_FLAG_2BYTE_INDEX = CTL_BIT(2), ///< 2-byte Indexed operation. If no Index Size flag set, decided based on
+ ///< Offset Value.
+ CTL_I2C_FLAG_4BYTE_INDEX = CTL_BIT(3), ///< 4-byte Indexed operation. If no Index Size flag set, decided based on
+ ///< Offset Value.
+ CTL_I2C_FLAG_SPEED_SLOW = CTL_BIT(4), ///< If no Speed Flag is set, defaults to Best Option possible.
+ CTL_I2C_FLAG_SPEED_FAST = CTL_BIT(5), ///< If no Speed Flag is set, defaults to Best Option possible.
+ CTL_I2C_FLAG_SPEED_BIT_BASH = CTL_BIT(6), ///< Uses Slower access using SW bit bashing method. If no Speed Flag is
+ ///< set, defaults to Best Option possible.
CTL_I2C_FLAG_MAX = 0x80000000
} ctl_i2c_flag_t;
@@ -2337,7 +2491,7 @@ typedef struct _ctl_i2c_access_args_t
uint32_t Size; ///< [in] size of this structure
uint8_t Version; ///< [in] version of this structure
uint32_t DataSize; ///< [in,out] Valid data size
- uint32_t Address; ///< [in] Adreess to read or write
+ uint32_t Address; ///< [in] Address to read or write
ctl_operation_type_t OpType; ///< [in] Operation type, 1 for Read, 2 for Write, for Write operation, App
///< needs to run with admin privileges
uint32_t Offset; ///< [in] Offset
@@ -2352,7 +2506,7 @@ typedef struct _ctl_i2c_access_args_t
/// @brief I2C Access
///
/// @details
-/// - The application does I2C aceess
+/// - Interface to access I2C using display handle as identifier.
///
/// @returns
/// - CTL_RESULT_SUCCESS
@@ -2377,6 +2531,75 @@ ctlI2CAccess(
ctl_i2c_access_args_t* pI2cAccessArgs ///< [in,out] I2c access arguments
);
+///////////////////////////////////////////////////////////////////////////////
+/// @brief I2C Access on PinPair Args input Flags bitmasks
+typedef uint32_t ctl_i2c_pinpair_flags_t;
+typedef enum _ctl_i2c_pinpair_flag_t
+{
+ CTL_I2C_PINPAIR_FLAG_ATOMICI2C = CTL_BIT(0), ///< Force Atomic I2C.
+ CTL_I2C_PINPAIR_FLAG_1BYTE_INDEX = CTL_BIT(1), ///< 1-byte Indexed operation. If no Index Size flag set, decided based on
+ ///< Offset Value.
+ CTL_I2C_PINPAIR_FLAG_2BYTE_INDEX = CTL_BIT(2), ///< 2-byte Indexed operation. If no Index Size flag set, decided based on
+ ///< Offset Value.
+ CTL_I2C_PINPAIR_FLAG_4BYTE_INDEX = CTL_BIT(3), ///< 4-byte Indexed operation. If no Index Size flag set, decided based on
+ ///< Offset Value.
+ CTL_I2C_PINPAIR_FLAG_SPEED_SLOW = CTL_BIT(4), ///< If no Speed Flag is set, defaults to Best Option possible.
+ CTL_I2C_PINPAIR_FLAG_SPEED_FAST = CTL_BIT(5), ///< If no Speed Flag is set, defaults to Best Option possible.
+ CTL_I2C_PINPAIR_FLAG_SPEED_BIT_BASH = CTL_BIT(6), ///< Uses Slower access using SW bit bashing method. If no Speed Flag is
+ ///< set, defaults to Best Option possible.
+ CTL_I2C_PINPAIR_FLAG_MAX = 0x80000000
+
+} ctl_i2c_pinpair_flag_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief I2C access on Pin Pair arguments
+typedef struct _ctl_i2c_access_pinpair_args_t
+{
+ uint32_t Size; ///< [in] size of this structure
+ uint8_t Version; ///< [in] version of this structure
+ uint32_t DataSize; ///< [in,out] Valid data size
+ uint32_t Address; ///< [in] Address to read or write
+ ctl_operation_type_t OpType; ///< [in] Operation type, 1 for Read, 2 for Write, for Write operation, App
+ ///< needs to run with admin privileges
+ uint32_t Offset; ///< [in] Offset
+ ctl_i2c_pinpair_flags_t Flags; ///< [in] I2C Flags. Refer ::ctl_i2c_pinpair_flag_t
+ uint8_t Data[CTL_I2C_MAX_DATA_SIZE]; ///< [in,out] Data array
+ uint32_t ReservedFields[4]; ///< [in] Reserved for future use, must be set to Zero.
+
+} ctl_i2c_access_pinpair_args_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief I2C Access On Pin Pair
+///
+/// @details
+/// - Interface to access I2C using pin-pair handle as identifier.
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hI2cPinPair`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pI2cAccessArgs`
+/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+/// - ::CTL_RESULT_ERROR_INVALID_OPERATION_TYPE - "Invalid operation type"
+/// - ::CTL_RESULT_ERROR_INVALID_SIZE - "Invalid I2C data size"
+/// - ::CTL_RESULT_ERROR_INVALID_ARGUMENT - "Invalid Args passed"
+/// - ::CTL_RESULT_ERROR_INSUFFICIENT_PERMISSIONS - "Insufficient permissions"
+/// - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
+/// - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
+/// - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+/// - ::CTL_RESULT_ERROR_KMD_CALL - "Kernal mode driver call failure"
+/// - ::CTL_RESULT_ERROR_INVALID_NULL_HANDLE - "Invalid or Null handle passed"
+/// - ::CTL_RESULT_ERROR_EXTERNAL_DISPLAY_ATTACHED - "Write to Address not allowed when Display is connected"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlI2CAccessOnPinPair(
+ ctl_i2c_pin_pair_handle_t hI2cPinPair, ///< [in] Handle to I2C pin pair.
+ ctl_i2c_access_pinpair_args_t* pI2cAccessArgs ///< [in,out] I2c access arguments.
+ );
+
///////////////////////////////////////////////////////////////////////////////
#ifndef CTL_AUX_MAX_DATA_SIZE
/// @brief Aux Maximum data size
@@ -2404,7 +2627,7 @@ typedef struct _ctl_aux_access_args_t
ctl_operation_type_t OpType; ///< [in] Operation type, 1 for Read, 2 for Write, for Write operation, App
///< needs to run with admin privileges
ctl_aux_flags_t Flags; ///< [in] Aux Flags. Refer ::ctl_aux_flag_t
- uint32_t Address; ///< [in] Adreess to read or write
+ uint32_t Address; ///< [in] Address to read or write
uint64_t RAD; ///< [in] RAD, For Future use, to be used for branch devices, Interface
///< will be provided to get RAD
uint32_t PortID; ///< [in] Port ID, For Future use, to be used for SST tiled devices
@@ -2417,7 +2640,7 @@ typedef struct _ctl_aux_access_args_t
/// @brief Aux Access
///
/// @details
-/// - The application does Aux aceess, PSR needs to be disabled for AUX
+/// - The application does Aux access, PSR needs to be disabled for AUX
/// call.
///
/// @returns
@@ -2456,6 +2679,7 @@ typedef enum _ctl_power_optimization_flag_t
CTL_POWER_OPTIMIZATION_FLAG_LRR = CTL_BIT(3), ///< Low refresh rate (LRR/ALRR/UBRR), UBRR is supported only for IGCC and
///< NDA clients. UBZRR and UBLRR both can not be enabled at the same time,
///< only one can be enabled at a given time
+ CTL_POWER_OPTIMIZATION_FLAG_LACE = CTL_BIT(4), ///< Lighting Aware Contrast Enhancement
CTL_POWER_OPTIMIZATION_FLAG_MAX = 0x80000000
} ctl_power_optimization_flag_t;
@@ -2470,6 +2694,8 @@ typedef enum _ctl_power_optimization_dpst_flag_t
CTL_POWER_OPTIMIZATION_DPST_FLAG_OPST = CTL_BIT(2), ///< Intel OLED Power Saving Technology
CTL_POWER_OPTIMIZATION_DPST_FLAG_ELP = CTL_BIT(3), ///< TCON based Edge Luminance Profile
CTL_POWER_OPTIMIZATION_DPST_FLAG_EPSM = CTL_BIT(4), ///< Extra power saving mode
+ CTL_POWER_OPTIMIZATION_DPST_FLAG_APD = CTL_BIT(5), ///< Adaptive Pixel Dimming
+ CTL_POWER_OPTIMIZATION_DPST_FLAG_PIXOPTIX = CTL_BIT(6), ///< TCON+ based DPST like solution
CTL_POWER_OPTIMIZATION_DPST_FLAG_MAX = 0x80000000
} ctl_power_optimization_dpst_flag_t;
@@ -2580,7 +2806,8 @@ typedef struct _ctl_power_optimization_dpst_t
uint8_t MaxLevel; ///< [out] Maximum supported aggressiveness level
uint8_t Level; ///< [in,out] Current aggressiveness level to be set
ctl_power_optimization_dpst_flags_t SupportedFeatures; ///< [out] Supported features
- ctl_power_optimization_dpst_flags_t EnabledFeatures;///< [in,out] Features enabled or to be enabled
+ ctl_power_optimization_dpst_flags_t EnabledFeatures;///< [in,out] Features enabled or to be enabled. Fill only one feature for
+ ///< SET call
} ctl_power_optimization_dpst_t;
@@ -2678,6 +2905,7 @@ ctlGetPowerOptimizationSetting(
/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
/// - ::CTL_RESULT_ERROR_INVALID_POWERFEATURE_OPTIMIZATION_FLAG - "Unsupported PowerOptimizationFeature"
/// - ::CTL_RESULT_ERROR_INVALID_POWERSOURCE_TYPE_FOR_DPST - "DPST is supported only in DC Mode"
+/// - ::CTL_RESULT_ERROR_SET_FBC_FEATURE_NOT_SUPPORTED - "Set FBC Feature not supported"
CTL_APIEXPORT ctl_result_t CTL_APICALL
ctlSetPowerOptimizationSetting(
ctl_display_output_handle_t hDisplayOutput, ///< [in][release] Handle to display output
@@ -2831,6 +3059,8 @@ typedef enum _ctl_pixtx_color_model_t
CTL_PIXTX_COLOR_MODEL_YCBCR_422_LR = 3, ///< Color model YCBCR 422 limited range
CTL_PIXTX_COLOR_MODEL_YCBCR_420_FR = 4, ///< Color model YCBCR 420 full range
CTL_PIXTX_COLOR_MODEL_YCBCR_420_LR = 5, ///< Color model YCBCR 420 limited range
+ CTL_PIXTX_COLOR_MODEL_YCBCR_444_FR = 6, ///< Color model YCBCR 444 full range
+ CTL_PIXTX_COLOR_MODEL_YCBCR_444_LR = 7, ///< Color model YCBCR 444 limited range
CTL_PIXTX_COLOR_MODEL_MAX
} ctl_pixtx_color_model_t;
@@ -2881,8 +3111,9 @@ typedef struct _ctl_pixtx_1dlut_config_t
///< sampling also but not vice versa.
uint32_t NumSamplesPerChannel; ///< [in,out] Number of samples per channel. Resampled internally based on
///< HW capability for uniformly sampled LUT.Maximum supported value is
- ///< MAX_NUM_SAMPLES_PER_CHANNEL_1D_LUT Caller needs to use exact sampling
- ///< position given in pSamplePositions for non-uniformly sampled LUTs.
+ ///< ::CTL_MAX_NUM_SAMPLES_PER_CHANNEL_1D_LUT Caller needs to use exact
+ ///< sampling position given in pSamplePositions for non-uniformly sampled
+ ///< LUTs.
uint32_t NumChannels; ///< [in,out] Number of channels, 1 for Grey scale LUT, 3 for RGB LUT
double* pSampleValues; ///< [in,out] Pointer to sample values, R array followed by G and B arrays
///< in case of multi-channel LUT. Allocation size for pSampleValues should
@@ -3203,14 +3434,21 @@ typedef struct _ctl_scaling_settings_t
uint32_t Size; ///< [in] size of this structure
uint8_t Version; ///< [in] version of this structure
bool Enable; ///< [in,out] State of the scaler
- ctl_scaling_type_flags_t ScalingType; ///< [in,out] Requested scaling types. Refer ::ctl_scaling_type_flag_t
- uint32_t CustomScalingX; ///< [in,out] Custom Scaling X resolution
- uint32_t CustomScalingY; ///< [in,out] Custom Scaling Y resolution
+ ctl_scaling_type_flags_t ScalingType; ///< [in,out] Requested scaling type. In Get call this field indicates
+ ///< 'currunt' scaling set. Refer ::ctl_scaling_type_flag_t
+ uint32_t CustomScalingX; ///< [in,out] Custom Scaling X in percentage. This is percentage of current
+ ///< OS resolution. Valid values are 0 to 100. Up to 11% of native
+ ///< resolution can be downscaled
+ uint32_t CustomScalingY; ///< [in,out] Custom Scaling Y in percentage. This is percentage of current
+ ///< OS resolution. Valid values are 0 to 100. Up to 11% of native
+ ///< resolution can be downscaled
bool HardwareModeSet; ///< [in] Flag to indicate hardware modeset should be done to apply the
///< scaling.Setting this to true would result in a flash on the screen. If
///< this flag is set to false , API will request the OS to do a virtual
///< modeset , but the OS can ignore this request and do a hardware modeset
///< in some instances
+ ctl_scaling_type_flags_t PreferredScalingType; ///< [out] Indicates OS persisted scaling type. This field is only valid
+ ///< when version > 0. Refer ::ctl_scaling_type_flag_t
} ctl_scaling_settings_t;
@@ -3883,7 +4121,8 @@ typedef struct _ctl_combined_display_args_t
///< configuration
uint32_t CombinedDesktopWidth; ///< [in,out] Width of desired combined display configuration
uint32_t CombinedDesktopHeight; ///< [in,out] Height of desired combined display configuration
- ctl_combined_display_child_info_t* pChildInfo; ///< [in,out] List of child display information respective to each output
+ ctl_combined_display_child_info_t* pChildInfo; ///< [in,out] List of child display information respective to each output.
+ ///< Up to 16 displays are supported with up to 4 displays per GPU.
ctl_display_output_handle_t hCombinedDisplayOutput; ///< [in,out] Handle to combined display output
} ctl_combined_display_args_t;
@@ -3892,7 +4131,16 @@ typedef struct _ctl_combined_display_args_t
/// @brief Get/Set Combined Display
///
/// @details
-/// - To get or set combined display.
+/// - To get or set combined display with given Child Targets on a Single
+/// GPU or across identical GPUs. Multi-GPU(MGPU) combined display is
+/// reserved i.e. it is not public and requires special application GUID.
+/// MGPU Combined Display will get activated or deactivated in next boot.
+/// MGPU scenario will internally link the associated adapters via Linked
+/// Display Adapter Call, with supplied hDeviceAdapter being the LDA
+/// Primary. If Genlock and enabled in Driver registry and supported by
+/// given Display Config, MGPU Combined Display will enable MGPU Genlock
+/// with supplied hDeviceAdapter being the Genlock Primary Adapter and the
+/// First Child Display being the Primary Display.
///
/// @returns
/// - CTL_RESULT_SUCCESS
@@ -3911,6 +4159,7 @@ typedef struct _ctl_combined_display_args_t
/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
/// - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
/// - ::CTL_RESULT_ERROR_FEATURE_NOT_SUPPORTED - "Combined Display feature is not supported in this platform"
+/// - ::CTL_RESULT_ERROR_ADAPTER_NOT_SUPPORTED_ON_LDA_SECONDARY - "Unsupported (secondary) adapter handle passed"
CTL_APIEXPORT ctl_result_t CTL_APICALL
ctlGetSetCombinedDisplay(
ctl_device_adapter_handle_t hDeviceAdapter, ///< [in][release] Handle to control device adapter
@@ -3999,11 +4248,417 @@ typedef struct _ctl_genlock_args_t
CTL_APIEXPORT ctl_result_t CTL_APICALL
ctlGetSetDisplayGenlock(
ctl_device_adapter_handle_t* hDeviceAdapter, ///< [in][release] Handle to control device adapter
- ctl_genlock_args_t** pGenlockArgs, ///< [in,out] Display Genlock operation and information
+ ctl_genlock_args_t* pGenlockArgs, ///< [in,out] Display Genlock operation and information
uint32_t AdapterCount, ///< [in] Number of device adapters
ctl_device_adapter_handle_t* hFailureDeviceAdapter ///< [out] Handle to address the failure device adapter in an error case
);
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CTL_MAX_DISPLAYS_FOR_MGPU_COLLAGE
+/// @brief Maximum number of displays for Single Large Screen
+#define CTL_MAX_DISPLAYS_FOR_MGPU_COLLAGE 16
+#endif // CTL_MAX_DISPLAYS_FOR_MGPU_COLLAGE
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Vblank timestamp arguments
+typedef struct _ctl_vblank_ts_args_t
+{
+ uint32_t Size; ///< [in] size of this structure
+ uint8_t Version; ///< [in] version of this structure
+ uint8_t NumOfTargets; ///< [out] Number of child targets
+ uint64_t VblankTS[CTL_MAX_DISPLAYS_FOR_MGPU_COLLAGE]; ///< [out] List of vblank timestamps in microseconds per child target
+
+} ctl_vblank_ts_args_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get Vblank Timestamp
+///
+/// @details
+/// - To get a list of vblank timestamps in microseconds for each child
+/// target of a display.
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDisplayOutput`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pVblankTSArgs`
+/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+/// - ::CTL_RESULT_ERROR_INSUFFICIENT_PERMISSIONS - "Insufficient permissions"
+/// - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
+/// - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+/// - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlGetVblankTimestamp(
+ ctl_display_output_handle_t hDisplayOutput, ///< [in] Handle to display output
+ ctl_vblank_ts_args_t* pVblankTSArgs ///< [out] Get vblank timestamp arguments
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Link Display Adapters Arguments
+typedef struct _ctl_lda_args_t
+{
+ uint32_t Size; ///< [in] size of this structure
+ uint8_t Version; ///< [in] version of this structure
+ uint8_t NumAdapters; ///< [in,out] Numbers of adapters to be linked. Up to 4 adapters are
+ ///< supported
+ ctl_device_adapter_handle_t* hLinkedAdapters; ///< [in,out][release] List of Control device adapter handles to be linked,
+ ///< first one being Primary Adapter
+ uint64_t Reserved[4]; ///< [out] Reserved fields. Set to zero.
+
+} ctl_lda_args_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Link Display Adapters
+///
+/// @details
+/// - To Link Display Adapters.
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hPrimaryAdapter`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pLdaArgs`
+/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+/// - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
+/// - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+/// - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+/// - ::CTL_RESULT_ERROR_ADAPTER_ALREADY_LINKED - "Adapter is already linked"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlLinkDisplayAdapters(
+ ctl_device_adapter_handle_t hPrimaryAdapter, ///< [in][release] Handle to Primary adapter in LDA chain
+ ctl_lda_args_t* pLdaArgs ///< [in] Link Display Adapters Arguments
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Unlink Display Adapters
+///
+/// @details
+/// - To Unlink Display Adapters
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hPrimaryAdapter`
+/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+/// - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+/// - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+/// - ::CTL_RESULT_ERROR_ADAPTER_NOT_SUPPORTED_ON_LDA_SECONDARY - "Unsupported (secondary) adapter handle passed"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlUnlinkDisplayAdapters(
+ ctl_device_adapter_handle_t hPrimaryAdapter ///< [in][release] Handle to Primary adapter in LDA chain
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get Linked Display Adapters
+///
+/// @details
+/// - To return list of Linked Display Adapters.
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hPrimaryAdapter`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pLdaArgs`
+/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+/// - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
+/// - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+/// - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+/// - ::CTL_RESULT_ERROR_ADAPTER_NOT_SUPPORTED_ON_LDA_SECONDARY - "Unsupported (secondary) adapter handle passed"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlGetLinkedDisplayAdapters(
+ ctl_device_adapter_handle_t hPrimaryAdapter, ///< [in][release] Handle to Primary adapter in LDA chain
+ ctl_lda_args_t* pLdaArgs ///< [out] Link Display Adapters Arguments
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get/Set Dynamic Contrast Enhancement arguments
+typedef struct _ctl_dce_args_t
+{
+ uint32_t Size; ///< [in] size of this structure
+ uint8_t Version; ///< [in] version of this structure
+ bool Set; ///< [in] Flag to indicate Set or Get operation
+ uint32_t TargetBrightnessPercent; ///< [in] Target brightness percent
+ double PhaseinSpeedMultiplier; ///< [in] Phase-in speed multiplier for brightness to take effect
+ uint32_t NumBins; ///< [in,out] Number of histogram bins
+ bool Enable; ///< [in,out] For get calls, this represents current state & for set this
+ ///< represents future state
+ bool IsSupported; ///< [out] is DCE feature supported
+ uint32_t* pHistogram; ///< [out] Bin wise histogram data of size NumBins * sizeof(uint32_t) for
+ ///< current frame
+
+} ctl_dce_args_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get/Set Dynamic Contrast Enhancement
+///
+/// @details
+/// - To get the DCE feature status and, if feature is enabled, returns the
+/// current histogram, or to set the brightness at the phase-in speed
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDisplayOutput`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pDceArgs`
+/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+/// - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
+/// - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+/// - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+/// - ::CTL_RESULT_ERROR_INVALID_NULL_HANDLE - "Invalid or Null handle passed"
+/// - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
+/// - ::CTL_RESULT_ERROR_INVALID_OPERATION_TYPE - "Invalid operation type"
+/// - ::CTL_RESULT_ERROR_INVALID_ARGUMENT - "Invalid combination of parameters"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlGetSetDynamicContrastEnhancement(
+ ctl_display_output_handle_t hDisplayOutput, ///< [in] Handle to display output
+ ctl_dce_args_t* pDceArgs ///< [in,out] Dynamic Contrast Enhancement arguments
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Color model
+typedef enum _ctl_wire_format_color_model_t
+{
+ CTL_WIRE_FORMAT_COLOR_MODEL_RGB = 0, ///< Color model RGB
+ CTL_WIRE_FORMAT_COLOR_MODEL_YCBCR_420 = 1, ///< Color model YCBCR 420
+ CTL_WIRE_FORMAT_COLOR_MODEL_YCBCR_422 = 2, ///< Color model YCBCR 422
+ CTL_WIRE_FORMAT_COLOR_MODEL_YCBCR_444 = 3, ///< Color model YCBCR 444
+ CTL_WIRE_FORMAT_COLOR_MODEL_MAX
+
+} ctl_wire_format_color_model_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Operation type
+typedef enum _ctl_wire_format_operation_type_t
+{
+ CTL_WIRE_FORMAT_OPERATION_TYPE_GET = 0, ///< Get request
+ CTL_WIRE_FORMAT_OPERATION_TYPE_SET = 1, ///< Set request
+ CTL_WIRE_FORMAT_OPERATION_TYPE_RESTORE_DEFAULT = 2, ///< Restore to default values
+ CTL_WIRE_FORMAT_OPERATION_TYPE_MAX
+
+} ctl_wire_format_operation_type_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Wire Format
+typedef struct _ctl_wire_format_t
+{
+ uint32_t Size; ///< [in] size of this structure
+ uint8_t Version; ///< [in] version of this structure
+ ctl_wire_format_color_model_t ColorModel; ///< [in,out] Color model
+ ctl_output_bpc_flags_t ColorDepth; ///< [in,out] Color Depth
+
+} ctl_wire_format_t;
+
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CTL_MAX_WIREFORMAT_COLOR_MODELS_SUPPORTED
+/// @brief Maximum Wire Formats Supported
+#define CTL_MAX_WIREFORMAT_COLOR_MODELS_SUPPORTED 4
+#endif // CTL_MAX_WIREFORMAT_COLOR_MODELS_SUPPORTED
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get Set Wire Format
+typedef struct _ctl_get_set_wire_format_config_t
+{
+ uint32_t Size; ///< [in] size of this structure
+ uint8_t Version; ///< [in] version of this structure
+ ctl_wire_format_operation_type_t Operation; ///< [in] Get/Set Operation
+ ctl_wire_format_t SupportedWireFormat[CTL_MAX_WIREFORMAT_COLOR_MODELS_SUPPORTED]; ///< [out] Array of WireFormats supported
+ ctl_wire_format_t WireFormat; ///< [in,out] Current/Requested WireFormat based on Operation. During SET
+ ///< Operation, if multiple bpc is set, the MIN bpc will be applied
+
+} ctl_get_set_wire_format_config_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get/Set Color Format and Color Depth
+///
+/// @details
+/// - Get and Set the Color Format and Color Depth of a target
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDisplayOutput`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pGetSetWireFormatSetting`
+/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+/// - ::CTL_RESULT_ERROR_INVALID_ARGUMENT - "Invalid data passed as argument, WireFormat is not supported"
+/// - ::CTL_RESULT_ERROR_DISPLAY_NOT_ACTIVE - "Display not active"
+/// - ::CTL_RESULT_ERROR_INVALID_OPERATION_TYPE - "Invalid operation type"
+/// - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
+/// - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlGetSetWireFormat(
+ ctl_display_output_handle_t hDisplayOutput, ///< [in][release] Handle to display output
+ ctl_get_set_wire_format_config_t* pGetSetWireFormatSetting ///< [in][release] Get/Set Wire Format settings to be fetched/applied
+ );
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Various display settings
+typedef uint32_t ctl_display_setting_flags_t;
+typedef enum _ctl_display_setting_flag_t
+{
+ CTL_DISPLAY_SETTING_FLAG_LOW_LATENCY = CTL_BIT(0), ///< Low latency
+ CTL_DISPLAY_SETTING_FLAG_SOURCE_TM = CTL_BIT(1),///< Source tone mapping
+ CTL_DISPLAY_SETTING_FLAG_CONTENT_TYPE = CTL_BIT(2), ///< Content type
+ CTL_DISPLAY_SETTING_FLAG_QUANTIZATION_RANGE = CTL_BIT(3), ///< Quantization range, full range or limited range
+ CTL_DISPLAY_SETTING_FLAG_PICTURE_AR = CTL_BIT(4), ///< Picture aspect ratio
+ CTL_DISPLAY_SETTING_FLAG_AUDIO = CTL_BIT(5), ///< Audio settings
+ CTL_DISPLAY_SETTING_FLAG_MAX = 0x80000000
+
+} ctl_display_setting_flag_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Low latency setting
+typedef enum _ctl_display_setting_low_latency_t
+{
+ CTL_DISPLAY_SETTING_LOW_LATENCY_DEFAULT = 0, ///< Default
+ CTL_DISPLAY_SETTING_LOW_LATENCY_DISABLED = 1, ///< Disabled
+ CTL_DISPLAY_SETTING_LOW_LATENCY_ENABLED = 2, ///< Enabled
+ CTL_DISPLAY_SETTING_LOW_LATENCY_MAX
+
+} ctl_display_setting_low_latency_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Source tone mapping setting
+typedef enum _ctl_display_setting_sourcetm_t
+{
+ CTL_DISPLAY_SETTING_SOURCETM_DEFAULT = 0, ///< Default
+ CTL_DISPLAY_SETTING_SOURCETM_DISABLED = 1, ///< Disabled
+ CTL_DISPLAY_SETTING_SOURCETM_ENABLED = 2, ///< Enabled
+ CTL_DISPLAY_SETTING_SOURCETM_MAX
+
+} ctl_display_setting_sourcetm_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Content type settings
+typedef enum _ctl_display_setting_content_type_t
+{
+ CTL_DISPLAY_SETTING_CONTENT_TYPE_DEFAULT = 0, ///< Default content type used by driver. Driver will use internal
+ ///< techniques to determine content type and indicate to panel
+ CTL_DISPLAY_SETTING_CONTENT_TYPE_DISABLED = 1, ///< Content type indication is disabled
+ CTL_DISPLAY_SETTING_CONTENT_TYPE_DESKTOP = 2, ///< Typical desktop with a mix of text and graphics
+ CTL_DISPLAY_SETTING_CONTENT_TYPE_MEDIA = 3, ///< Video or media content
+ CTL_DISPLAY_SETTING_CONTENT_TYPE_GAMING = 4, ///< Gaming content
+ CTL_DISPLAY_SETTING_CONTENT_TYPE_MAX
+
+} ctl_display_setting_content_type_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Quantization range
+typedef enum _ctl_display_setting_quantization_range_t
+{
+ CTL_DISPLAY_SETTING_QUANTIZATION_RANGE_DEFAULT = 0, ///< Default based on video format
+ CTL_DISPLAY_SETTING_QUANTIZATION_RANGE_LIMITED_RANGE = 1, ///< Limited range
+ CTL_DISPLAY_SETTING_QUANTIZATION_RANGE_FULL_RANGE = 2, ///< Full range
+ CTL_DISPLAY_SETTING_QUANTIZATION_RANGE_MAX
+
+} ctl_display_setting_quantization_range_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Picture aspect ratio
+typedef uint32_t ctl_display_setting_picture_ar_flags_t;
+typedef enum _ctl_display_setting_picture_ar_flag_t
+{
+ CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_DEFAULT = CTL_BIT(0), ///< Default picture aspect ratio
+ CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_DISABLED = CTL_BIT(1), ///< Picture aspect ratio indication is explicitly disabled
+ CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_AR_4_3 = CTL_BIT(2),///< Aspect ratio of 4:3
+ CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_AR_16_9 = CTL_BIT(3), ///< Aspect ratio of 16:9
+ CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_AR_64_27 = CTL_BIT(4), ///< Aspect ratio of 64:27 or 21:9 anamorphic
+ CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_AR_256_135 = CTL_BIT(5),///< Aspect ratio of 256:135
+ CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_MAX = 0x80000000
+
+} ctl_display_setting_picture_ar_flag_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Audio settings
+typedef enum _ctl_display_setting_audio_t
+{
+ CTL_DISPLAY_SETTING_AUDIO_DEFAULT = 0, ///< Default audio settings, always enumerated and enabled if display
+ ///< supports it
+ CTL_DISPLAY_SETTING_AUDIO_DISABLED = 1, ///< Forcefully disable display audio end point enumeration to OS
+ CTL_DISPLAY_SETTING_AUDIO_MAX
+
+} ctl_display_setting_audio_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get/Set end display settings
+typedef struct _ctl_display_settings_t
+{
+ uint32_t Size; ///< [in] size of this structure
+ uint8_t Version; ///< [in] version of this structure
+ bool Set; ///< [in] Flag to indicate Set or Get operation. Default option for all
+ ///< features are reserved for Set=true calls, which will reset the setting
+ ///< to driver defaults.
+ ctl_display_setting_flags_t SupportedFlags; ///< [out] Display setting flags supported by the display.
+ ctl_display_setting_flags_t ControllableFlags; ///< [out] Display setting flags which can be controlled by the caller.
+ ///< Features which doesn't have this flag set cannot be changed by caller.
+ ctl_display_setting_flags_t ValidFlags; ///< [in,out] Display setting flags which caller can use to indicate the
+ ///< features it's interested in. This cannot have a bit set which is not
+ ///< supported by SupportedFlags and ControllableFlags.
+ ctl_display_setting_low_latency_t LowLatency; ///< [in,out] Low latency state of panel. For HDR10+ Gaming this need to be
+ ///< in ENABLED state.
+ ctl_display_setting_sourcetm_t SourceTM; ///< [in,out] Source tone mapping state known to panel. For HDR10+ Gaming
+ ///< this need to be in ENABLED state.
+ ctl_display_setting_content_type_t ContentType; ///< [in,out] Source content type known to panel.
+ ctl_display_setting_quantization_range_t QuantizationRange; ///< [in,out] Quantization range
+ ctl_display_setting_picture_ar_flags_t SupportedPictureAR; ///< [out] Supported Picture aspect ratios
+ ctl_display_setting_picture_ar_flag_t PictureAR;///< [in,out] Picture aspect ratio
+ ctl_display_setting_audio_t AudioSettings; ///< [in,out] Audio settings
+ uint32_t Reserved[25]; ///< [out] Reserved fields for future enumerations
+
+} ctl_display_settings_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Get/Set Display settings
+///
+/// @details
+/// - To get/set end display settings like low latency, HDR10+ signaling
+/// etc. which are controlled via info-frames/secondary data packets
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDisplayOutput`
+/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
+/// + `nullptr == pDisplaySettings`
+/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
+/// - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
+/// - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
+/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
+/// - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
+/// - ::CTL_RESULT_ERROR_INVALID_NULL_HANDLE - "Invalid or Null handle passed"
+/// - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
+/// - ::CTL_RESULT_ERROR_INVALID_OPERATION_TYPE - "Invalid operation type"
+/// - ::CTL_RESULT_ERROR_INVALID_ARGUMENT - "Invalid combination of parameters"
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlGetSetDisplaySettings(
+ ctl_display_output_handle_t hDisplayOutput, ///< [in] Handle to display output
+ ctl_display_settings_t* pDisplaySettings ///< [in,out] End display capabilities
+ );
+
#if !defined(__GNUC__)
#pragma endregion // display
@@ -4428,6 +5083,7 @@ typedef enum _ctl_freq_domain_t
{
CTL_FREQ_DOMAIN_GPU = 0, ///< GPU Core Domain.
CTL_FREQ_DOMAIN_MEMORY = 1, ///< Local Memory Domain.
+ CTL_FREQ_DOMAIN_MEDIA = 2, ///< Media Domain
CTL_FREQ_DOMAIN_MAX
} ctl_freq_domain_t;
@@ -4458,14 +5114,17 @@ typedef struct _ctl_freq_range_t
uint8_t Version; ///< [in] version of this structure
double min; ///< [in,out] The min frequency in MHz below which hardware frequency
///< management will not request frequencies. On input, setting to 0 will
- ///< permit the frequency to go down to the hardware minimum. On output, a
- ///< negative value indicates that no external minimum frequency limit is
- ///< in effect.
+ ///< permit the frequency to go down to the hardware minimum while setting
+ ///< to -1 will return the min frequency limit to the factory value (can be
+ ///< larger than the hardware min). On output, a negative value indicates
+ ///< that no external minimum frequency limit is in effect.
double max; ///< [in,out] The max frequency in MHz above which hardware frequency
///< management will not request frequencies. On input, setting to 0 or a
///< very big number will permit the frequency to go all the way up to the
- ///< hardware maximum. On output, a negative number indicates that no
- ///< external maximum frequency limit is in effect.
+ ///< hardware maximum while setting to -1 will return the max frequency to
+ ///< the factory value (which can be less than the hardware max). On
+ ///< output, a negative number indicates that no external maximum frequency
+ ///< limit is in effect.
} ctl_freq_range_t;
@@ -5307,8 +5966,8 @@ typedef struct _ctl_oc_properties_t
bool bSupported; ///< [out] Indicates if the adapter supports overclocking.
ctl_oc_control_info_t gpuFrequencyOffset; ///< [out] related to function ::ctlOverclockGpuFrequencyOffsetSet
ctl_oc_control_info_t gpuVoltageOffset; ///< [out] related to function ::ctlOverclockGpuVoltageOffsetSet
- ctl_oc_control_info_t vramFrequencyOffset; ///< [out] related to function ::ctlOverclockVramFrequencyOffsetSet
- ctl_oc_control_info_t vramVoltageOffset; ///< [out] related to function ::ctlOverclockVramVoltageOffsetSet
+ ctl_oc_control_info_t vramFrequencyOffset; ///< [out] Property Field Deprecated / No Longer Supported
+ ctl_oc_control_info_t vramVoltageOffset; ///< [out] Property Field Deprecated / No Longer Supported
ctl_oc_control_info_t powerLimit; ///< [out] related to function ::ctlOverclockPowerLimitSet
ctl_oc_control_info_t temperatureLimit; ///< [out] related to function ::ctlOverclockTemperatureLimitSet
@@ -5935,6 +6594,27 @@ ctlPowerTelemetryGet(
ctl_power_telemetry_t* pTelemetryInfo ///< [out] The overclocking properties for the specified domain.
);
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Reset all Overclock Settings to stock
+///
+/// @details
+/// - Reset all Overclock setting to default using single API call
+/// - This request resets any changes made to GpuFrequencyOffset,
+/// GpuVoltageOffset, PowerLimit, TemperatureLimit, GpuLock
+/// - This Doesn't reset any Fan Curve Changes. It can be reset using
+/// ctlFanSetDefaultMode
+///
+/// @returns
+/// - CTL_RESULT_SUCCESS
+/// - CTL_RESULT_ERROR_UNINITIALIZED
+/// - CTL_RESULT_ERROR_DEVICE_LOST
+/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
+/// + `nullptr == hDeviceHandle`
+CTL_APIEXPORT ctl_result_t CTL_APICALL
+ctlOverclockResetToDefault(
+ ctl_device_adapter_handle_t hDeviceHandle ///< [in][release] Handle to display adapter
+ );
+
#if !defined(__GNUC__)
#pragma endregion // overclock
@@ -6474,6 +7154,15 @@ typedef ctl_result_t (CTL_APICALL *ctl_pfnEnumerateDisplayOutputs_t)(
);
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlEnumerateI2CPinPairs
+typedef ctl_result_t (CTL_APICALL *ctl_pfnEnumerateI2CPinPairs_t)(
+ ctl_device_adapter_handle_t,
+ uint32_t*,
+ ctl_i2c_pin_pair_handle_t*
+ );
+
+
///////////////////////////////////////////////////////////////////////////////
/// @brief Function-pointer for ctlGetDeviceProperties
typedef ctl_result_t (CTL_APICALL *ctl_pfnGetDeviceProperties_t)(
@@ -6539,6 +7228,14 @@ typedef ctl_result_t (CTL_APICALL *ctl_pfnI2CAccess_t)(
);
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlI2CAccessOnPinPair
+typedef ctl_result_t (CTL_APICALL *ctl_pfnI2CAccessOnPinPair_t)(
+ ctl_i2c_pin_pair_handle_t,
+ ctl_i2c_access_pinpair_args_t*
+ );
+
+
///////////////////////////////////////////////////////////////////////////////
/// @brief Function-pointer for ctlAUXAccess
typedef ctl_result_t (CTL_APICALL *ctl_pfnAUXAccess_t)(
@@ -6752,12 +7449,67 @@ typedef ctl_result_t (CTL_APICALL *ctl_pfnGetSetCombinedDisplay_t)(
/// @brief Function-pointer for ctlGetSetDisplayGenlock
typedef ctl_result_t (CTL_APICALL *ctl_pfnGetSetDisplayGenlock_t)(
ctl_device_adapter_handle_t*,
- ctl_genlock_args_t**,
+ ctl_genlock_args_t*,
uint32_t,
ctl_device_adapter_handle_t*
);
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlGetVblankTimestamp
+typedef ctl_result_t (CTL_APICALL *ctl_pfnGetVblankTimestamp_t)(
+ ctl_display_output_handle_t,
+ ctl_vblank_ts_args_t*
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlLinkDisplayAdapters
+typedef ctl_result_t (CTL_APICALL *ctl_pfnLinkDisplayAdapters_t)(
+ ctl_device_adapter_handle_t,
+ ctl_lda_args_t*
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlUnlinkDisplayAdapters
+typedef ctl_result_t (CTL_APICALL *ctl_pfnUnlinkDisplayAdapters_t)(
+ ctl_device_adapter_handle_t
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlGetLinkedDisplayAdapters
+typedef ctl_result_t (CTL_APICALL *ctl_pfnGetLinkedDisplayAdapters_t)(
+ ctl_device_adapter_handle_t,
+ ctl_lda_args_t*
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlGetSetDynamicContrastEnhancement
+typedef ctl_result_t (CTL_APICALL *ctl_pfnGetSetDynamicContrastEnhancement_t)(
+ ctl_display_output_handle_t,
+ ctl_dce_args_t*
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlGetSetWireFormat
+typedef ctl_result_t (CTL_APICALL *ctl_pfnGetSetWireFormat_t)(
+ ctl_display_output_handle_t,
+ ctl_get_set_wire_format_config_t*
+ );
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlGetSetDisplaySettings
+typedef ctl_result_t (CTL_APICALL *ctl_pfnGetSetDisplaySettings_t)(
+ ctl_display_output_handle_t,
+ ctl_display_settings_t*
+ );
+
+
///////////////////////////////////////////////////////////////////////////////
/// @brief Function-pointer for ctlEnumEngineGroups
typedef ctl_result_t (CTL_APICALL *ctl_pfnEnumEngineGroups_t)(
@@ -7082,6 +7834,13 @@ typedef ctl_result_t (CTL_APICALL *ctl_pfnPowerTelemetryGet_t)(
);
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Function-pointer for ctlOverclockResetToDefault
+typedef ctl_result_t (CTL_APICALL *ctl_pfnOverclockResetToDefault_t)(
+ ctl_device_adapter_handle_t
+ );
+
+
///////////////////////////////////////////////////////////////////////////////
/// @brief Function-pointer for ctlPciGetProperties
typedef ctl_result_t (CTL_APICALL *ctl_pfnPciGetProperties_t)(
diff --git a/IntelPresentMon/Core/source/pmon/RawFrameDataMetricList.h b/IntelPresentMon/Core/source/pmon/RawFrameDataMetricList.h
index cfbff38f..c4274a95 100644
--- a/IntelPresentMon/Core/source/pmon/RawFrameDataMetricList.h
+++ b/IntelPresentMon/Core/source/pmon/RawFrameDataMetricList.h
@@ -41,8 +41,10 @@ namespace p2c::pmon
Element{.metricId = PM_METRIC_DISPLAY_LATENCY, .deviceId = 0 },
Element{.metricId = PM_METRIC_DISPLAYED_TIME, .deviceId = 0 },
Element{.metricId = PM_METRIC_ANIMATION_ERROR, .deviceId = 0 },
+ Element{.metricId = PM_METRIC_ANIMATION_TIME, .deviceId = 0 },
Element{.metricId = PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY, .deviceId = 0 },
Element{.metricId = PM_METRIC_CLICK_TO_PHOTON_LATENCY, .deviceId = 0 },
+ Element{.metricId = PM_METRIC_INSTRUMENTED_LATENCY, .deviceId = 0 },
Element{.metricId = PM_METRIC_GPU_POWER, .deviceId = activeDeviceId },
Element{.metricId = PM_METRIC_GPU_VOLTAGE, .deviceId = activeDeviceId },
diff --git a/IntelPresentMon/Core/source/pmon/RawFrameDataWriter.cpp b/IntelPresentMon/Core/source/pmon/RawFrameDataWriter.cpp
index 29c6174c..a9e76365 100644
--- a/IntelPresentMon/Core/source/pmon/RawFrameDataWriter.cpp
+++ b/IntelPresentMon/Core/source/pmon/RawFrameDataWriter.cpp
@@ -136,6 +136,7 @@ namespace p2c::pmon
if (metricId == PM_METRIC_DISPLAYED_TIME ||
metricId == PM_METRIC_DISPLAY_LATENCY ||
metricId == PM_METRIC_ANIMATION_ERROR ||
+ metricId == PM_METRIC_ANIMATION_TIME ||
metricId == PM_METRIC_CLICK_TO_PHOTON_LATENCY ||
metricId == PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY) {
flags |= Annotation_::FLAG_NAN_MEANS_NOT_AVAILABLE;
diff --git a/IntelPresentMon/Interprocess/source/metadata/EnumFrameType.h b/IntelPresentMon/Interprocess/source/metadata/EnumFrameType.h
index b6de5b72..83766999 100644
--- a/IntelPresentMon/Interprocess/source/metadata/EnumFrameType.h
+++ b/IntelPresentMon/Interprocess/source/metadata/EnumFrameType.h
@@ -7,4 +7,5 @@
X_(FRAME_TYPE, UNSPECIFIED, "Unspecified", "", "Frame rendered by unspecified technique") \
X_(FRAME_TYPE, APPLICATION, "Application", "", "Frame rendered by the target application") \
X_(FRAME_TYPE, REPEATED, "Application", "", "Frame rendered by the taget application") \
- X_(FRAME_TYPE, AMD_AFMF, "AMD_AFMF", "", "Frame generated by AMD Fluid Motion Frames")
+ X_(FRAME_TYPE, INTEL_XEFG, "Intel XeSS-FG", "", "Frame generated by Intel XeSS-FG") \
+ X_(FRAME_TYPE, AMD_AFMF, "AMD AFMF", "", "Frame generated by AMD Fluid Motion Frames")
diff --git a/IntelPresentMon/Interprocess/source/metadata/MetricList.h b/IntelPresentMon/Interprocess/source/metadata/MetricList.h
index b2044c27..80519f9b 100644
--- a/IntelPresentMon/Interprocess/source/metadata/MetricList.h
+++ b/IntelPresentMon/Interprocess/source/metadata/MetricList.h
@@ -31,6 +31,7 @@
\
X_(PM_METRIC_DISPLAYED_TIME, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_MILLISECONDS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, FULL_STATS) \
X_(PM_METRIC_ANIMATION_ERROR, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_MILLISECONDS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, FULL_STATS) \
+ X_(PM_METRIC_ANIMATION_TIME, PM_METRIC_TYPE_FRAME_EVENT, PM_UNIT_MILLISECONDS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_NONE) \
\
X_(PM_METRIC_SYNC_INTERVAL, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_VERTICAL_BLANKS, PM_DATA_TYPE_INT32, PM_DATA_TYPE_INT32, 0, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_MID_POINT) \
X_(PM_METRIC_PRESENT_FLAGS, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_DIMENSIONLESS, PM_DATA_TYPE_UINT32, PM_DATA_TYPE_UINT32, 0, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_MID_POINT) \
@@ -84,4 +85,6 @@
X_(PM_METRIC_CPU_TEMPERATURE, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_CELSIUS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_GRAPHICS_ADAPTER, FULL_STATS) \
X_(PM_METRIC_CPU_FREQUENCY, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_MEGAHERTZ, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_GRAPHICS_ADAPTER, FULL_STATS) \
X_(PM_METRIC_CPU_CORE_UTILITY, PM_METRIC_TYPE_DYNAMIC, PM_UNIT_PERCENT, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_VOID, 0, PM_DEVICE_TYPE_INDEPENDENT, FULL_STATS) \
- X_(PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_MILLISECONDS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_NON_ZERO_AVG, PM_STAT_PERCENTILE_01, PM_STAT_PERCENTILE_05, PM_STAT_PERCENTILE_10, PM_STAT_MAX)
+ X_(PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_MILLISECONDS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_NON_ZERO_AVG, PM_STAT_PERCENTILE_01, PM_STAT_PERCENTILE_05, PM_STAT_PERCENTILE_10, PM_STAT_MAX) \
+\
+ X_(PM_METRIC_INSTRUMENTED_LATENCY, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_MILLISECONDS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, FULL_STATS)
\ No newline at end of file
diff --git a/IntelPresentMon/PMInstaller/PresentMon.wxs b/IntelPresentMon/PMInstaller/PresentMon.wxs
index d91a9c96..9befe820 100644
--- a/IntelPresentMon/PMInstaller/PresentMon.wxs
+++ b/IntelPresentMon/PMInstaller/PresentMon.wxs
@@ -4,7 +4,7 @@
Id="*"
Name="Intel(R) PresentMon"
Language="1033"
- Version="2.1.0.0"
+ Version="2.3.0.0"
Manufacturer="Intel(R) Corporation"
UpgradeCode="CD0D489E-0FE7-452D-90D9-F94F3F5FF410">
@@ -16,7 +16,7 @@
-
+
diff --git a/IntelPresentMon/PresentMonAPI2/PresentMonAPI.h b/IntelPresentMon/PresentMonAPI2/PresentMonAPI.h
index ea5a44f1..0aab317d 100644
--- a/IntelPresentMon/PresentMonAPI2/PresentMonAPI.h
+++ b/IntelPresentMon/PresentMonAPI2/PresentMonAPI.h
@@ -115,6 +115,9 @@ extern "C" {
PM_METRIC_ANIMATION_ERROR,
PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY,
+ PM_METRIC_INSTRUMENTED_LATENCY,
+ PM_METRIC_ANIMATION_TIME,
+
};
enum PM_METRIC_TYPE
@@ -225,6 +228,7 @@ extern "C" {
PM_FRAME_TYPE_UNSPECIFIED,
PM_FRAME_TYPE_APPLICATION,
PM_FRAME_TYPE_REPEATED,
+ PM_FRAME_TYPE_INTEL_XEFG = 50,
PM_FRAME_TYPE_AMD_AFMF = 100,
};
diff --git a/IntelPresentMon/PresentMonAPI2/PresentMonAPI2.rc b/IntelPresentMon/PresentMonAPI2/PresentMonAPI2.rc
index cae893fe..660ee6ae 100644
Binary files a/IntelPresentMon/PresentMonAPI2/PresentMonAPI2.rc and b/IntelPresentMon/PresentMonAPI2/PresentMonAPI2.rc differ
diff --git a/IntelPresentMon/PresentMonAPI2Tests/CsvHelper.h b/IntelPresentMon/PresentMonAPI2Tests/CsvHelper.h
index 918fcf9c..7c982f00 100644
--- a/IntelPresentMon/PresentMonAPI2Tests/CsvHelper.h
+++ b/IntelPresentMon/PresentMonAPI2Tests/CsvHelper.h
@@ -40,9 +40,13 @@ enum Header {
Header_DisplayLatency,
Header_DisplayedTime,
Header_AnimationError,
+ Header_AnimationTime,
Header_ClickToPhotonLatency,
Header_AllInputToPhotonLatency,
+ // App Provided Metrics
+ Header_InstrumentedLatency,
+
// --v1_metrics
Header_Runtime,
Header_Dropped,
@@ -76,6 +80,7 @@ struct v2Metrics {
uint32_t presentFlags = 0;
uint32_t allowsTearing = 0;
PM_PRESENT_MODE presentMode = PM_PRESENT_MODE_UNKNOWN;
+ PM_FRAME_TYPE frameType = PM_FRAME_TYPE_NOT_SET;
uint64_t cpuFrameQpc = 0;
double cpuFrameTime = 0.;
double cpuBusy = 0.;
@@ -88,8 +93,10 @@ struct v2Metrics {
std::optional displayLatency;
std::optional displayedTime;
std::optional animationError;
+ std::optional animationTime;
std::optional clickToPhotonLatency;
std::optional AllInputToPhotonLatency;
+ std::optional InstrumentedLatency;
};
constexpr char const* GetHeaderString(Header h)
@@ -119,6 +126,7 @@ constexpr char const* GetHeaderString(Header h)
case Header_DisplayLatency: return "DisplayLatency";
case Header_DisplayedTime: return "DisplayedTime";
case Header_AnimationError: return "AnimationError";
+ case Header_AnimationTime: return "AnimationTime";
case Header_ClickToPhotonLatency: return "ClickToPhotonLatency";
case Header_AllInputToPhotonLatency: return "AllInputToPhotonLatency";
@@ -138,6 +146,9 @@ constexpr char const* GetHeaderString(Header h)
case Header_WasBatched: return "WasBatched";
case Header_DwmNotified: return "DwmNotified";
+
+ case Header_InstrumentedLatency: return "InstrumentedLatency";
+
default: return "";
}
}
@@ -245,10 +256,33 @@ void CharConvert::Convert(const std::string data, T& convertedData, Header co
else if (data == "Hardware Composed: Independent Flip") {
convertedData = PM_PRESENT_MODE_HARDWARE_COMPOSED_INDEPENDENT_FLIP;
}
+ else if (data == "Other") {
+ convertedData = PM_PRESENT_MODE_UNKNOWN;
+ }
else {
Assert::Fail(CreateErrorString(Header_PresentMode, line).c_str());
}
}
+ else if constexpr (std::is_same::value) {
+ if (data == "NotSet") {
+ convertedData = PM_FRAME_TYPE_NOT_SET;
+ }
+ else if (data == "Unspecified") {
+ convertedData = PM_FRAME_TYPE_UNSPECIFIED;
+ }
+ else if (data == "Application") {
+ convertedData = PM_FRAME_TYPE_APPLICATION;
+ }
+ else if (data == "Repeated") {
+ convertedData = PM_FRAME_TYPE_REPEATED;
+ }
+ else if (data == "AMD_AFMF") {
+ convertedData = PM_FRAME_TYPE_AMD_AFMF;
+ }
+ else {
+ Assert::Fail(CreateErrorString(Header_FrameType, line).c_str());
+ }
+ }
else
{
Assert::Fail(CreateErrorString(UnknownHeader, line).c_str());
@@ -297,7 +331,7 @@ class CsvParser {
bool Open(std::wstring const& path, uint32_t processId);
void Close();
bool VerifyBlobAgainstCsv(const std::string& processName, const unsigned int& processId,
- PM_QUERY_ELEMENT(&queryElements)[19], pmapi::BlobContainer& blobs);
+ PM_QUERY_ELEMENT(&queryElements)[22], pmapi::BlobContainer& blobs);
bool ResetCsv();
private:
@@ -326,7 +360,7 @@ CsvParser::CsvParser()
{}
bool CsvParser::VerifyBlobAgainstCsv(const std::string& processName, const unsigned int& processId,
- PM_QUERY_ELEMENT(&queryElements)[19], pmapi::BlobContainer& blobs)
+ PM_QUERY_ELEMENT(&queryElements)[22], pmapi::BlobContainer& blobs)
{
for (auto pBlob : blobs) {
@@ -338,19 +372,24 @@ bool CsvParser::VerifyBlobAgainstCsv(const std::string& processName, const unsig
const auto presentFlags = *reinterpret_cast(&pBlob[queryElements[3].dataOffset]);
const auto allowsTearing = *reinterpret_cast(&pBlob[queryElements[4].dataOffset]);
const auto presentMode = *reinterpret_cast(&pBlob[queryElements[5].dataOffset]);
- const auto cpuFrameQpc = *reinterpret_cast(&pBlob[queryElements[6].dataOffset]);
- const auto cpuFrameTime = *reinterpret_cast(&pBlob[queryElements[7].dataOffset]);
- const auto cpuBusy = *reinterpret_cast(&pBlob[queryElements[8].dataOffset]);
- const auto cpuWait = *reinterpret_cast(&pBlob[queryElements[9].dataOffset]);
- const auto gpuLatency = *reinterpret_cast(&pBlob[queryElements[10].dataOffset]);
- const auto gpuTime = *reinterpret_cast(&pBlob[queryElements[11].dataOffset]);
- const auto gpuBusy = *reinterpret_cast(&pBlob[queryElements[12].dataOffset]);
- const auto gpuWait = *reinterpret_cast(&pBlob[queryElements[13].dataOffset]);
- const auto displayLatency = *reinterpret_cast(&pBlob[queryElements[14].dataOffset]);
- const auto displayedTime = *reinterpret_cast(&pBlob[queryElements[15].dataOffset]);
- const auto animationError = *reinterpret_cast(&pBlob[queryElements[16].dataOffset]);
- const auto allInputToPhotonLatency = *reinterpret_cast(&pBlob[queryElements[17].dataOffset]);
- const auto clickToPhotonLatency = *reinterpret_cast(&pBlob[queryElements[18].dataOffset]);
+ const auto frameType = *reinterpret_cast(&pBlob[queryElements[6].dataOffset]);
+ const auto cpuFrameQpc = *reinterpret_cast(&pBlob[queryElements[7].dataOffset]);
+ const auto cpuFrameTime = *reinterpret_cast(&pBlob[queryElements[8].dataOffset]);
+ const auto cpuBusy = *reinterpret_cast(&pBlob[queryElements[9].dataOffset]);
+ const auto cpuWait = *reinterpret_cast(&pBlob[queryElements[10].dataOffset]);
+ const auto gpuLatency = *reinterpret_cast(&pBlob[queryElements[11].dataOffset]);
+ const auto gpuTime = *reinterpret_cast(&pBlob[queryElements[12].dataOffset]);
+ const auto gpuBusy = *reinterpret_cast(&pBlob[queryElements[13].dataOffset]);
+ const auto gpuWait = *reinterpret_cast(&pBlob[queryElements[14].dataOffset]);
+ const auto displayLatency = *reinterpret_cast(&pBlob[queryElements[15].dataOffset]);
+ const auto displayedTime = *reinterpret_cast(&pBlob[queryElements[16].dataOffset]);
+ const auto animationError = *reinterpret_cast(&pBlob[queryElements[17].dataOffset]);
+ const auto animationTime = *reinterpret_cast(&pBlob[queryElements[18].dataOffset]);
+ const auto allInputToPhotonLatency = *reinterpret_cast(&pBlob[queryElements[19].dataOffset]);
+ const auto clickToPhotonLatency = *reinterpret_cast(&pBlob[queryElements[20].dataOffset]);
+ const auto instrumentedLatency = *reinterpret_cast(&pBlob[queryElements[21].dataOffset]);
+
+
// Read rows until we find one with the process we are interested in
// or we are out of data.
@@ -381,7 +420,7 @@ bool CsvParser::VerifyBlobAgainstCsv(const std::string& processName, const unsig
columnsMatch = Validate(v2MetricRow_.processId, processId_);
break;
case Header_SwapChainAddress:
- columnsMatch = Validate(v2MetricRow_.swapChain, swapChain);
+ columnsMatch = Validate(v2MetricRow_.swapChain, swapChain);
break;
case Header_Runtime:
columnsMatch = Validate(v2MetricRow_.runtime, graphicsRuntime);
@@ -398,6 +437,9 @@ bool CsvParser::VerifyBlobAgainstCsv(const std::string& processName, const unsig
case Header_PresentMode:
columnsMatch = Validate(v2MetricRow_.presentMode, presentMode);
break;
+ case Header_FrameType:
+ columnsMatch = Validate(v2MetricRow_.frameType, frameType);
+ break;
case Header_CPUStartQPC:
columnsMatch = Validate(v2MetricRow_.cpuFrameQpc, cpuFrameQpc);
break;
@@ -468,6 +510,21 @@ bool CsvParser::VerifyBlobAgainstCsv(const std::string& processName, const unsig
}
}
break;
+ case Header_AnimationTime:
+ if (v2MetricRow_.animationTime.has_value()) {
+ columnsMatch = Validate(v2MetricRow_.animationTime.value(), animationTime);
+ }
+ else
+ {
+ if (std::isnan(animationTime)) {
+ columnsMatch = true;
+ }
+ else
+ {
+ columnsMatch = false;
+ }
+ }
+ break;
case Header_ClickToPhotonLatency:
if (v2MetricRow_.clickToPhotonLatency.has_value()) {
columnsMatch = Validate(v2MetricRow_.clickToPhotonLatency.value(), clickToPhotonLatency);
@@ -498,6 +555,21 @@ bool CsvParser::VerifyBlobAgainstCsv(const std::string& processName, const unsig
}
}
break;
+ case Header_InstrumentedLatency:
+ if (v2MetricRow_.InstrumentedLatency.has_value()) {
+ columnsMatch = Validate(v2MetricRow_.InstrumentedLatency.value(), instrumentedLatency);
+ }
+ else
+ {
+ if (std::isnan(instrumentedLatency)) {
+ columnsMatch = true;
+ }
+ else
+ {
+ columnsMatch = false;
+ }
+ }
+ break;
default:
columnsMatch = true;
break;
@@ -597,6 +669,7 @@ bool CsvParser::Open(std::wstring const& path, uint32_t processId) {
Header_PresentFlags,
Header_AllowsTearing,
Header_PresentMode,
+ Header_FrameType,
Header_CPUStartQPC,
Header_FrameTime,
Header_CPUBusy,
@@ -609,8 +682,10 @@ bool CsvParser::Open(std::wstring const& path, uint32_t processId) {
Header_DisplayLatency,
Header_DisplayedTime,
Header_AnimationError,
+ Header_AnimationTime,
Header_ClickToPhotonLatency,
- Header_AllInputToPhotonLatency});
+ Header_AllInputToPhotonLatency,
+ Header_InstrumentedLatency });
if (!columnsOK) {
Assert::Fail(L"Missing required columns");
@@ -697,6 +772,12 @@ void CsvParser::ConvertToMetricDataType(const char* data, Header columnId)
converter.Convert(data, v2MetricRow_.presentMode, columnId, line_);
}
break;
+ case Header_FrameType:
+ {
+ CharConvert converter;
+ converter.Convert(data, v2MetricRow_.frameType, columnId, line_);
+ }
+ break;
case Header_CPUStartQPC:
{
CharConvert converter;
@@ -791,6 +872,19 @@ void CsvParser::ConvertToMetricDataType(const char* data, Header columnId)
}
}
break;
+ case Header_AnimationTime:
+ {
+ if (strncmp(data, "NA", 2) != 0) {
+ double convertedData = 0.;
+ CharConvert converter;
+ converter.Convert(data, convertedData, columnId, line_);
+ v2MetricRow_.animationTime = convertedData;
+ }
+ else {
+ v2MetricRow_.animationTime.reset();
+ }
+ }
+ break;
case Header_ClickToPhotonLatency:
{
if (strncmp(data, "NA", 2) != 0) {
@@ -817,6 +911,21 @@ void CsvParser::ConvertToMetricDataType(const char* data, Header columnId)
}
}
break;
+ case Header_InstrumentedLatency:
+ {
+ if (strncmp(data, "NA", 2) != 0) {
+ double convertedData = 0.;
+ CharConvert converter;
+ converter.Convert(data, convertedData, columnId, line_);
+ v2MetricRow_.InstrumentedLatency = convertedData;
+ }
+ else
+ {
+ v2MetricRow_.InstrumentedLatency.reset();
+ }
+ }
+ break;
+
default:
Assert::Fail(CreateErrorString(UnknownHeader, line_).c_str());
}
diff --git a/IntelPresentMon/PresentMonAPI2Tests/EtlTests.cpp b/IntelPresentMon/PresentMonAPI2Tests/EtlTests.cpp
index 6676df03..12973c3d 100644
--- a/IntelPresentMon/PresentMonAPI2Tests/EtlTests.cpp
+++ b/IntelPresentMon/PresentMonAPI2Tests/EtlTests.cpp
@@ -17,7 +17,6 @@ namespace EtlTests
switch (present_mode) {
case PM_PRESENT_MODE::PM_PRESENT_MODE_HARDWARE_LEGACY_FLIP:
return "Hardware: Legacy Flip";
-
case PM_PRESENT_MODE::PM_PRESENT_MODE_HARDWARE_LEGACY_COPY_TO_FRONT_BUFFER:
return "Hardware: Legacy Copy to front buffer";
case PM_PRESENT_MODE::PM_PRESENT_MODE_HARDWARE_INDEPENDENT_FLIP:
@@ -31,7 +30,7 @@ namespace EtlTests
case PM_PRESENT_MODE::PM_PRESENT_MODE_COMPOSED_COPY_WITH_CPU_GDI:
return "Composed: Copy with CPU GDI";
default:
- return("Present Mode: Unknown");
+ return("Other");
}
}
@@ -138,7 +137,7 @@ namespace EtlTests
const uint32_t& processId, const std::string& processName, CsvParser& goldCsvFile) {
using namespace std::chrono_literals;
pmapi::ProcessTracker processTracker;
- static constexpr uint32_t numberOfBlobs = 150u;
+ static constexpr uint32_t numberOfBlobs = 4000u;
PM_QUERY_ELEMENT queryElements[]{
//{ PM_METRIC_APPLICATION, PM_STAT_NONE, 0, 0 },
@@ -148,6 +147,7 @@ namespace EtlTests
{ PM_METRIC_PRESENT_FLAGS, PM_STAT_NONE, 0, 0 },
{ PM_METRIC_ALLOWS_TEARING, PM_STAT_NONE, 0, 0 },
{ PM_METRIC_PRESENT_MODE, PM_STAT_NONE, 0, 0 },
+ { PM_METRIC_FRAME_TYPE, PM_STAT_NONE, 0, 0 },
{ PM_METRIC_CPU_START_QPC, PM_STAT_NONE, 0, 0 },
{ PM_METRIC_CPU_FRAME_TIME, PM_STAT_NONE, 0, 0 },
{ PM_METRIC_CPU_BUSY, PM_STAT_NONE, 0, 0 },
@@ -159,8 +159,10 @@ namespace EtlTests
{ PM_METRIC_DISPLAY_LATENCY, PM_STAT_NONE, 0, 0 },
{ PM_METRIC_DISPLAYED_TIME, PM_STAT_NONE, 0, 0 },
{ PM_METRIC_ANIMATION_ERROR, PM_STAT_NONE, 0, 0 },
+ { PM_METRIC_ANIMATION_TIME, PM_STAT_NONE, 0, 0 },
{ PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY, PM_STAT_NONE, 0, 0},
- { PM_METRIC_CLICK_TO_PHOTON_LATENCY, PM_STAT_NONE, 0, 0}
+ { PM_METRIC_CLICK_TO_PHOTON_LATENCY, PM_STAT_NONE, 0, 0},
+ { PM_METRIC_INSTRUMENTED_LATENCY, PM_STAT_NONE, 0, 0 }
};
auto frameQuery = pSession->RegisterFrameQuery(queryElements);
@@ -1653,6 +1655,150 @@ namespace EtlTests
}
}
+ RunTestCaseV2(std::move(pSession), processId, processName, goldCsvFile);
+ goldCsvFile.Close();
+ }
+ TEST_METHOD(Tc6v2CPXellOn10796Ext)
+ {
+ namespace bp = boost::process;
+ using namespace std::string_literals;
+ using namespace std::chrono_literals;
+
+ const uint32_t processId = 10796;
+ const std::string processName = "cpLauncher.exe";
+
+ bp::ipstream out; // Stream for reading the process's output
+ bp::opstream in; // Stream for writing to the process's input
+
+ const auto pipeName = R"(\\.\pipe\test-pipe-pmsvc-2)"s;
+ const auto introName = "PM_intro_test_nsm_2"s;
+ const auto etlName = "F:\\EtlTesting\\test_case_6.etl";
+ const auto goldCsvName = L"F:\\EtlTesting\\test_case_6.csv";
+
+ CsvParser goldCsvFile;
+ if (!goldCsvFile.Open(goldCsvName, processId)) {
+ return;
+ }
+
+ oChild.emplace("PresentMonService.exe"s,
+ "--timed-stop"s, "60000"s,
+ "--control-pipe"s, pipeName,
+ "--nsm-prefix"s, "pmon_nsm_utest_"s,
+ "--intro-nsm"s, introName,
+ "--etl-test-file"s, etlName,
+ bp::std_out > out, bp::std_in < in);
+
+ std::this_thread::sleep_for(1000ms);
+
+ std::unique_ptr pSession;
+ {
+ try
+ {
+ pSession = std::make_unique(pipeName.c_str(), introName.c_str());
+ }
+ catch (const std::exception& e) {
+ std::cout << "Error: " << e.what() << std::endl;
+ Assert::AreEqual(false, true, L"*** Connecting to service via named pipe");
+ return;
+ }
+ }
+
+ RunTestCaseV2(std::move(pSession), processId, processName, goldCsvFile);
+ goldCsvFile.Close();
+ }
+ TEST_METHOD(Tc7v2CPXellOnFgOn11320Ext)
+ {
+ namespace bp = boost::process;
+ using namespace std::string_literals;
+ using namespace std::chrono_literals;
+
+ const uint32_t processId = 11320;
+ const std::string processName = "cpLauncher.exe";
+
+ bp::ipstream out; // Stream for reading the process's output
+ bp::opstream in; // Stream for writing to the process's input
+
+ const auto pipeName = R"(\\.\pipe\test-pipe-pmsvc-2)"s;
+ const auto introName = "PM_intro_test_nsm_2"s;
+ const auto etlName = "F:\\EtlTesting\\test_case_7.etl";
+ const auto goldCsvName = L"F:\\EtlTesting\\test_case_7.csv";
+
+ CsvParser goldCsvFile;
+ if (!goldCsvFile.Open(goldCsvName, processId)) {
+ return;
+ }
+
+ oChild.emplace("PresentMonService.exe"s,
+ "--timed-stop"s, "60000"s,
+ "--control-pipe"s, pipeName,
+ "--nsm-prefix"s, "pmon_nsm_utest_"s,
+ "--intro-nsm"s, introName,
+ "--etl-test-file"s, etlName,
+ bp::std_out > out, bp::std_in < in);
+
+ std::this_thread::sleep_for(1000ms);
+
+ std::unique_ptr pSession;
+ {
+ try
+ {
+ pSession = std::make_unique(pipeName.c_str(), introName.c_str());
+ }
+ catch (const std::exception& e) {
+ std::cout << "Error: " << e.what() << std::endl;
+ Assert::AreEqual(false, true, L"*** Connecting to service via named pipe");
+ return;
+ }
+ }
+
+ RunTestCaseV2(std::move(pSession), processId, processName, goldCsvFile);
+ goldCsvFile.Close();
+ }
+ TEST_METHOD(Tc8v2ACSXellOnFgOn6920Ext)
+ {
+ namespace bp = boost::process;
+ using namespace std::string_literals;
+ using namespace std::chrono_literals;
+
+ const uint32_t processId = 6920;
+ const std::string processName = "scimitar_engine_win64_vs2022_llvm_fusion_dx12_px.exe";
+
+ bp::ipstream out; // Stream for reading the process's output
+ bp::opstream in; // Stream for writing to the process's input
+
+ const auto pipeName = R"(\\.\pipe\test-pipe-pmsvc-2)"s;
+ const auto introName = "PM_intro_test_nsm_2"s;
+ const auto etlName = "F:\\EtlTesting\\test_case_7.etl";
+ const auto goldCsvName = L"F:\\EtlTesting\\test_case_7.csv";
+
+ CsvParser goldCsvFile;
+ if (!goldCsvFile.Open(goldCsvName, processId)) {
+ return;
+ }
+
+ oChild.emplace("PresentMonService.exe"s,
+ "--timed-stop"s, "60000"s,
+ "--control-pipe"s, pipeName,
+ "--nsm-prefix"s, "pmon_nsm_utest_"s,
+ "--intro-nsm"s, introName,
+ "--etl-test-file"s, etlName,
+ bp::std_out > out, bp::std_in < in);
+
+ std::this_thread::sleep_for(1000ms);
+
+ std::unique_ptr pSession;
+ {
+ try
+ {
+ pSession = std::make_unique(pipeName.c_str(), introName.c_str());
+ }
+ catch (const std::exception& e) {
+ std::cout << "Error: " << e.what() << std::endl;
+ Assert::AreEqual(false, true, L"*** Connecting to service via named pipe");
+ return;
+ }
+ }
+
RunTestCaseV2(std::move(pSession), processId, processName, goldCsvFile);
goldCsvFile.Close();
}
diff --git a/IntelPresentMon/PresentMonMiddleware/ActionClient.h b/IntelPresentMon/PresentMonMiddleware/ActionClient.h
index da50cc27..e4e0b446 100644
--- a/IntelPresentMon/PresentMonMiddleware/ActionClient.h
+++ b/IntelPresentMon/PresentMonMiddleware/ActionClient.h
@@ -4,7 +4,7 @@
#include "../Interprocess/source/act/AsyncActionManager.h"
#include "../CommonUtilities/pipe/Pipe.h"
#include "../PresentMonService/AllActions.h"
-#include "../CommonUtilities/BuildId.h"
+#include "../Versioning/BuildId.h"
namespace pmon::mid
{
@@ -22,7 +22,7 @@ namespace pmon::mid
pipe_{ pipe::DuplexPipe::Connect(pipeName_, ioctx_) }
{
auto res = DispatchSync(OpenSession::Params{
- .clientPid = thisPid_, .clientBuildId = BuildIdShortHash()
+ .clientPid = thisPid_, .clientBuildId = bid::BuildIdShortHash()
});
pmlog_info(std::format("Opened session with server, build id = [{}]", res.serviceBuildId));
}
diff --git a/IntelPresentMon/PresentMonMiddleware/ConcreteMiddleware.cpp b/IntelPresentMon/PresentMonMiddleware/ConcreteMiddleware.cpp
index 9242ccf5..e367b097 100644
--- a/IntelPresentMon/PresentMonMiddleware/ConcreteMiddleware.cpp
+++ b/IntelPresentMon/PresentMonMiddleware/ConcreteMiddleware.cpp
@@ -293,6 +293,7 @@ namespace pmon::mid
case PM_METRIC_DROPPED_FRAMES:
case PM_METRIC_CLICK_TO_PHOTON_LATENCY:
case PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY:
+ case PM_METRIC_INSTRUMENTED_LATENCY:
pQuery->accumFpsData = true;
break;
case PM_METRIC_GPU_POWER:
@@ -473,6 +474,13 @@ struct FrameMetrics {
double mAnimationError;
double mClickToPhotonLatency;
double mAllInputPhotonLatency;
+ FrameType mFrameType;
+ double mInstrumentedDisplayLatency;
+
+ double mInstrumentedRenderLatency;
+ double mInstrumentedSleep;
+ double mInstrumentedGpuLatency;
+ double mInstrumentedReadyTimeToDisplayLatency;
};
// Copied from: PresentMon/OutputThread.cpp
@@ -480,17 +488,21 @@ void UpdateChain(
fpsSwapChainData* chain,
PmNsmPresentEvent const& p)
{
-
if (p.FinalState == PresentResult::Presented) {
// Used when calculating animation error
- if (chain->mLastPresentIsValid == true) {
- chain->mLastDisplayedCPUStart = chain->mLastPresent.PresentStartTime + chain->mLastPresent.TimeInPresent;
+ if (p.AppSimStartTime != 0) {
+ chain->mLastDisplayedSimStart = p.AppSimStartTime;
+ } else if (chain->mLastPresentIsValid == true) {
+ chain->mLastDisplayedSimStart = chain->mLastPresent.PresentStartTime +
+ chain->mLastPresent.TimeInPresent;
}
+ uint64_t mLastDisplayedScreenTime = p.DisplayedCount == 0 ? 0 : p.Displayed_ScreenTime[0];
+
// IntelPresentMon specifics:
if (chain->display_count == 0) {
- chain->display_0_screen_time = p.ScreenTime;
+ chain->display_0_screen_time = mLastDisplayedScreenTime;
}
- chain->display_n_screen_time = p.ScreenTime;
+ chain->mLastDisplayedScreenTime = mLastDisplayedScreenTime;
chain->display_count += 1;
}
@@ -500,143 +512,254 @@ void UpdateChain(
}
// Copied from: PresentMon/OutputThread.cpp
-void ReportMetrics(
+static void ReportMetricsHelper(
FakePMTraceSession const& pmSession,
fpsSwapChainData* chain,
PmNsmPresentEvent* p,
- PmNsmPresentEvent* nextPresent,
PmNsmPresentEvent const* nextDisplayedPresent)
{
- // Ignore repeated frames
- if (p->FrameType == FrameType::Repeated) {
- if (p->FrameId == chain->mLastPresent.FrameId) {
- return;
- }
-
- if (p->FrameId == nextPresent->FrameId &&
- nextPresent->ScreenTime != 0) {
- nextPresent->ScreenTime = p->ScreenTime;
- return;
- }
-
- p->FrameType = FrameType::Application;
- }
-
- // PB = PresentStartTime
- // PE = PresentEndTime
- // D = ScreenTime
+ // Figure out what display index to start processing.
//
- // chain->mLastPresent: PB--PE----D
- // p: | PB--PE----D
- // nextPresent: | | | PB--PE
- // ... | | | | PB--PE
- // nextDisplayedPresent: | | | | PB--PE----D
- // | | | | |
- // mCPUStart/mCPUBusy: |------->| | | |
- // mCPUWait: |-->| | |
- // mDisplayLatency: |----------------->| |
- // mDisplayedTime: |---------------------->|
-
- bool includeFrameData = chain->mIncludeFrameData && (p->FrameId != nextPresent->FrameId || p->FrameType == FrameType::Application);
-
- bool displayed = p->FinalState == PresentResult::Presented;
- double msGPUDuration = 0.0;
-
- FrameMetrics metrics;
- metrics.mCPUStart = chain->mLastPresent.PresentStartTime + chain->mLastPresent.TimeInPresent;
-
- if (includeFrameData) {
- msGPUDuration = pmSession.TimestampDeltaToUnsignedMilliSeconds(p->GPUStartTime, p->ReadyTime);
- metrics.mCPUBusy = pmSession.TimestampDeltaToUnsignedMilliSeconds(metrics.mCPUStart, p->PresentStartTime);
- metrics.mCPUWait = pmSession.TimestampDeltaToMilliSeconds(p->TimeInPresent);
- metrics.mGPULatency = pmSession.TimestampDeltaToUnsignedMilliSeconds(metrics.mCPUStart, p->GPUStartTime);
- metrics.mGPUBusy = pmSession.TimestampDeltaToMilliSeconds(p->GPUDuration);
- metrics.mVideoBusy = pmSession.TimestampDeltaToMilliSeconds(p->GPUVideoDuration);
- metrics.mGPUWait = std::max(0.0, msGPUDuration - metrics.mGPUBusy);
- } else {
- metrics.mCPUBusy = 0.0;
- metrics.mCPUWait = 0.0;
- metrics.mGPULatency = 0.0;
- metrics.mGPUBusy = 0.0;
- metrics.mVideoBusy = 0.0;
- metrics.mGPUWait = 0.0;
+ // The following cases are expected:
+ // p.Displayed empty and nextDisplayedPresent == nullptr: process p as not displayed
+ // p.Displayed with size N and nextDisplayedPresent == nullptr: process p.Displayed[0..N-2] as displayed, postponing N-1
+ // p.Displayed with size N and nextDisplayedPresent != nullptr: process p.Displayed[N-1] as displayed
+ auto displayCount = p->DisplayedCount;
+ bool displayed = p->FinalState == PresentResult::Presented && displayCount > 0;
+ size_t displayIndex = displayed && nextDisplayedPresent != nullptr ? displayCount - 1 : 0;
+
+ // Figure out what display index to attribute cpu work, gpu work, animation error, and input
+ // latency to. Start looking from the current display index.
+ size_t appIndex = 0;
+ for (size_t i = displayIndex; i < displayCount; ++i) {
+ if (p->Displayed_FrameType[i] == FrameType::NotSet ||
+ p->Displayed_FrameType[i] == FrameType::Application) {
+ appIndex = i;
+ break;
+ }
}
- if (displayed) {
- metrics.mDisplayLatency = pmSession.TimestampDeltaToUnsignedMilliSeconds(metrics.mCPUStart, p->ScreenTime);
- metrics.mDisplayedTime = pmSession.TimestampDeltaToUnsignedMilliSeconds(p->ScreenTime, nextDisplayedPresent->ScreenTime);
- metrics.mAnimationError = chain->mLastDisplayedCPUStart == 0 ? 0 : pmSession.TimestampDeltaToMilliSeconds(p->ScreenTime - chain->display_n_screen_time,
- metrics.mCPUStart - chain->mLastDisplayedCPUStart);
- // If we have an input time that was associated with a dropped frame calculate the latency
- // based on this Presents screen time.
- auto updatedInputTime = chain->mLastReceivedNotDisplayedAllInputTime == 0 ? 0 :
- pmSession.TimestampDeltaToUnsignedMilliSeconds(chain->mLastReceivedNotDisplayedAllInputTime, p->ScreenTime);
- // If this present doesn't have an input associated with it use the time from the latest input time calculated
- // above. If there is an input associated with the Present use it.
- metrics.mAllInputPhotonLatency = p->InputTime == 0 ? updatedInputTime :
- pmSession.TimestampDeltaToUnsignedMilliSeconds(p->InputTime, p->ScreenTime);
- // Do the same for the mouse click input
- updatedInputTime = chain->mLastReceivedNotDisplayedMouseClickTime == 0 ? 0 :
- pmSession.TimestampDeltaToUnsignedMilliSeconds(chain->mLastReceivedNotDisplayedMouseClickTime, p->ScreenTime);
- metrics.mClickToPhotonLatency = p->MouseClickTime == 0 ? updatedInputTime :
- pmSession.TimestampDeltaToUnsignedMilliSeconds(p->MouseClickTime, p->ScreenTime);
-
- chain->mLastReceivedNotDisplayedAllInputTime = 0;
- chain->mLastReceivedNotDisplayedMouseClickTime = 0;
- } else {
- metrics.mDisplayLatency = 0.0;
- metrics.mDisplayedTime = 0.0;
- metrics.mAnimationError = 0.0;
- metrics.mClickToPhotonLatency = 0.0;
- metrics.mAllInputPhotonLatency = 0.0;
- if (p->InputTime != 0) {
- chain->mLastReceivedNotDisplayedAllInputTime = p->InputTime;
+ do {
+ // PB = PresentStartTime
+ // PE = PresentEndTime
+ // D = ScreenTime
+ //
+ // chain->mLastPresent: PB--PE----D
+ // p: | PB--PE----D
+ // ... | | | | PB--PE
+ // nextDisplayedPresent: | | | | PB--PE----D
+ // | | | | |
+ // mCPUStart/mCPUBusy: |------->| | | |
+ // mCPUWait: |-->| | |
+ // mDisplayLatency: |----------------->| |
+ // mDisplayedTime: |---------------------->|
+
+ // Lookup the ScreenTime and next ScreenTime
+ uint64_t screenTime = 0;
+ uint64_t nextScreenTime = 0;
+ if (displayed) {
+ screenTime = p->Displayed_ScreenTime[displayIndex];
+
+ if (displayIndex + 1 < displayCount) {
+ nextScreenTime = p->Displayed_ScreenTime[displayIndex + 1];
+ } else if (nextDisplayedPresent != nullptr) {
+ nextScreenTime = nextDisplayedPresent->Displayed_ScreenTime[0];
+ } else {
+ return;
+ }
}
- if (p->MouseClickTime != 0) {
- chain->mLastReceivedNotDisplayedMouseClickTime = p->MouseClickTime;
+
+ double msGPUDuration = 0.0;
+
+ FrameMetrics metrics;
+
+ metrics.mCPUStart = chain->mLastPresent.PresentStartTime + chain->mLastPresent.TimeInPresent;
+
+ if (displayIndex == appIndex) {
+ msGPUDuration = pmSession.TimestampDeltaToUnsignedMilliSeconds(p->GPUStartTime, p->ReadyTime);
+ metrics.mCPUBusy = pmSession.TimestampDeltaToUnsignedMilliSeconds(metrics.mCPUStart, p->PresentStartTime);
+ metrics.mCPUWait = pmSession.TimestampDeltaToMilliSeconds(p->TimeInPresent);
+ metrics.mGPULatency = pmSession.TimestampDeltaToUnsignedMilliSeconds(metrics.mCPUStart, p->GPUStartTime);
+ metrics.mGPUBusy = pmSession.TimestampDeltaToMilliSeconds(p->GPUDuration);
+ metrics.mVideoBusy = pmSession.TimestampDeltaToMilliSeconds(p->GPUVideoDuration);
+ metrics.mGPUWait = std::max(0.0, msGPUDuration - metrics.mGPUBusy);
+ // Need both AppSleepStart and AppSleepEnd to calculate XellSleep
+ metrics.mInstrumentedSleep = (p->AppSleepEndTime == 0 || p->AppSleepStartTime == 0) ? 0 :
+ pmSession.TimestampDeltaToUnsignedMilliSeconds(p->AppSleepStartTime, p->AppSleepEndTime);
+ // If there isn't a valid sleep end time use the sim start time
+ auto instrumentedStartTime = p->AppSleepEndTime != 0 ? p->AppSleepEndTime : p->AppSimStartTime;
+ // If neither the sleep end time or sim start time is valid, there is no
+ // way to calculate the Xell Gpu latency
+ metrics.mInstrumentedGpuLatency = instrumentedStartTime == 0 ? 0 :
+ pmSession.TimestampDeltaToUnsignedMilliSeconds(instrumentedStartTime, p->GPUStartTime);
+ } else {
+ metrics.mCPUBusy = 0;
+ metrics.mCPUWait = 0;
+ metrics.mGPULatency = 0;
+ metrics.mGPUBusy = 0;
+ metrics.mVideoBusy = 0;
+ metrics.mGPUWait = 0;
+ metrics.mInstrumentedSleep = 0;
+ metrics.mInstrumentedGpuLatency = 0;
+ }
+
+ if (displayed) {
+ metrics.mDisplayLatency = pmSession.TimestampDeltaToUnsignedMilliSeconds(metrics.mCPUStart, screenTime);
+ metrics.mDisplayedTime = pmSession.TimestampDeltaToUnsignedMilliSeconds(screenTime, nextScreenTime);
+ // If AppRenderSubmitStart is valid calculate the render latency
+ metrics.mInstrumentedRenderLatency = p->AppRenderSubmitStartTime == 0 ? 0 :
+ pmSession.TimestampDeltaToUnsignedMilliSeconds(p->AppRenderSubmitStartTime, screenTime);
+ metrics.mInstrumentedReadyTimeToDisplayLatency = pmSession.TimestampDeltaToUnsignedMilliSeconds(p->ReadyTime, screenTime);
+ // If there isn't a valid sleep end time use the sim start time
+ auto xellStartTime = p->AppSleepEndTime != 0 ? p->AppSleepEndTime : p->AppSimStartTime;
+ // If neither the sleep end time or sim start time is valid, there is no
+ // way to calculate the Xell Gpu latency
+ metrics.mInstrumentedDisplayLatency = xellStartTime == 0 ? 0 :
+ pmSession.TimestampDeltaToUnsignedMilliSeconds(xellStartTime, screenTime);
+ } else {
+ metrics.mDisplayLatency = 0;
+ metrics.mDisplayedTime = 0;
+ metrics.mInstrumentedRenderLatency = 0;
+ metrics.mInstrumentedReadyTimeToDisplayLatency = 0;
+ metrics.mInstrumentedDisplayLatency = 0;
+ }
+
+ if (displayIndex == appIndex) {
+ if (displayed) {
+ auto updatedInputTime = chain->mLastReceivedNotDisplayedAllInputTime == 0 ? 0 :
+ pmSession.TimestampDeltaToUnsignedMilliSeconds(chain->mLastReceivedNotDisplayedAllInputTime, screenTime);
+ metrics.mAllInputPhotonLatency = p->InputTime == 0 ? updatedInputTime :
+ pmSession.TimestampDeltaToUnsignedMilliSeconds(p->InputTime, screenTime);
+
+ updatedInputTime = chain->mLastReceivedNotDisplayedMouseClickTime == 0 ? 0 :
+ pmSession.TimestampDeltaToUnsignedMilliSeconds(chain->mLastReceivedNotDisplayedMouseClickTime, screenTime);
+ metrics.mClickToPhotonLatency = p->MouseClickTime == 0 ? updatedInputTime :
+ pmSession.TimestampDeltaToUnsignedMilliSeconds(p->MouseClickTime, screenTime);
+
+ chain->mLastReceivedNotDisplayedAllInputTime = 0;
+ chain->mLastReceivedNotDisplayedMouseClickTime = 0;
+ }
+ else {
+ metrics.mClickToPhotonLatency = 0;
+ metrics.mAllInputPhotonLatency = 0;
+ if (p->InputTime != 0) {
+ chain->mLastReceivedNotDisplayedAllInputTime = p->InputTime;
+ }
+ if (p->MouseClickTime != 0) {
+ chain->mLastReceivedNotDisplayedMouseClickTime = p->MouseClickTime;
+ }
+ }
+ } else {
+ metrics.mClickToPhotonLatency = 0;
+ metrics.mAllInputPhotonLatency = 0;
}
- }
- if (p->FrameId == nextPresent->FrameId) {
- if (includeFrameData) {
- chain->mIncludeFrameData = false;
+ if (displayed && displayIndex == appIndex && chain->mLastDisplayedSimStart != 0) {
+ // Calculate the sim start time based on if AppSimStartTime is non-zero
+ auto simStartTime = p->AppSimStartTime != 0 ? p->AppSimStartTime : metrics.mCPUStart;
+ metrics.mAnimationError = pmSession.TimestampDeltaToMilliSeconds(screenTime - chain->mLastDisplayedScreenTime,
+ simStartTime - chain->mLastDisplayedSimStart);
+ chain->mAnimationError.push_back(std::abs(metrics.mAnimationError));
+ } else {
+ metrics.mAnimationError = 0;
}
- } else {
- UpdateChain(chain, *p);
- }
- // IntelPresentMon specifics:
+ if (p->DisplayedCount == 0) {
+ metrics.mFrameType = FrameType::NotSet;
+ } else {
+ metrics.mFrameType = p->Displayed_FrameType[displayIndex];
+ }
- if (includeFrameData) {
- chain->mCPUBusy .push_back(metrics.mCPUBusy);
- chain->mCPUWait .push_back(metrics.mCPUWait);
- chain->mGPULatency .push_back(metrics.mGPULatency);
- chain->mGPUBusy .push_back(metrics.mGPUBusy);
- chain->mVideoBusy .push_back(metrics.mVideoBusy);
- chain->mGPUWait .push_back(metrics.mGPUWait);
- chain->mAnimationError.push_back(std::abs(metrics.mAnimationError));
- }
+ if (displayIndex == appIndex) {
+ chain->mCPUBusy .push_back(metrics.mCPUBusy);
+ chain->mCPUWait .push_back(metrics.mCPUWait);
+ chain->mGPULatency .push_back(metrics.mGPULatency);
+ chain->mGPUBusy .push_back(metrics.mGPUBusy);
+ chain->mVideoBusy .push_back(metrics.mVideoBusy);
+ chain->mGPUWait .push_back(metrics.mGPUWait);
+ chain->mInstrumentedSleep .push_back(metrics.mInstrumentedSleep);
+ chain->mInstrumentedGpuLatency.push_back(metrics.mInstrumentedGpuLatency);
+ }
- if (displayed) {
- if (chain->mAppDisplayedTime.empty() || p->FrameType == FrameType::NotSet || p->FrameType == FrameType::Application) {
- chain->mAppDisplayedTime.push_back(metrics.mDisplayedTime);
+ if (displayed) {
+ chain->mDisplayLatency .push_back(metrics.mDisplayLatency);
+ chain->mDisplayedTime .push_back(metrics.mDisplayedTime);
+ chain->mDropped .push_back(0.0);
} else {
- chain->mAppDisplayedTime.back() += metrics.mDisplayedTime;
+ chain->mDropped .push_back(1.0);
+ }
+
+ if (displayed) {
+ if (chain->mAppDisplayedTime.empty() || displayIndex == appIndex) {
+ chain->mAppDisplayedTime.push_back(metrics.mDisplayedTime);
+ } else {
+ chain->mAppDisplayedTime.back() += metrics.mDisplayedTime;
+ }
}
- if (p->MouseClickTime) {
- chain->mClickToPhotonLatency.push_back(metrics.mClickToPhotonLatency);
+ if (displayed && displayIndex == appIndex) {
+ if (metrics.mAllInputPhotonLatency != 0) {
+ chain->mAllInputToPhotonLatency.push_back(metrics.mAllInputPhotonLatency);
+ }
+ if (metrics.mClickToPhotonLatency != 0) {
+ chain->mClickToPhotonLatency.push_back(metrics.mClickToPhotonLatency);
+ }
}
- if (p->InputTime) {
- chain->mAllInputToPhotonLatency.push_back(metrics.mAllInputPhotonLatency);
+ if (displayed && displayIndex == appIndex) {
+ if (metrics.mInstrumentedRenderLatency != 0) {
+ chain->mInstrumentedRenderLatency.push_back(metrics.mInstrumentedRenderLatency);
+ }
+ if (metrics.mInstrumentedDisplayLatency != 0) {
+ chain->mInstrumentedDisplayLatency.push_back(metrics.mInstrumentedDisplayLatency);
+ }
+ if (metrics.mInstrumentedReadyTimeToDisplayLatency != 0) {
+ chain->mInstrumentedReadyTimeToDisplayLatency.push_back(metrics.mInstrumentedReadyTimeToDisplayLatency);
+ }
}
- chain->mDisplayLatency.push_back(metrics.mDisplayLatency);
- chain->mDisplayedTime .push_back(metrics.mDisplayedTime);
- chain->mDropped .push_back(0.0);
+ displayIndex += 1;
+ } while (displayIndex < displayCount);
+
+ UpdateChain(chain, *p);
+}
+
+static void ReportMetrics(
+ FakePMTraceSession const& pmSession,
+ fpsSwapChainData* chain,
+ PmNsmPresentEvent* p)
+{
+ // For the chain's first present, we just initialize mLastPresent to give a baseline for the
+ // first frame.
+ if (!chain->mLastPresentIsValid) {
+ UpdateChain(chain, *p);
+ return;
+ }
+
+ // If chain->mPendingPresents is non-empty, then it contains a displayed present followed by
+ // some number of discarded presents. If the displayed present has multiple Displayed entries,
+ // all but the last have already been handled.
+ //
+ // If p is displayed, then we can complete all pending presents, and complete any flips in p
+ // except for the last one, but then we have to add p to the pending list to wait for the next
+ // displayed frame.
+ //
+ // If p is not displayed, we can process it now unless it is blocked behind an earlier present
+ // waiting for the next displayed one, in which case we need to add it to the pending list as
+ // well.
+ if (p->FinalState == PresentResult::Presented) {
+ for (auto& p2 : chain->mPendingPresents) {
+ ReportMetricsHelper(pmSession, chain, &p2, p);
+ }
+ ReportMetricsHelper(pmSession, chain, p, nullptr);
+ chain->mPendingPresents.clear();
+ chain->mPendingPresents.push_back(*p);
} else {
- chain->mDropped .push_back(1.0);
+ if (chain->mPendingPresents.empty()) {
+ ReportMetricsHelper(pmSession, chain, p, nullptr);
+ } else {
+ chain->mPendingPresents.push_back(*p);
+ }
}
}
@@ -733,24 +856,7 @@ void ReportMetrics(
// The following code block copied from: PresentMon/OutputThread.cpp
if (chain->mLastPresentIsValid) {
- auto numPendingPresents = chain->mPendingPresents.size();
- if (numPendingPresents > 0) {
- if (presentEvent->FinalState == PresentResult::Presented) {
- size_t i = 1;
- for ( ; i < numPendingPresents; ++i) {
- ReportMetrics(pmSession, chain, &chain->mPendingPresents[i - 1], &chain->mPendingPresents[i], presentEvent);
- }
- ReportMetrics(pmSession, chain, &chain->mPendingPresents[i - 1], presentEvent, presentEvent);
- chain->mPendingPresents.clear();
- } else {
- if (chain->mPendingPresents[0].FinalState != PresentResult::Presented) {
- ReportMetrics(pmSession, chain, &chain->mPendingPresents[0], presentEvent, nullptr);
- chain->mPendingPresents.clear();
- }
- }
- }
-
- chain->mPendingPresents.push_back(*presentEvent);
+ ReportMetrics(pmSession, chain, presentEvent);
} else {
UpdateChain(chain, *presentEvent);
}
@@ -952,16 +1058,23 @@ void ReportMetrics(
SetActiveGraphicsAdapter(*devId);
}
+ uint64_t simStartTime = 0;
+ auto iter = appSimStartTime.find(processId);
+ if (iter != appSimStartTime.end()) {
+ simStartTime = iter->second;
+ }
+
// context transmits various data that applies to each gather command in the query
- PM_FRAME_QUERY::Context ctx{ nsm_hdr->start_qpc, pShmClient->GetQpcFrequency().QuadPart };
+ PM_FRAME_QUERY::Context ctx{ nsm_hdr->start_qpc, pShmClient->GetQpcFrequency().QuadPart, simStartTime };
- for (uint32_t i = 0; i < frames_to_copy; i++) {
+ while (frames_copied < frames_to_copy) {
const PmNsmFrameData* pCurrentFrameData = nullptr;
+ const PmNsmFrameData* pNextFrameData = nullptr;
const PmNsmFrameData* pFrameDataOfLastPresented = nullptr;
const PmNsmFrameData* pFrameDataOfNextDisplayed = nullptr;
const PmNsmFrameData* pFrameDataOfLastDisplayed = nullptr;
const PmNsmFrameData* pPreviousFrameDataOfLastDisplayed = nullptr;
- const auto status = pShmClient->ConsumePtrToNextNsmFrameData(&pCurrentFrameData,
+ const auto status = pShmClient->ConsumePtrToNextNsmFrameData(&pCurrentFrameData, &pNextFrameData,
&pFrameDataOfNextDisplayed, &pFrameDataOfLastPresented, &pFrameDataOfLastDisplayed, &pPreviousFrameDataOfLastDisplayed);
if (status != PM_STATUS::PM_STATUS_SUCCESS) {
pmlog_error("Error while trying to get frame data from shared memory").diag();
@@ -976,14 +1089,35 @@ void ReportMetrics(
pFrameDataOfLastPresented,
pFrameDataOfLastDisplayed,
pPreviousFrameDataOfLastDisplayed);
- pQuery->GatherToBlob(ctx, pBlob);
- pBlob += pQuery->GetBlobSize();
- frames_copied++;
- }
+ if (simStartTime == 0 && ctx.firstAppSimStartTime != 0) {
+ simStartTime = ctx.firstAppSimStartTime;
+ }
+
+ if (ctx.dropped) {
+ pQuery->GatherToBlob(ctx, pBlob);
+ pBlob += pQuery->GetBlobSize();
+ frames_copied++;
+ } else {
+ while (ctx.sourceFrameDisplayIndex < ctx.pSourceFrameData->present_event.DisplayedCount) {
+ pQuery->GatherToBlob(ctx, pBlob);
+ pBlob += pQuery->GetBlobSize();
+ frames_copied++;
+ ctx.sourceFrameDisplayIndex++;
+ }
+ }
+ }
+ // Check to see if the next frame produces more frames than we can store in the
+ // the blob.
+ if (frames_copied + pNextFrameData->present_event.DisplayedCount >= frames_to_copy) {
+ break;
+ }
}
// Set to the actual number of frames copied
numFrames = frames_copied;
+ if (simStartTime != 0) {
+ appSimStartTime[processId] = simStartTime;
+ }
}
void ConcreteMiddleware::CalculateFpsMetric(fpsSwapChainData& swapChain, const PM_QUERY_ELEMENT& element, uint8_t* pBlob, LARGE_INTEGER qpcFrequency)
@@ -1011,7 +1145,7 @@ void ReportMetrics(
reinterpret_cast(pBlob[element.dataOffset]) = swapChain.mLastPresent.SupportsTearing;
break;
case PM_METRIC_FRAME_TYPE:
- reinterpret_cast(pBlob[element.dataOffset]) = (PM_FRAME_TYPE)swapChain.mLastPresent.FrameType;
+ reinterpret_cast(pBlob[element.dataOffset]) = (PM_FRAME_TYPE)(swapChain.mLastPresent.DisplayedCount == 0 ? FrameType::NotSet : swapChain.mLastPresent.Displayed_FrameType[0]);
break;
case PM_METRIC_CPU_BUSY:
output = CalculateStatistic(swapChain.mCPUBusy, element.stat);
@@ -1057,29 +1191,24 @@ void ReportMetrics(
break;
case PM_METRIC_PRESENTED_FPS:
{
- std::vector presented_fps(swapChain.mCPUBusy.size());
+ std::vector presented_fts(swapChain.mCPUBusy.size());
for (size_t i = 0; i < swapChain.mCPUBusy.size(); ++i) {
- presented_fps[i] = 1000.0 / (swapChain.mCPUBusy[i] + swapChain.mCPUWait[i]);
+ presented_fts[i] = swapChain.mCPUBusy[i] + swapChain.mCPUWait[i];
}
- output = CalculateStatistic(presented_fps, element.stat);
+ output = CalculateStatistic(presented_fts, element.stat, true);
+ output = output == 0 ? 0 : 1000.0 / output;
break;
}
case PM_METRIC_APPLICATION_FPS:
{
- std::vector application_fps(swapChain.mAppDisplayedTime.size());
- for (size_t i = 0; i < swapChain.mAppDisplayedTime.size(); ++i) {
- application_fps[i] = 1000.0 / swapChain.mAppDisplayedTime[i];
- }
- output = CalculateStatistic(application_fps, element.stat);
+ output = CalculateStatistic(swapChain.mAppDisplayedTime, element.stat, true);
+ output = output == 0 ? 0 : 1000.0 / output;
break;
}
case PM_METRIC_DISPLAYED_FPS:
{
- std::vector displayed_fps(swapChain.mDisplayedTime.size());
- for (size_t i = 0; i < swapChain.mDisplayedTime.size(); ++i) {
- displayed_fps[i] = 1000.0 / swapChain.mDisplayedTime[i];
- }
- output = CalculateStatistic(displayed_fps, element.stat);
+ output = CalculateStatistic(swapChain.mDisplayedTime, element.stat, true);
+ output = output == 0 ? 0 : 1000.0 / output;
break;
}
case PM_METRIC_DROPPED_FRAMES:
@@ -1091,6 +1220,9 @@ void ReportMetrics(
case PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY:
output = CalculateStatistic(swapChain.mAllInputToPhotonLatency, element.stat);
break;
+ case PM_METRIC_INSTRUMENTED_LATENCY:
+ output = CalculateStatistic(swapChain.mInstrumentedDisplayLatency, element.stat);
+ break;
default:
output = 0.;
break;
@@ -1114,8 +1246,8 @@ void ReportMetrics(
}
return;
}
-
- double ConcreteMiddleware::CalculateStatistic(std::vector& inData, PM_STAT stat) const
+
+ double ConcreteMiddleware::CalculateStatistic(std::vector& inData, PM_STAT stat, bool invert) const
{
if (inData.size() == 1) {
return inData[0];
@@ -1133,17 +1265,21 @@ void ReportMetrics(
}
return sum / inData.size();
}
- case PM_STAT_PERCENTILE_99: return CalculatePercentile(inData, 0.99);
- case PM_STAT_PERCENTILE_95: return CalculatePercentile(inData, 0.95);
- case PM_STAT_PERCENTILE_90: return CalculatePercentile(inData, 0.90);
- case PM_STAT_PERCENTILE_01: return CalculatePercentile(inData, 0.01);
- case PM_STAT_PERCENTILE_05: return CalculatePercentile(inData, 0.05);
- case PM_STAT_PERCENTILE_10: return CalculatePercentile(inData, 0.10);
+ case PM_STAT_PERCENTILE_99: return CalculatePercentile(inData, 0.99, invert);
+ case PM_STAT_PERCENTILE_95: return CalculatePercentile(inData, 0.95, invert);
+ case PM_STAT_PERCENTILE_90: return CalculatePercentile(inData, 0.90, invert);
+ case PM_STAT_PERCENTILE_01: return CalculatePercentile(inData, 0.01, invert);
+ case PM_STAT_PERCENTILE_05: return CalculatePercentile(inData, 0.05, invert);
+ case PM_STAT_PERCENTILE_10: return CalculatePercentile(inData, 0.10, invert);
case PM_STAT_MAX:
{
double max = inData[0];
for (size_t i = 1; i < inData.size(); ++i) {
- max = std::max(max, inData[i]);
+ if (invert) {
+ max = std::min(max, inData[i]);
+ } else {
+ max = std::max(max, inData[i]);
+ }
}
return max;
}
@@ -1151,7 +1287,12 @@ void ReportMetrics(
{
double min = inData[0];
for (size_t i = 1; i < inData.size(); ++i) {
- min = std::min(min, inData[i]);
+ if (invert) {
+ min = std::max(min, inData[i]);
+ }
+ else {
+ min = std::min(min, inData[i]);
+ }
}
return min;
}
@@ -1189,8 +1330,11 @@ void ReportMetrics(
}
// Calculate percentile using linear interpolation between the closet ranks
- double ConcreteMiddleware::CalculatePercentile(std::vector& inData, double percentile) const
+ double ConcreteMiddleware::CalculatePercentile(std::vector& inData, double percentile, bool invert) const
{
+ if (invert) {
+ percentile = 1.0 - percentile;
+ }
percentile = std::min(std::max(percentile, 0.), 1.);
double integral_part_as_double;
@@ -1589,6 +1733,7 @@ void ReportMetrics(
case PM_METRIC_DISPLAYED_TIME:
case PM_METRIC_ANIMATION_ERROR:
case PM_METRIC_APPLICATION:
+ case PM_METRIC_INSTRUMENTED_LATENCY:
CalculateFpsMetric(swapChain, qe, pBlob, qpcFrequency);
break;
case PM_METRIC_CPU_VENDOR:
diff --git a/IntelPresentMon/PresentMonMiddleware/ConcreteMiddleware.h b/IntelPresentMon/PresentMonMiddleware/ConcreteMiddleware.h
index 66177e98..809a8b1a 100644
--- a/IntelPresentMon/PresentMonMiddleware/ConcreteMiddleware.h
+++ b/IntelPresentMon/PresentMonMiddleware/ConcreteMiddleware.h
@@ -53,6 +53,12 @@ namespace pmon::mid
std::vector mClickToPhotonLatency;
std::vector mAllInputToPhotonLatency;
std::vector mDropped;
+ std::vector mInstrumentedDisplayLatency;
+
+ std::vector mInstrumentedSleep;
+ std::vector mInstrumentedRenderLatency;
+ std::vector mInstrumentedGpuLatency;
+ std::vector mInstrumentedReadyTimeToDisplayLatency;
// QPC of last received input data that did not make it to the screen due
// to the Present() being dropped
@@ -60,9 +66,9 @@ namespace pmon::mid
uint64_t mLastReceivedNotDisplayedMouseClickTime;
// begin/end screen times to optimize average calculation:
- uint64_t display_n_screen_time = 0; // The last presented frame's ScreenTime (qpc)
+ uint64_t mLastDisplayedScreenTime = 0; // The last presented frame's ScreenTime (qpc)
uint64_t display_0_screen_time = 0; // The first presented frame's ScreenTime (qpc)
- uint64_t mLastDisplayedCPUStart = 0; // The CPU start of the last presented frame
+ uint64_t mLastDisplayedSimStart = 0; // The simulation start of the last presented frame
uint32_t display_count = 0; // The number of presented frames
};
@@ -112,8 +118,8 @@ namespace pmon::mid
void CalculateFpsMetric(fpsSwapChainData& swapChain, const PM_QUERY_ELEMENT& element, uint8_t* pBlob, LARGE_INTEGER qpcFrequency);
void CalculateGpuCpuMetric(std::unordered_map& metricInfo, const PM_QUERY_ELEMENT& element, uint8_t* pBlob);
- double CalculateStatistic(std::vector& inData, PM_STAT stat) const;
- double CalculatePercentile(std::vector& inData, double percentile) const;
+ double CalculateStatistic(std::vector& inData, PM_STAT stat, bool invert = false) const;
+ double CalculatePercentile(std::vector& inData, double percentile, bool invert) const;
bool GetGpuMetricData(size_t telemetry_item_bit, PresentMonPowerTelemetryInfo& power_telemetry_info, std::unordered_map& metricInfo);
bool GetCpuMetricData(size_t telemetryBit, CpuTelemetryInfo& cpuTelemetry, std::unordered_map& metricInfo);
void GetStaticCpuMetrics();
@@ -132,6 +138,8 @@ namespace pmon::mid
uint32_t clientProcessId = 0;
// Stream clients mapping to process id
std::map> presentMonStreamClients;
+ // App sim start time for each process id
+ std::map appSimStartTime;
std::unique_ptr pComms;
// Dynamic query handle to frame data delta
std::unordered_map, uint64_t> queryFrameDataDeltas;
diff --git a/IntelPresentMon/PresentMonMiddleware/FrameEventQuery.cpp b/IntelPresentMon/PresentMonMiddleware/FrameEventQuery.cpp
index 0238ec93..6a8b9621 100644
--- a/IntelPresentMon/PresentMonMiddleware/FrameEventQuery.cpp
+++ b/IntelPresentMon/PresentMonMiddleware/FrameEventQuery.cpp
@@ -114,6 +114,42 @@ namespace
uint16_t outputPaddingSize_;
uint16_t inputIndex_;
};
+ class CopyGatherFrameTypeCommand_ : public mid::GatherCommand_
+ {
+ public:
+ CopyGatherFrameTypeCommand_(size_t nextAvailableByteOffset, uint16_t index = 0)
+ :
+ inputIndex_{ index }
+ {
+ outputPaddingSize_ = (uint16_t)util::GetPadding(nextAvailableByteOffset, alignof(FrameType));
+ outputOffset_ = uint32_t(nextAvailableByteOffset) + outputPaddingSize_;
+ }
+ void Gather(Context& ctx, uint8_t* pDestBlob) const override
+ {
+ auto val = ctx.pSourceFrameData->present_event.Displayed_FrameType[ctx.sourceFrameDisplayIndex];
+ // Currently not reporting out not set or repeated frames.
+ if (val == FrameType::NotSet || val == FrameType::Repeated) {
+ val = FrameType::Application;
+ }
+ reinterpret_cast&>(pDestBlob[outputOffset_]) = val;
+ }
+ uint32_t GetBeginOffset() const override
+ {
+ return outputOffset_ - outputPaddingSize_;
+ }
+ uint32_t GetEndOffset() const override
+ {
+ return outputOffset_ + alignof(FrameType);
+ }
+ uint32_t GetOutputOffset() const override
+ {
+ return outputOffset_;
+ }
+ private:
+ uint32_t outputOffset_;
+ uint16_t outputPaddingSize_;
+ uint16_t inputIndex_;
+ };
template
class QpcDurationGatherCommand_ : public pmon::mid::GatherCommand_
{
@@ -127,8 +163,13 @@ namespace
{
const auto qpcDuration = ctx.pSourceFrameData->present_event.*pMember;
if (qpcDuration != 0) {
- const auto val = ctx.performanceCounterPeriodMs * double(qpcDuration);
- reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ const auto val = ctx.performanceCounterPeriodMs * double(qpcDuration);
+ reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ }
+ else {
+ reinterpret_cast(pDestBlob[outputOffset_]) = 0.;
+ }
}
else {
reinterpret_cast(pDestBlob[outputOffset_]) = 0.;
@@ -150,42 +191,119 @@ namespace
uint32_t outputOffset_;
uint16_t outputPaddingSize_;
};
- template
- class QpcDifferenceGatherCommand_ : public pmon::mid::GatherCommand_
+ template
+ class QpcDeltaGatherCommand_ : public pmon::mid::GatherCommand_
{
public:
- QpcDifferenceGatherCommand_(size_t nextAvailableByteOffset)
+ QpcDeltaGatherCommand_(size_t nextAvailableByteOffset)
{
outputPaddingSize_ = (uint16_t)util::GetPadding(nextAvailableByteOffset, alignof(double));
outputOffset_ = uint32_t(nextAvailableByteOffset) + outputPaddingSize_;
}
void Gather(Context& ctx, uint8_t* pDestBlob) const override
{
- if constexpr (doDroppedCheck) {
- if (ctx.dropped) {
- reinterpret_cast(pDestBlob[outputOffset_]) =
- std::numeric_limits::quiet_NaN();
- return;
+ const auto qpcFrom = ctx.pSourceFrameData->present_event.*pFromMember;
+ const auto qpcTo = ctx.pSourceFrameData->present_event.*pToMember;
+ if (qpcFrom != 0) {
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ const auto val = TimestampDeltaToUnsignedMilliSeconds(qpcFrom, qpcTo, ctx.performanceCounterPeriodMs);
+ reinterpret_cast(pDestBlob[outputOffset_]) = val;
}
- }
- uint64_t start = ctx.pSourceFrameData->present_event.*pStart;
- if constexpr (doZeroCheck) {
- if (start == 0ull) {
+ else {
reinterpret_cast(pDestBlob[outputOffset_]) =
std::numeric_limits::quiet_NaN();
- return;
}
}
- if constexpr (allowNegative) {
- auto qpcDurationDouble = double(ctx.pSourceFrameData->present_event.*pEnd) - double(start);
- const auto val = ctx.performanceCounterPeriodMs * qpcDurationDouble;
- reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ else {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ }
+ }
+ uint32_t GetBeginOffset() const override
+ {
+ return outputOffset_ - outputPaddingSize_;
+ }
+ uint32_t GetEndOffset() const override
+ {
+ return outputOffset_ + alignof(double);
+ }
+ uint32_t GetOutputOffset() const override
+ {
+ return outputOffset_;
+ }
+ private:
+ uint32_t outputOffset_;
+ uint16_t outputPaddingSize_;
+ };
+ class GpuTimeGatherCommand_ : public pmon::mid::GatherCommand_
+ {
+ public:
+ GpuTimeGatherCommand_(size_t nextAvailableByteOffset)
+ {
+ outputPaddingSize_ = (uint16_t)util::GetPadding(nextAvailableByteOffset, alignof(double));
+ outputOffset_ = uint32_t(nextAvailableByteOffset) + outputPaddingSize_;
+ }
+ void Gather(Context& ctx, uint8_t* pDestBlob) const override
+ {
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ const auto gpuDuration = TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.GPUStartTime,
+ ctx.pSourceFrameData->present_event.ReadyTime, ctx.performanceCounterPeriodMs);
+ const auto gpuBusy = TimestampDeltaToMilliSeconds(ctx.pSourceFrameData->present_event.GPUDuration,
+ ctx.performanceCounterPeriodMs);
+ const auto gpuWait = std::max(0., gpuDuration - gpuBusy);
+ reinterpret_cast(pDestBlob[outputOffset_]) = gpuBusy + gpuWait;
}
else {
+ reinterpret_cast(pDestBlob[outputOffset_]) = 0.;
+ }
+ }
+ uint32_t GetBeginOffset() const override
+ {
+ return outputOffset_ - outputPaddingSize_;
+ }
+ uint32_t GetEndOffset() const override
+ {
+ return outputOffset_ + alignof(double);
+ }
+ uint32_t GetOutputOffset() const override
+ {
+ return outputOffset_;
+ }
+ private:
+ uint32_t outputOffset_;
+ uint16_t outputPaddingSize_;
+ };
+ class ClickToPhotonGatherCommand_ : public pmon::mid::GatherCommand_
+ {
+ public:
+ ClickToPhotonGatherCommand_(size_t nextAvailableByteOffset)
+ {
+ outputPaddingSize_ = (uint16_t)util::GetPadding(nextAvailableByteOffset, alignof(double));
+ outputOffset_ = uint32_t(nextAvailableByteOffset) + outputPaddingSize_;
+ }
+ void Gather(Context& ctx, uint8_t* pDestBlob) const override
+ {
+ if (ctx.dropped) {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ return;
+ }
+ uint64_t start = ctx.pSourceFrameData->present_event.InputTime;
+ if (start == 0ull) {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ return;
+ }
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
const auto val = TimestampDeltaToUnsignedMilliSeconds(start,
- ctx.pSourceFrameData->present_event.*pEnd, ctx.performanceCounterPeriodMs);
+ ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex], ctx.performanceCounterPeriodMs);
reinterpret_cast(pDestBlob[outputOffset_]) = val;
}
+ else
+ {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ }
}
uint32_t GetBeginOffset() const override
{
@@ -226,7 +344,7 @@ namespace
private:
uint32_t outputOffset_;
};
- template
+ template
class StartDifferenceGatherCommand_ : public pmon::mid::GatherCommand_
{
public:
@@ -237,9 +355,29 @@ namespace
}
void Gather(Context& ctx, uint8_t* pDestBlob) const override
{
- const auto qpcDuration = ctx.pSourceFrameData->present_event.*pEnd - ctx.qpcStart;
- const auto val = ctx.performanceCounterPeriodMs * double(qpcDuration);
- reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ if constexpr (calcAnimationTime) {
+ if constexpr (doDroppedCheck) {
+ if (ctx.dropped) {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ return;
+ }
+ }
+ if (ctx.sourceFrameDisplayIndex != ctx.appIndex) {
+ reinterpret_cast(pDestBlob[outputOffset_]) = 0.;
+ return;
+ }
+ const auto firstSimStartTime = ctx.firstAppSimStartTime != 0 ? ctx.firstAppSimStartTime :
+ ctx.qpcStart;
+ const auto currentSimTime = ctx.pSourceFrameData->present_event.*pEnd != 0 ? ctx.pSourceFrameData->present_event.*pEnd :
+ ctx.cpuStart;
+ const auto val = TimestampDeltaToUnsignedMilliSeconds(firstSimStartTime, currentSimTime, ctx.performanceCounterPeriodMs);
+ reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ } else {
+ const auto qpcDuration = ctx.cpuStart - ctx.qpcStart;
+ const auto val = ctx.performanceCounterPeriodMs * double(qpcDuration);
+ reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ }
}
uint32_t GetBeginOffset() const override
{
@@ -298,9 +436,14 @@ namespace
return;
}
}
- const auto val = TimestampDeltaToUnsignedMilliSeconds(ctx.cpuStart,
- ctx.pSourceFrameData->present_event.*pEnd, ctx.performanceCounterPeriodMs);
- reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ const auto val = TimestampDeltaToUnsignedMilliSeconds(ctx.cpuStart,
+ ctx.pSourceFrameData->present_event.*pEnd, ctx.performanceCounterPeriodMs);
+ reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ }
+ else{
+ reinterpret_cast(pDestBlob[outputOffset_]) = 0.;
+ }
}
uint32_t GetBeginOffset() const override
{
@@ -318,38 +461,123 @@ namespace
uint32_t outputOffset_;
uint16_t outputPaddingSize_;
};
- template
- class DisplayDifferenceGatherCommand_ : public pmon::mid::GatherCommand_
+ template
+ class DisplayLatencyGatherCommand_ : public pmon::mid::GatherCommand_
{
public:
- DisplayDifferenceGatherCommand_(size_t nextAvailableByteOffset)
+ DisplayLatencyGatherCommand_(size_t nextAvailableByteOffset)
{
outputPaddingSize_ = (uint16_t)util::GetPadding(nextAvailableByteOffset, alignof(double));
outputOffset_ = uint32_t(nextAvailableByteOffset) + outputPaddingSize_;
}
void Gather(Context& ctx, uint8_t* pDestBlob) const override
{
- if constexpr (doDroppedCheck) {
- if (ctx.dropped) {
+ if (ctx.dropped) {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ return;
+ }
+
+ uint64_t startQpc = 0;
+ if constexpr (isXellRenderLatency) {
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ if (ctx.pSourceFrameData->present_event.AppRenderSubmitStartTime == 0) {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ return;
+ }
+ const auto val = TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.AppRenderSubmitStartTime,
+ ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex],
+ ctx.performanceCounterPeriodMs);
+ reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ return;
+ } else {
reinterpret_cast(pDestBlob[outputOffset_]) =
std::numeric_limits::quiet_NaN();
return;
}
- }
- if constexpr (doZeroCheck) {
- const auto val = TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.*pStart,
- ctx.nextDisplayedQpc, ctx.performanceCounterPeriodMs);
- if (val == 0.) {
+ } else if constexpr (isXellRenderEndToDisplayLatency) {
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ const auto val = TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.ReadyTime,
+ ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex],
+ ctx.performanceCounterPeriodMs);
+ reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ return;
+ } else {
reinterpret_cast(pDestBlob[outputOffset_]) =
std::numeric_limits::quiet_NaN();
+ return;
}
- else {
+ } else if constexpr (isXellDisplayLatency) {
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ if (ctx.pSourceFrameData->present_event.AppSleepEndTime == 0 &&
+ ctx.pSourceFrameData->present_event.AppSimStartTime == 0) {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ return;
+ }
+ const auto xellStartTime = ctx.pSourceFrameData->present_event.AppSleepEndTime != 0 ?
+ ctx.pSourceFrameData->present_event.AppSleepEndTime :
+ ctx.pSourceFrameData->present_event.AppSimStartTime;
+ const auto val = TimestampDeltaToUnsignedMilliSeconds(xellStartTime,
+ ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex],
+ ctx.performanceCounterPeriodMs);
reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ return;
+ } else {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ return;
}
+ } else {
+ const auto val = TimestampDeltaToUnsignedMilliSeconds(ctx.cpuStart,
+ ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex],
+ ctx.performanceCounterPeriodMs);
+ reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ return;
+ }
+ }
+ uint32_t GetBeginOffset() const override
+ {
+ return outputOffset_ - outputPaddingSize_;
+ }
+ uint32_t GetEndOffset() const override
+ {
+ return outputOffset_ + alignof(double);
+ }
+ uint32_t GetOutputOffset() const override
+ {
+ return outputOffset_;
+ }
+ private:
+ uint32_t outputOffset_;
+ uint16_t outputPaddingSize_;
+ };
+ class DisplayDifferenceGatherCommand_ : public pmon::mid::GatherCommand_
+ {
+ public:
+ DisplayDifferenceGatherCommand_(size_t nextAvailableByteOffset)
+ {
+ outputPaddingSize_ = (uint16_t)util::GetPadding(nextAvailableByteOffset, alignof(double));
+ outputOffset_ = uint32_t(nextAvailableByteOffset) + outputPaddingSize_;
+ }
+ void Gather(Context& ctx, uint8_t* pDestBlob) const override
+ {
+ if (ctx.dropped) {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ return;
+ }
+ auto ScreenTime = ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex];
+ auto NextScreenTime = ctx.sourceFrameDisplayIndex == ctx.pSourceFrameData->present_event.DisplayedCount - 1
+ ? ctx.nextDisplayedQpc
+ : ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex + 1];
+ const auto val = TimestampDeltaToUnsignedMilliSeconds(ScreenTime, NextScreenTime, ctx.performanceCounterPeriodMs);
+ if (val == 0.) {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
}
else {
- const auto val = TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.*pStart,
- ctx.nextDisplayedQpc, ctx.performanceCounterPeriodMs);
reinterpret_cast(pDestBlob[outputOffset_]) = val;
}
}
@@ -369,7 +597,7 @@ namespace
uint32_t outputOffset_;
uint16_t outputPaddingSize_;
};
- template
+ template
class AnimationErrorGatherCommand_ : public pmon::mid::GatherCommand_
{
public:
@@ -388,14 +616,35 @@ namespace
}
}
if constexpr (doZeroCheck) {
- if (ctx.previousDisplayedCpuStartQpc == 0) {
+ if (ctx.previousDisplayedSimStartQpc == 0 && ctx.lastDisplayedCpuStart == 0) {
reinterpret_cast(pDestBlob[outputOffset_]) = 0.0;
return;
}
}
- const auto val = TimestampDeltaToMilliSeconds(ctx.pSourceFrameData->present_event.*pStart - ctx.previousDisplayedQpc,
- ctx.cpuStart - ctx.previousDisplayedCpuStartQpc, ctx.performanceCounterPeriodMs);
- reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ auto ScreenTime = ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex];
+ auto PrevScreenTime = ctx.previousDisplayedQpc; // Always use application display time for animation error
+ auto SimStartTime = ctx.pSourceFrameData->present_event.AppSimStartTime != 0 ?
+ ctx.pSourceFrameData->present_event.AppSimStartTime :
+ ctx.cpuStart;
+ auto PrevSimStartTime = ctx.previousDisplayedSimStartQpc != 0 ?
+ ctx.previousDisplayedSimStartQpc :
+ ctx.lastDisplayedCpuStart;
+ // If the simulation start time is less than the last displated simulation start time it means
+ // we are transitioning to app provider events.
+ if (SimStartTime > PrevSimStartTime) {
+ const auto val = TimestampDeltaToMilliSeconds(ScreenTime - PrevScreenTime,
+ SimStartTime - PrevSimStartTime, ctx.performanceCounterPeriodMs);
+ reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ } else {
+ reinterpret_cast(pDestBlob[outputOffset_]) = 0.0;
+ return;
+ }
+ }
+ else {
+ reinterpret_cast(pDestBlob[outputOffset_]) =
+ std::numeric_limits::quiet_NaN();
+ }
}
uint32_t GetBeginOffset() const override
{
@@ -419,12 +668,17 @@ namespace
CpuFrameQpcFrameTimeCommand_(size_t nextAvailableByteOffset) : outputOffset_{ (uint32_t)nextAvailableByteOffset } {}
void Gather(Context& ctx, uint8_t* pDestBlob) const override
{
- const auto cpuBusy = TimestampDeltaToUnsignedMilliSeconds(ctx.cpuStart, ctx.pSourceFrameData->present_event.PresentStartTime,
- ctx.performanceCounterPeriodMs);
- const auto cpuWait = TimestampDeltaToMilliSeconds(ctx.pSourceFrameData->present_event.TimeInPresent,
- ctx.performanceCounterPeriodMs);
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ const auto cpuBusy = TimestampDeltaToUnsignedMilliSeconds(ctx.cpuStart, ctx.pSourceFrameData->present_event.PresentStartTime,
+ ctx.performanceCounterPeriodMs);
+ const auto cpuWait = TimestampDeltaToMilliSeconds(ctx.pSourceFrameData->present_event.TimeInPresent,
+ ctx.performanceCounterPeriodMs);
- reinterpret_cast(pDestBlob[outputOffset_]) = cpuBusy + cpuWait;
+ reinterpret_cast(pDestBlob[outputOffset_]) = cpuBusy + cpuWait;
+ }
+ else {
+ reinterpret_cast(pDestBlob[outputOffset_]) = 0.;
+ }
}
uint32_t GetBeginOffset() const override
{
@@ -447,12 +701,17 @@ namespace
GpuWaitGatherCommand_(size_t nextAvailableByteOffset) : outputOffset_{ (uint32_t)nextAvailableByteOffset } {}
void Gather(Context& ctx, uint8_t* pDestBlob) const override
{
- const auto gpuDuration = TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.GPUStartTime,
- ctx.pSourceFrameData->present_event.ReadyTime, ctx.performanceCounterPeriodMs);
- const auto gpuBusy = TimestampDeltaToMilliSeconds(ctx.pSourceFrameData->present_event.GPUDuration,
- ctx.performanceCounterPeriodMs);
- const auto val = std::max(0., gpuDuration - gpuBusy);
- reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ const auto gpuDuration = TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.GPUStartTime,
+ ctx.pSourceFrameData->present_event.ReadyTime, ctx.performanceCounterPeriodMs);
+ const auto gpuBusy = TimestampDeltaToMilliSeconds(ctx.pSourceFrameData->present_event.GPUDuration,
+ ctx.performanceCounterPeriodMs);
+ const auto val = std::max(0., gpuDuration - gpuBusy);
+ reinterpret_cast(pDestBlob[outputOffset_]) = val;
+ }
+ else {
+ reinterpret_cast(pDestBlob[outputOffset_]) = 0.;
+ }
}
uint32_t GetBeginOffset() const override
{
@@ -469,7 +728,7 @@ namespace
private:
uint32_t outputOffset_;
};
- template
+ template
class InputLatencyGatherCommand_ : public pmon::mid::GatherCommand_
{
public:
@@ -490,25 +749,29 @@ namespace
double updatedInputTime = 0.;
double val = 0.;
- if (isMouseClick) {
- updatedInputTime = ctx.lastReceivedNotDisplayedClickQpc == 0 ? 0. :
- TimestampDeltaToUnsignedMilliSeconds(ctx.lastReceivedNotDisplayedClickQpc,
- ctx.pSourceFrameData->present_event.*pEnd, ctx.performanceCounterPeriodMs);
- val = ctx.pSourceFrameData->present_event.*pStart == 0 ? updatedInputTime :
- TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.*pStart,
- ctx.pSourceFrameData->present_event.*pEnd,
- ctx.performanceCounterPeriodMs);
- ctx.lastReceivedNotDisplayedClickQpc = 0;
- }
- else {
- updatedInputTime = ctx.lastReceivedNotDisplayedAllInputTime == 0 ? 0. :
- TimestampDeltaToUnsignedMilliSeconds(ctx.lastReceivedNotDisplayedAllInputTime,
- ctx.pSourceFrameData->present_event.*pEnd, ctx.performanceCounterPeriodMs);
- val = ctx.pSourceFrameData->present_event.*pStart == 0 ? updatedInputTime :
- TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.*pStart,
- ctx.pSourceFrameData->present_event.*pEnd,
- ctx.performanceCounterPeriodMs);
- ctx.lastReceivedNotDisplayedAllInputTime = 0;
+ if (ctx.sourceFrameDisplayIndex == ctx.appIndex) {
+ if (isMouseClick) {
+ updatedInputTime = ctx.lastReceivedNotDisplayedClickQpc == 0 ? 0. :
+ TimestampDeltaToUnsignedMilliSeconds(ctx.lastReceivedNotDisplayedClickQpc,
+ ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex],
+ ctx.performanceCounterPeriodMs);
+ val = ctx.pSourceFrameData->present_event.*pStart == 0 ? updatedInputTime :
+ TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.*pStart,
+ ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex],
+ ctx.performanceCounterPeriodMs);
+ ctx.lastReceivedNotDisplayedClickQpc = 0;
+ }
+ else {
+ updatedInputTime = ctx.lastReceivedNotDisplayedAllInputTime == 0 ? 0. :
+ TimestampDeltaToUnsignedMilliSeconds(ctx.lastReceivedNotDisplayedAllInputTime,
+ ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex],
+ ctx.performanceCounterPeriodMs);
+ val = ctx.pSourceFrameData->present_event.*pStart == 0 ? updatedInputTime :
+ TimestampDeltaToUnsignedMilliSeconds(ctx.pSourceFrameData->present_event.*pStart,
+ ctx.pSourceFrameData->present_event.Displayed_ScreenTime[ctx.sourceFrameDisplayIndex],
+ ctx.performanceCounterPeriodMs);
+ ctx.lastReceivedNotDisplayedAllInputTime = 0;
+ }
}
if (val == 0.) {
@@ -623,7 +886,7 @@ std::unique_ptr PM_FRAME_QUERY::MapQueryElementToGatherComm
case PM_METRIC_ALLOWS_TEARING:
return std::make_unique>(pos);
case PM_METRIC_FRAME_TYPE:
- return std::make_unique>(pos);
+ return std::make_unique(pos);
case PM_METRIC_SYNC_INTERVAL:
return std::make_unique>(pos);
@@ -692,7 +955,7 @@ std::unique_ptr PM_FRAME_QUERY::MapQueryElementToGatherComm
case PM_METRIC_PRESENT_FLAGS:
return std::make_unique>(pos);
case PM_METRIC_CPU_START_TIME:
- return std::make_unique>(pos);
+ return std::make_unique>(pos);
case PM_METRIC_CPU_FRAME_TIME:
return std::make_unique(pos);
case PM_METRIC_CPU_BUSY:
@@ -700,22 +963,25 @@ std::unique_ptr PM_FRAME_QUERY::MapQueryElementToGatherComm
case PM_METRIC_CPU_WAIT:
return std::make_unique>(pos);
case PM_METRIC_GPU_TIME:
- return std::make_unique>(pos);
+ return std::make_unique(pos);
case PM_METRIC_GPU_WAIT:
return std::make_unique(pos);
case PM_METRIC_DISPLAYED_TIME:
- return std::make_unique>(pos);
+ return std::make_unique(pos);
case PM_METRIC_ANIMATION_ERROR:
- return std::make_unique>(pos);
+ return std::make_unique>(pos);
+ case PM_METRIC_ANIMATION_TIME:
+ return std::make_unique>(pos);
case PM_METRIC_GPU_LATENCY:
return std::make_unique>(pos);
case PM_METRIC_DISPLAY_LATENCY:
- return std::make_unique>(pos);
+ return std::make_unique>(pos);
case PM_METRIC_CLICK_TO_PHOTON_LATENCY:
- return std::make_unique>(pos);
+ return std::make_unique>(pos);
case PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY:
- return std::make_unique>(pos);
-
+ return std::make_unique>(pos);
+ case PM_METRIC_INSTRUMENTED_LATENCY:
+ return std::make_unique>(pos);
default:
pmlog_error("unknown metric id").pmwatch((int)q.metric).diag();
return {};
@@ -729,7 +995,8 @@ void PM_FRAME_QUERY::Context::UpdateSourceData(const PmNsmFrameData* pSourceFram
const PmNsmFrameData* pPreviousFrameDataOfLastDisplayed)
{
pSourceFrameData = pSourceFrameData_in;
- dropped = pSourceFrameData->present_event.FinalState != PresentResult::Presented;
+ sourceFrameDisplayIndex = 0;
+ dropped = pSourceFrameData->present_event.FinalState != PresentResult::Presented && pSourceFrameData->present_event.DisplayedCount == 0;
if (dropped) {
if (pSourceFrameData->present_event.MouseClickTime != 0) {
lastReceivedNotDisplayedClickQpc = pSourceFrameData->present_event.MouseClickTime;
@@ -739,34 +1006,56 @@ void PM_FRAME_QUERY::Context::UpdateSourceData(const PmNsmFrameData* pSourceFram
}
}
+ if (firstAppSimStartTime == 0) {
+ firstAppSimStartTime = pSourceFrameData->present_event.AppSimStartTime;
+ }
+
if (pFrameDataOfLastPresented) {
- cpuStart = pFrameDataOfLastPresented->present_event.PresentStartTime + pFrameDataOfLastPresented->present_event.TimeInPresent;
+ cpuStart = pFrameDataOfLastPresented->present_event.PresentStartTime +
+ pFrameDataOfLastPresented->present_event.TimeInPresent;
}
else {
// TODO: log issue or invalidate related columns or drop frame (or some combination)
pmlog_info("null pFrameDataOfLastPresented");
cpuStart = 0;
}
+
if (pFrameDataOfNextDisplayed) {
- nextDisplayedQpc = pFrameDataOfNextDisplayed->present_event.ScreenTime;
+ nextDisplayedQpc = pFrameDataOfNextDisplayed->present_event.Displayed_ScreenTime[0];
}
else {
// TODO: log issue or invalidate related columns or drop frame (or some combination)
pmlog_info("null pFrameDataOfNextDisplayed");
nextDisplayedQpc = 0;
}
- if (pFrameDataOfLastDisplayed) {
- previousDisplayedQpc = pFrameDataOfLastDisplayed->present_event.ScreenTime;
+
+ if (pFrameDataOfLastDisplayed && pFrameDataOfLastDisplayed->present_event.DisplayedCount > 0) {
+ previousDisplayedQpc = pFrameDataOfLastDisplayed->present_event.Displayed_ScreenTime[pFrameDataOfLastDisplayed->present_event.DisplayedCount - 1];
+ previousDisplayedSimStartQpc = pFrameDataOfLastDisplayed->present_event.AppSimStartTime;
}
else {
// TODO: log issue or invalidate related columns or drop frame (or some combination)
pmlog_info("null pFrameDataOfLastDisplayed");
previousDisplayedQpc = 0;
+ previousDisplayedSimStartQpc = 0;
}
+
if (pPreviousFrameDataOfLastDisplayed) {
- previousDisplayedCpuStartQpc = pPreviousFrameDataOfLastDisplayed->present_event.PresentStartTime + pPreviousFrameDataOfLastDisplayed->present_event.TimeInPresent;
+ // Similar to above calculation for cpu start however this time using data from
+ // the last displayed present
+ lastDisplayedCpuStart = pPreviousFrameDataOfLastDisplayed->present_event.PresentStartTime +
+ pPreviousFrameDataOfLastDisplayed->present_event.TimeInPresent;
}
else {
- previousDisplayedCpuStartQpc = 0;
+ pmlog_info("null pPreviousFrameDataOfLastDisplayed");
+ lastDisplayedCpuStart = 0;
+ }
+ appIndex = 0;
+ for (size_t i = 0; i < pSourceFrameData->present_event.DisplayedCount; ++i) {
+ if (pSourceFrameData->present_event.Displayed_FrameType[i] == FrameType::NotSet ||
+ pSourceFrameData->present_event.Displayed_FrameType[i] == FrameType::Application) {
+ appIndex = i;
+ break;
+ }
}
}
diff --git a/IntelPresentMon/PresentMonMiddleware/FrameEventQuery.h b/IntelPresentMon/PresentMonMiddleware/FrameEventQuery.h
index 01d49317..c786bf3c 100644
--- a/IntelPresentMon/PresentMonMiddleware/FrameEventQuery.h
+++ b/IntelPresentMon/PresentMonMiddleware/FrameEventQuery.h
@@ -22,8 +22,9 @@ struct PM_FRAME_QUERY
struct Context
{
// functions
- Context(uint64_t qpcStart, long long perfCounterFrequency) : qpcStart{ qpcStart },
- performanceCounterPeriodMs{ perfCounterFrequency != 0.f ? 1000.0 / perfCounterFrequency : 0.f } {}
+ Context(uint64_t qpcStart, long long perfCounterFrequency, uint64_t appSimStartTime) : qpcStart{ qpcStart },
+ performanceCounterPeriodMs{ perfCounterFrequency != 0.f ? 1000.0 / perfCounterFrequency : 0.f },
+ firstAppSimStartTime { appSimStartTime} {}
void UpdateSourceData(const PmNsmFrameData* pSourceFrameData_in,
const PmNsmFrameData* pFrameDataOfNextDisplayed,
const PmNsmFrameData* pFrameDataofLastPresented,
@@ -31,21 +32,29 @@ struct PM_FRAME_QUERY
const PmNsmFrameData* pPreviousFrameDataOfLastDisplayed);
// data
const PmNsmFrameData* pSourceFrameData = nullptr;
+ uint32_t sourceFrameDisplayIndex = 0;
const double performanceCounterPeriodMs{};
const uint64_t qpcStart{};
bool dropped{};
// Start qpc of the previous frame, displayed or not
uint64_t cpuStart = 0;
- // Start qpc of the previously DISPLAYED frame.
- uint64_t previousDisplayedCpuStartQpc = 0;
+ // The simulation start of the last displayed frame
+ uint64_t previousDisplayedSimStartQpc = 0;
+ // Start cpustart qpc of the previously displayed frame
+ uint64_t lastDisplayedCpuStart = 0;
// Screen time qpc of the previously displayed frame.
uint64_t previousDisplayedQpc = 0;
- // Screen time qpc of the next displayed frame
+ // Screen time qpc of the first display in the next displayed PmNsmFrameData
uint64_t nextDisplayedQpc = 0;
+ // Display index to attribute cpu work, gpu work, animation error and
+ // input latency
+ size_t appIndex = 0;
// Click time qpc of non displayed frame
uint64_t lastReceivedNotDisplayedClickQpc = 0;
// All other input time qpc of non displayed frame
uint64_t lastReceivedNotDisplayedAllInputTime = 0;
+ // The first app sim start time
+ uint64_t firstAppSimStartTime = 0;
};
// functions
PM_FRAME_QUERY(std::span queryElements);
diff --git a/IntelPresentMon/PresentMonMiddleware/MockMiddleware.cpp b/IntelPresentMon/PresentMonMiddleware/MockMiddleware.cpp
index d1df52d5..06d3e531 100644
--- a/IntelPresentMon/PresentMonMiddleware/MockMiddleware.cpp
+++ b/IntelPresentMon/PresentMonMiddleware/MockMiddleware.cpp
@@ -199,7 +199,7 @@ namespace pmon::mid
}
const auto numFramesToProcess = std::min(numFrames, (uint32_t)frames.size());
const auto blobSize = pQuery->GetBlobSize();
- PM_FRAME_QUERY::Context ctx{ 0ull, 0ll };
+ PM_FRAME_QUERY::Context ctx{ 0ull, 0ll , 0ull};
for (uint32_t i = 0; i < numFramesToProcess; i++) {
// TODO: feed actual prev/next frames into this function
ctx.UpdateSourceData(&frames.front(), nullptr, nullptr, nullptr, nullptr);
diff --git a/IntelPresentMon/PresentMonMiddleware/PresentMonMiddleware.vcxproj b/IntelPresentMon/PresentMonMiddleware/PresentMonMiddleware.vcxproj
index e270e497..30a25139 100644
--- a/IntelPresentMon/PresentMonMiddleware/PresentMonMiddleware.vcxproj
+++ b/IntelPresentMon/PresentMonMiddleware/PresentMonMiddleware.vcxproj
@@ -45,6 +45,9 @@
{bf43064b-01f0-4c69-91fb-c2122baf621d}
+
+ {c73aa532-e532-4d93-9279-905444653c08}
+
17.0
diff --git a/IntelPresentMon/PresentMonMiddleware/PresentMonMiddleware.vcxproj.filters b/IntelPresentMon/PresentMonMiddleware/PresentMonMiddleware.vcxproj.filters
index c3e858cb..2a8ee1ae 100644
--- a/IntelPresentMon/PresentMonMiddleware/PresentMonMiddleware.vcxproj.filters
+++ b/IntelPresentMon/PresentMonMiddleware/PresentMonMiddleware.vcxproj.filters
@@ -1,4 +1,4 @@
-
+
@@ -53,5 +53,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file
diff --git a/IntelPresentMon/PresentMonService/MockPresentMonSession.cpp b/IntelPresentMon/PresentMonService/MockPresentMonSession.cpp
index c3ddfead..d32d78f4 100644
--- a/IntelPresentMon/PresentMonService/MockPresentMonSession.cpp
+++ b/IntelPresentMon/PresentMonService/MockPresentMonSession.cpp
@@ -99,6 +99,7 @@ PM_STATUS MockPresentMonSession::StartTraceSession(uint32_t processId) {
pm_consumer_->mTrackGPUVideo = false;
pm_consumer_->mTrackInput = true;
pm_consumer_->mTrackFrameType = true;
+ pm_consumer_->mTrackAppTiming = true;
if (opt.etwSessionName.AsOptional().has_value()) {
pm_session_name_ =
@@ -193,6 +194,7 @@ void MockPresentMonSession::AddPresents(
// If mStartTimestamp contains a value an etl file is being processed.
// Set this value in the streamer to have the correct start time.
streamer_.SetStartQpc(trace_session_.mStartTimestamp.QuadPart);
+ streamer_.SetStreamMode(StreamMode::kOfflineEtl);
for (auto n = presentEvents.size(); i < n; ++i) {
auto presentEvent = presentEvents[i];
@@ -252,6 +254,23 @@ void MockPresentMonSession::AddPresents(
chain->mLastDisplayedPresentQPC = 0;
}
+ // Remove Repeated flips if they are in Application->Repeated or Repeated->Application sequences.
+ for (size_t i = 0, n = presentEvent->Displayed.size(); i + 1 < n; ) {
+ if (presentEvent->Displayed[i].first == FrameType::Application &&
+ presentEvent->Displayed[i + 1].first == FrameType::Repeated) {
+ presentEvent->Displayed.erase(presentEvent->Displayed.begin() + i + 1);
+ n -= 1;
+ }
+ else if (presentEvent->Displayed[i].first == FrameType::Repeated &&
+ presentEvent->Displayed[i + 1].first == FrameType::Application) {
+ presentEvent->Displayed.erase(presentEvent->Displayed.begin() + i);
+ n -= 1;
+ }
+ else {
+ i += 1;
+ }
+ }
+
// Last producer and last consumer are internal fields
// Remove for public build
// Send data to streamer if we have more than single present event
@@ -264,7 +283,7 @@ void MockPresentMonSession::AddPresents(
chain->mLastPresentQPC = presentEvent->PresentStartTime;
if (presentEvent->FinalState == PresentResult::Presented) {
- chain->mLastDisplayedPresentQPC = presentEvent->ScreenTime;
+ chain->mLastDisplayedPresentQPC = presentEvent->Displayed.empty() ? 0 : presentEvent->Displayed[0].second;
}
else if (chain->mLastDisplayedPresentQPC == chain->mLastPresentQPC) {
chain->mLastDisplayedPresentQPC = 0;
diff --git a/IntelPresentMon/PresentMonService/PresentMonService.rc b/IntelPresentMon/PresentMonService/PresentMonService.rc
index 64ef11d8..b978d72e 100644
Binary files a/IntelPresentMon/PresentMonService/PresentMonService.rc and b/IntelPresentMon/PresentMonService/PresentMonService.rc differ
diff --git a/IntelPresentMon/PresentMonService/PresentMonService.vcxproj b/IntelPresentMon/PresentMonService/PresentMonService.vcxproj
index 4ace4e0d..062833b3 100644
--- a/IntelPresentMon/PresentMonService/PresentMonService.vcxproj
+++ b/IntelPresentMon/PresentMonService/PresentMonService.vcxproj
@@ -261,6 +261,9 @@
{bf43064b-01f0-4c69-91fb-c2122baf621d}
+
+ {c73aa532-e532-4d93-9279-905444653c08}
+
diff --git a/IntelPresentMon/PresentMonService/RealtimePresentMonSession.cpp b/IntelPresentMon/PresentMonService/RealtimePresentMonSession.cpp
index d7415bb2..ba2ee6e9 100644
--- a/IntelPresentMon/PresentMonService/RealtimePresentMonSession.cpp
+++ b/IntelPresentMon/PresentMonService/RealtimePresentMonSession.cpp
@@ -130,6 +130,7 @@ PM_STATUS RealtimePresentMonSession::StartTraceSession() {
pm_consumer_->mTrackGPUVideo = false;
pm_consumer_->mTrackInput = true;
pm_consumer_->mTrackFrameType = true;
+ pm_consumer_->mTrackAppTiming = true;
auto& opt = clio::Options::Get();
if (opt.etwSessionName.AsOptional().has_value()) {
@@ -231,7 +232,9 @@ void RealtimePresentMonSession::AddPresents(
if (p->FinalState == PresentResult::Presented) {
const auto per = util::GetTimestampPeriodSeconds();
const auto now = util::GetCurrentTimestamp();
- const auto lag = util::TimestampDeltaToSeconds(p->ScreenTime, now, per);
+ // TODO: Presents can now have multiple displayed frames if we are tracking
+ // frame types. For now take the first displayed frame for logging stats
+ const auto lag = util::TimestampDeltaToSeconds(p->Displayed[0].second, now, per);
pmlog_verb(svc::v::etwq)(std::format("Frame [{}] lag: {} ms", p->FrameId, lag * 1000.));
}
}
@@ -295,6 +298,23 @@ void RealtimePresentMonSession::AddPresents(
chain->mLastDisplayedPresentQPC = 0;
}
+ // Remove Repeated flips if they are in Application->Repeated or Repeated->Application sequences.
+ for (size_t i = 0, n = presentEvent->Displayed.size(); i + 1 < n; ) {
+ if (presentEvent->Displayed[i].first == FrameType::Application &&
+ presentEvent->Displayed[i + 1].first == FrameType::Repeated) {
+ presentEvent->Displayed.erase(presentEvent->Displayed.begin() + i + 1);
+ n -= 1;
+ }
+ else if (presentEvent->Displayed[i].first == FrameType::Repeated &&
+ presentEvent->Displayed[i + 1].first == FrameType::Application) {
+ presentEvent->Displayed.erase(presentEvent->Displayed.begin() + i);
+ n -= 1;
+ }
+ else {
+ i += 1;
+ }
+ }
+
if (chain->mPresentHistoryCount > 0) {
// Last producer and last consumer are internal fields
// Remove for public build
@@ -308,7 +328,7 @@ void RealtimePresentMonSession::AddPresents(
chain->mLastPresentQPC = presentEvent->PresentStartTime;
if (presentEvent->FinalState == PresentResult::Presented) {
- chain->mLastDisplayedPresentQPC = presentEvent->ScreenTime;
+ chain->mLastDisplayedPresentQPC = presentEvent->Displayed.empty() ? 0 : presentEvent->Displayed[0].second;
}
else if (chain->mLastDisplayedPresentQPC == chain->mLastPresentQPC) {
chain->mLastDisplayedPresentQPC = 0;
diff --git a/IntelPresentMon/PresentMonService/ServiceMain.cpp b/IntelPresentMon/PresentMonService/ServiceMain.cpp
index 9d7e6f17..45323ec6 100644
--- a/IntelPresentMon/PresentMonService/ServiceMain.cpp
+++ b/IntelPresentMon/PresentMonService/ServiceMain.cpp
@@ -8,8 +8,11 @@
#include "CliOptions.h"
#include "LogSetup.h"
#include "Registry.h"
+#include "../Versioning/BuildId.h"
+#include "../CommonUtilities/log/GlobalPolicy.h"
TCHAR serviceName[MaxBufferLength] = TEXT("Intel PresentMon Service");
+using namespace pmon;
// common entry point whether invoked as service or as app
int CommonEntry(DWORD argc, LPTSTR* argv, bool asApp)
@@ -24,6 +27,13 @@ int CommonEntry(DWORD argc, LPTSTR* argv, bool asApp)
// configure logging based on CLI arguments and registry settings
logsetup::ConfigureLogging(asApp);
+ // annouce versioning etc.
+ pmlog_info(std::format("Starting service, build #{} ({}) [{}], logging @{} (log build @{})",
+ bid::BuildIdShortHash(), bid::BuildIdDirtyFlag() ? "dirty" : "clean",
+ bid::BuildIdTimestamp(),
+ log::GetLevelName(log::GlobalPolicy::Get().GetLogLevel()),
+ log::GetLevelName(PMLOG_BUILD_LEVEL_)));
+
if (asApp) {
auto& svc = ConsoleDebugMockService::Get();
svc.Run();
diff --git a/IntelPresentMon/PresentMonService/acts/OpenSession.h b/IntelPresentMon/PresentMonService/acts/OpenSession.h
index eeff5704..1e7ac001 100644
--- a/IntelPresentMon/PresentMonService/acts/OpenSession.h
+++ b/IntelPresentMon/PresentMonService/acts/OpenSession.h
@@ -1,6 +1,6 @@
#pragma once
#include "../ActionHelper.h"
-#include "../../CommonUtilities/BuildId.h"
+#include "../../Versioning/BuildId.h"
#include
#define ACTNAME OpenSession
@@ -37,8 +37,8 @@ namespace pmon::svc::acts
stx.clientBuildId = in.clientBuildId;
ctx.pSvc->SignalClientSessionOpened();
pmlog_info(std::format("Open action for session #{} pid={}; [BID] cli={} svc={}",
- stx.pPipe->GetId(), in.clientPid, in.clientBuildId, BuildIdShortHash()));
- return Response{ .serviceBuildId = BuildIdShortHash() };
+ stx.pPipe->GetId(), in.clientPid, in.clientBuildId, bid::BuildIdShortHash()));
+ return Response{ .serviceBuildId = bid::BuildIdShortHash() };
}
};
diff --git a/IntelPresentMon/PresentMonUtils/StreamFormat.h b/IntelPresentMon/PresentMonUtils/StreamFormat.h
index b171296a..edd6dd40 100644
--- a/IntelPresentMon/PresentMonUtils/StreamFormat.h
+++ b/IntelPresentMon/PresentMonUtils/StreamFormat.h
@@ -63,24 +63,38 @@ struct PmNsmPresentEvent
uint32_t ProcessId; // ID of the process that presented
uint32_t ThreadId; // ID of the thread that presented
uint64_t TimeInPresent; // QPC duration between runtime present start and end
- uint64_t GPUStartTime; // QPC value when the frame's first DMA packet started
- uint64_t ReadyTime; // QPC value when the frame's last DMA packet completed
+ uint64_t GPUStartTime; // QPC value when the frame's first DMA packet started
+ uint64_t ReadyTime; // QPC value when the frame's last DMA packet completed
- uint64_t GPUDuration; // QPC duration during which a frame's DMA packet was
- // running on any node
+ uint64_t GPUDuration; // QPC duration during which a frame's DMA packet was
+ // running on any node
uint64_t
- GPUVideoDuration; // QPC duration during which a frame's DMA packet was
- // running on a video node (if mTrackGPUVideo==true)
- uint64_t ScreenTime; // QPC value when the present was displayed on screen
-
+ GPUVideoDuration; // QPC duration during which a frame's DMA packet was
+ // running on a video node (if mTrackGPUVideo==true)
uint64_t InputTime; // Earliest QPC value for all keyboard/mouse input used by this frame
uint64_t MouseClickTime; // Earliest QPC value when the mouse was clicked and used by this frame
+ uint64_t AppSleepStartTime; // QPC value of app sleep start time provided by Intel App Provider
+ uint64_t AppSleepEndTime; // QPC value of app sleep end time provided by Intel App Provider
+ uint64_t AppSimStartTime; // QPC value of app sim start time provided by Intel App Provider
+ uint64_t AppSimEndTime; // QPC value of app sim end time provided by Intel App Provider
+ uint64_t AppRenderSubmitStartTime; // QPC value of app render submit start time provided by Intel App Provider
+ uint64_t AppRenderSubmitEndTime; // QPC value of app render submit end time provided by Intel App Provider
+ uint64_t AppPresentStartTime; // QPC value of app present start time provided by Intel App Provider
+ uint64_t AppPresentEndTime; // QPC value of app present end time provided by Intel App Provider
+ uint64_t AppInputTime; // QPC value of app input time provided by Intel App Provider
+ InputDeviceType AppInputType; // Input type provided by Intel App Provider
+
// Extra present parameters obtained through DXGI or D3D9 present
uint64_t SwapChainAddress;
int32_t SyncInterval;
uint32_t PresentFlags;
+ // (FrameType, DisplayedQPC) for each time the frame was displayed
+ uint64_t Displayed_ScreenTime[16];
+ FrameType Displayed_FrameType[16];
+ uint32_t DisplayedCount;
+
// Keys used to index into PMTraceConsumer's tracking data structures:
uint64_t CompositionSurfaceLuid; // mPresentByWin32KPresentHistoryToken
uint64_t Win32KPresentCount; // mPresentByWin32KPresentHistoryToken
diff --git a/IntelPresentMon/SampleClient/SampleClient.args.json b/IntelPresentMon/SampleClient/SampleClient.args.json
index dae2615a..a79b3f27 100644
--- a/IntelPresentMon/SampleClient/SampleClient.args.json
+++ b/IntelPresentMon/SampleClient/SampleClient.args.json
@@ -46,6 +46,14 @@
"Id": "edf9d064-e8f2-4c3c-8ab3-a70ae989a245",
"Command": "--log-demo 29916"
},
+ {
+ "Id": "78f46a64-b667-4d83-91f5-48b1332ca0c0",
+ "Command": "--diag-demo 32612"
+ },
+ {
+ "Id": "edf9d064-e8f2-4c3c-8ab3-a70ae989a245",
+ "Command": "--log-demo 29916"
+ },
{
"Id": "de172ca4-f013-4f7c-99e2-5b93c03c4ec5",
"Command": "--log-demo 19"
diff --git a/IntelPresentMon/Streamer/StreamClient.cpp b/IntelPresentMon/Streamer/StreamClient.cpp
index 25885c7e..806657d3 100644
--- a/IntelPresentMon/Streamer/StreamClient.cpp
+++ b/IntelPresentMon/Streamer/StreamClient.cpp
@@ -155,29 +155,33 @@ PM_STATUS StreamClient::RecordFrame(PM_FRAME_DATA** out_frame_data) {
}
}
-const PmNsmFrameData* StreamClient::PeekNextDisplayedFrame()
+void StreamClient::PeekNextFrames(const PmNsmFrameData** pNextFrame,
+ const PmNsmFrameData** pNextDisplayedFrame)
{
- uint64_t peekIndex = next_dequeue_idx_;
+ *pNextFrame = nullptr;
+ *pNextDisplayedFrame = nullptr;
if (recording_frame_data_) {
auto nsm_view = GetNamedSharedMemView();
auto nsm_hdr = nsm_view->GetHeader();
if (!nsm_hdr->process_active) {
// Service destroyed the named shared memory.
- return nullptr;
+ return;
}
- const PmNsmFrameData* pNsmData = nullptr;
- pNsmData = ReadFrameByIdx(peekIndex);
- while (pNsmData) {
- if (pNsmData->present_event.ScreenTime != 0) {
- return pNsmData;
+ uint64_t peekIndex{ next_dequeue_idx_ };
+ auto pTempFrameData = ReadFrameByIdx(peekIndex);
+ *pNextFrame = pTempFrameData;
+ while (pTempFrameData) {
+ if (pTempFrameData->present_event.DisplayedCount != 0) {
+ *pNextDisplayedFrame = pTempFrameData;
+ return;
}
// advance to next frame with circular buffer wrapping behavior
peekIndex = (peekIndex + 1) % nsm_view->GetHeader()->max_entries;
- pNsmData = ReadFrameByIdx(peekIndex);
+ pTempFrameData = ReadFrameByIdx(peekIndex);
}
}
- return nullptr;
+ return;
}
void StreamClient::PeekPreviousFrames(const PmNsmFrameData** pFrameDataOfLastPresented,
@@ -254,6 +258,7 @@ void StreamClient::PeekPreviousFrames(const PmNsmFrameData** pFrameDataOfLastPre
}
PM_STATUS StreamClient::ConsumePtrToNextNsmFrameData(const PmNsmFrameData** pNsmData,
+ const PmNsmFrameData** pNextFrame,
const PmNsmFrameData** pFrameDataOfNextDisplayed,
const PmNsmFrameData** pFrameDataOfLastPresented,
const PmNsmFrameData** pFrameDataOfLastDisplayed,
@@ -318,6 +323,7 @@ PM_STATUS StreamClient::ConsumePtrToNextNsmFrameData(const PmNsmFrameData** pNsm
// Set the rest of the incoming frame pointers in
// preparation for the various frame data peeks and
// reads
+ *pNextFrame = nullptr;
*pFrameDataOfNextDisplayed = nullptr;
*pFrameDataOfLastPresented = nullptr;
*pFrameDataOfLastDisplayed = nullptr;
@@ -334,13 +340,14 @@ PM_STATUS StreamClient::ConsumePtrToNextNsmFrameData(const PmNsmFrameData** pNsm
// the frame to be incremented. Can change this when done debugging so we don't have to
// reset the dequeue index.
next_dequeue_idx_ = (next_dequeue_idx_ + 1) % nsm_hdr->max_entries;
- *pFrameDataOfNextDisplayed = PeekNextDisplayedFrame();
+ PeekNextFrames(pNextFrame, pFrameDataOfNextDisplayed);
if (*pFrameDataOfNextDisplayed == nullptr) {
// We were unable to get the next displayed frame. It might not have been displayed
// yet. Reset the next_dequeue_idx back to where we first started.
next_dequeue_idx_ = previous_dequeue_idx;
- // Also reset the current frame data pointer
+ // Also reset the current and next frame data pointers
*pNsmData = nullptr;
+ *pNextFrame = nullptr;
return PM_STATUS::PM_STATUS_SUCCESS;
}
PeekPreviousFrames(pFrameDataOfLastPresented, pFrameDataOfLastDisplayed, pPreviousFrameDataOfLastDisplayed);
@@ -380,11 +387,11 @@ void StreamClient::CopyFrameData(uint64_t start_qpc,
// displayed frame.
if (src_frame->present_event.last_displayed_qpc > 0) {
dst_frame->ms_between_display_change =
- QpcDeltaToMs(src_frame->present_event.ScreenTime -
+ QpcDeltaToMs(src_frame->present_event.Displayed_ScreenTime[0] -
src_frame->present_event.last_displayed_qpc,
GetQpcFrequency());
}
- dst_frame->ms_until_displayed = QpcDeltaToMs(src_frame->present_event.ScreenTime -
+ dst_frame->ms_until_displayed = QpcDeltaToMs(src_frame->present_event.Displayed_ScreenTime[0] -
src_frame->present_event.PresentStartTime,
GetQpcFrequency());
} else {
diff --git a/IntelPresentMon/Streamer/StreamClient.h b/IntelPresentMon/Streamer/StreamClient.h
index c8e0e804..56584de3 100644
--- a/IntelPresentMon/Streamer/StreamClient.h
+++ b/IntelPresentMon/Streamer/StreamClient.h
@@ -23,7 +23,8 @@ class StreamClient {
// Dequeue a frame of data from shared mem and update the last_read_idx
PM_STATUS RecordFrame(PM_FRAME_DATA** out_frame_data);
// Dequeue a frame of data from shared mem and update the last_read_idx (just get pointer to NsmData)
- PM_STATUS ConsumePtrToNextNsmFrameData(const PmNsmFrameData** pNsmData,
+ PM_STATUS ConsumePtrToNextNsmFrameData(const PmNsmFrameData** pNsmData,
+ const PmNsmFrameData** pNextFrame,
const PmNsmFrameData** pFrameDataOfNextDisplayed,
const PmNsmFrameData** pFrameDataOfLastPresented,
const PmNsmFrameData** pFrameDataOfLastDisplayed,
@@ -49,7 +50,8 @@ class StreamClient {
private:
uint64_t CheckPendingReadFrames();
- const PmNsmFrameData* PeekNextDisplayedFrame();
+ void PeekNextFrames(const PmNsmFrameData** pNextFrame,
+ const PmNsmFrameData** pNextDisplayedFrame);
void PeekPreviousFrames(const PmNsmFrameData** pFrameDataOfLastPresented,
const PmNsmFrameData** pFrameDataOfLastDisplayed,
const PmNsmFrameData** pPreviousFrameDataOfLastDisplayed);
diff --git a/IntelPresentMon/Streamer/Streamer.cpp b/IntelPresentMon/Streamer/Streamer.cpp
index 96a74fc9..800b3176 100644
--- a/IntelPresentMon/Streamer/Streamer.cpp
+++ b/IntelPresentMon/Streamer/Streamer.cpp
@@ -78,14 +78,30 @@ void Streamer::CopyFromPresentMonPresentEvent(
nsm_present_event->TimeInPresent = present_event->TimeInPresent;
nsm_present_event->GPUStartTime = present_event->GPUStartTime;
nsm_present_event->ReadyTime = present_event->ReadyTime;
- nsm_present_event->ScreenTime = present_event->ScreenTime;
nsm_present_event->InputTime = present_event->InputTime;
nsm_present_event->MouseClickTime = present_event->MouseClickTime;
+ nsm_present_event->AppSleepStartTime = present_event->AppSleepStartTime;
+ nsm_present_event->AppSleepEndTime = present_event->AppSleepEndTime;
+ nsm_present_event->AppSimStartTime = present_event->AppSimStartTime;
+ nsm_present_event->AppSimEndTime = present_event->AppSimEndTime;
+ nsm_present_event->AppRenderSubmitStartTime = present_event->AppRenderSubmitStartTime;
+ nsm_present_event->AppRenderSubmitEndTime = present_event->AppRenderSubmitEndTime;
+ nsm_present_event->AppPresentStartTime = present_event->AppPresentStartTime;
+ nsm_present_event->AppPresentEndTime = present_event->AppPresentEndTime;
+ nsm_present_event->AppInputTime = present_event->AppInputSample.first;
+ nsm_present_event->AppInputType = present_event->AppInputSample.second;
+
nsm_present_event->SwapChainAddress = present_event->SwapChainAddress;
nsm_present_event->SyncInterval = present_event->SyncInterval;
nsm_present_event->PresentFlags = present_event->PresentFlags;
+ nsm_present_event->DisplayedCount = (uint32_t) min(present_event->Displayed.size(), _countof(nsm_present_event->Displayed_ScreenTime));
+ for (uint32_t i = 0; i < nsm_present_event->DisplayedCount; ++i) {
+ nsm_present_event->Displayed_ScreenTime[i] = present_event->Displayed[i].second;
+ nsm_present_event->Displayed_FrameType[i] = present_event->Displayed[i].first;
+ }
+
nsm_present_event->CompositionSurfaceLuid =
present_event->CompositionSurfaceLuid;
nsm_present_event->Win32KPresentCount = present_event->Win32KPresentCount;
@@ -110,7 +126,6 @@ void Streamer::CopyFromPresentMonPresentEvent(
nsm_present_event->PresentMode = present_event->PresentMode;
nsm_present_event->FinalState = present_event->FinalState;
nsm_present_event->InputType = present_event->InputType;
- nsm_present_event->FrameType = present_event->FrameType;
nsm_present_event->SupportsTearing = present_event->SupportsTearing;
nsm_present_event->WaitForFlipEvent = present_event->WaitForFlipEvent;
@@ -186,6 +201,10 @@ void Streamer::ProcessPresentEvent(
}
PmNsmFrameData data = {};
+ if (present_event->PresentStartTime == 2694939860393)
+ {
+ auto i = 20;
+ }
// Copy the passed in PresentEvent data into the PmNsmFrameData
// structure.
CopyFromPresentMonPresentEvent(present_event, &data.present_event);
diff --git a/IntelPresentMon/ULT/PmFrameGenerator.cpp b/IntelPresentMon/ULT/PmFrameGenerator.cpp
index 8315290b..8ba91c17 100644
--- a/IntelPresentMon/ULT/PmFrameGenerator.cpp
+++ b/IntelPresentMon/ULT/PmFrameGenerator.cpp
@@ -741,10 +741,10 @@ bool PmFrameGenerator::CalculateFpsMetrics(
pmft_frames_[current_frame_number].time_in_seconds;
swap_chain->cpu_0_time = swap_chain->cpu_n_time;
if (pmft_frames_[current_frame_number].dropped == false) {
- swap_chain->display_n_screen_time =
+ swap_chain->mLastDisplayedScreenTime =
pmft_frames_[current_frame_number].time_in_seconds +
(pmft_frames_[current_frame_number].ms_until_displayed / 1000.);
- swap_chain->display_0_screen_time = swap_chain->display_n_screen_time;
+ swap_chain->display_0_screen_time = swap_chain->mLastDisplayedScreenTime;
swap_chain->dropped.push_back(0);
} else {
swap_chain->dropped.push_back(1);
@@ -776,7 +776,7 @@ bool PmFrameGenerator::CalculateFpsMetrics(
1. / (swap_chain->display_0_screen_time -
current_display_screen_time_s));
} else {
- swap_chain->display_n_screen_time = current_display_screen_time_s;
+ swap_chain->mLastDisplayedScreenTime = current_display_screen_time_s;
}
swap_chain->display_0_screen_time = current_display_screen_time_s;
swap_chain->dropped.push_back(0);
@@ -800,7 +800,7 @@ bool PmFrameGenerator::CalculateFpsMetrics(
CalcMetricStats(swap_chain.gpu_sum_ms, temp_fps_data.gpu_busy);
// Overwrite the average both the display and cpu average fps.
auto avg_fps =
- swap_chain.display_n_screen_time - swap_chain.display_0_screen_time;
+ swap_chain.mLastDisplayedScreenTime - swap_chain.display_0_screen_time;
avg_fps /= swap_chain.display_fps.size();
avg_fps = 1. / avg_fps;
temp_fps_data.displayed_fps.avg = avg_fps;
diff --git a/IntelPresentMon/ULT/PmFrameGenerator.h b/IntelPresentMon/ULT/PmFrameGenerator.h
index 097fedb2..7bb5925f 100644
--- a/IntelPresentMon/ULT/PmFrameGenerator.h
+++ b/IntelPresentMon/ULT/PmFrameGenerator.h
@@ -207,7 +207,7 @@ class PmFrameGenerator {
std::vector frame_times_ms;
std::vector gpu_sum_ms;
std::vector dropped;
- double display_n_screen_time = 0.;
+ double mLastDisplayedScreenTime = 0.;
double display_0_screen_time = 0.;
double cpu_n_time = 0.;
double cpu_0_time = 0.;
diff --git a/IntelPresentMon/CommonUtilities/BuildId.cpp b/IntelPresentMon/Versioning/BuildId.cpp
similarity index 95%
rename from IntelPresentMon/CommonUtilities/BuildId.cpp
rename to IntelPresentMon/Versioning/BuildId.cpp
index 98018063..4eb32c24 100644
--- a/IntelPresentMon/CommonUtilities/BuildId.cpp
+++ b/IntelPresentMon/Versioning/BuildId.cpp
@@ -1,7 +1,7 @@
#include "BuildId.h"
#include "generated/build_id.h"
-namespace pmon::util
+namespace pmon::bid
{
const char* BuildIdShortHash() noexcept
{
diff --git a/IntelPresentMon/CommonUtilities/BuildId.h b/IntelPresentMon/Versioning/BuildId.h
similarity index 91%
rename from IntelPresentMon/CommonUtilities/BuildId.h
rename to IntelPresentMon/Versioning/BuildId.h
index 2e8b85ad..c6a5cf22 100644
--- a/IntelPresentMon/CommonUtilities/BuildId.h
+++ b/IntelPresentMon/Versioning/BuildId.h
@@ -1,6 +1,6 @@
#pragma once
-namespace pmon::util
+namespace pmon::bid
{
const char* BuildIdShortHash() noexcept;
const char* BuildIdLongHash() noexcept;
diff --git a/IntelPresentMon/Versioning/Versioning.vcxproj b/IntelPresentMon/Versioning/Versioning.vcxproj
new file mode 100644
index 00000000..bbebb587
--- /dev/null
+++ b/IntelPresentMon/Versioning/Versioning.vcxproj
@@ -0,0 +1,122 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 17.0
+ Win32Proj
+ {c73aa532-e532-4d93-9279-905444653c08}
+ Versioning
+ 10.0
+
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BuildGenerateSources
+ BuildGenerateSources
+
+
+ BuildGenerateSources
+ BuildGenerateSources
+
+
+ false
+
+
+
+ Level3
+ true
+ _DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDebug
+
+
+
+
+ true
+
+
+ scripts\pre-build.bat
+
+
+ Generating Build IDs
+
+
+ force-run-nonexist.fake
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+
+
+
+
+ true
+ true
+ true
+
+
+ scripts\pre-build.bat
+
+
+ Generating Build IDs
+
+
+ force-run-nonexist.fake
+
+
+
+
+
+
\ No newline at end of file
diff --git a/IntelPresentMon/Versioning/Versioning.vcxproj.filters b/IntelPresentMon/Versioning/Versioning.vcxproj.filters
new file mode 100644
index 00000000..3a0a3631
--- /dev/null
+++ b/IntelPresentMon/Versioning/Versioning.vcxproj.filters
@@ -0,0 +1,33 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+
+
\ No newline at end of file
diff --git a/IntelPresentMon/CommonUtilities/generated/.gitignore b/IntelPresentMon/Versioning/generated/.gitignore
similarity index 100%
rename from IntelPresentMon/CommonUtilities/generated/.gitignore
rename to IntelPresentMon/Versioning/generated/.gitignore
diff --git a/IntelPresentMon/CommonUtilities/build-scripts/pre-build.bat b/IntelPresentMon/Versioning/scripts/pre-build.bat
similarity index 100%
rename from IntelPresentMon/CommonUtilities/build-scripts/pre-build.bat
rename to IntelPresentMon/Versioning/scripts/pre-build.bat
diff --git a/IntelPresentMon/metrics.csv b/IntelPresentMon/metrics.csv
index c6c28b3b..225699bb 100644
--- a/IntelPresentMon/metrics.csv
+++ b/IntelPresentMon/metrics.csv
@@ -26,6 +26,7 @@ PM_METRIC_VIDEO_BUSY,,Video Busy,How long the GPU video encode/decode engines we
PM_METRIC_DISPLAY_LATENCY,,Display Latency,How long it took from the start of this frame until the frame was displayed on the screen.
PM_METRIC_DISPLAYED_TIME,,Displayed Time,"How long the frame was displayed on the screen, or 'NA' if the frame was not displayed."
PM_METRIC_ANIMATION_ERROR,,Animation Error,"The difference between the previous frame's CPU delta and display delta."
+PM_METRIC_ANIMATION_TIME,,Animation Time,The time the CPU started animation work on this frame.
PM_METRIC_CLICK_TO_PHOTON_LATENCY,,Click-To-Photon Latency,How long it took from the earliest mouse click that contributed to this frame until this frame was displayed.
PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY,,All-Input-To-Photon Latency,How long it took from the earliest keyboard or mouse interaction that contributed to this frame until this frame was displayed.
,,,
@@ -79,4 +80,6 @@ PM_METRIC_CPU_POWER_LIMIT,1,CPU Power Limit,Power limit of the CPU.
PM_METRIC_CPU_POWER,1,CPU Power,Power consumed by the CPU.
PM_METRIC_CPU_TEMPERATURE,1,CPU Temperature,Temperature of the CPU.
PM_METRIC_CPU_FREQUENCY,1,CPU Frequency,Clock speed of the CPU.
-PM_METRIC_CPU_CORE_UTILITY,1,CPU Core Utility,Amount of CPU processing utility being used per core.
\ No newline at end of file
+PM_METRIC_CPU_CORE_UTILITY,1,CPU Core Utility,Amount of CPU processing utility being used per core.
+,,,
+PM_METRIC_INSTRUMENTED_LATENCY,,Instrumented Latency,Instrumented Frame Start To Display Latency,How long it took from the instrumented start of this frame until the frame was displayed on the screen.
\ No newline at end of file
diff --git a/PresentData/Debug.cpp b/PresentData/Debug.cpp
index 36bc18c5..2e19400d 100644
--- a/PresentData/Debug.cpp
+++ b/PresentData/Debug.cpp
@@ -178,7 +178,8 @@ wchar_t const* PMPFrameTypeToString(Intel_PresentMon::FrameType type)
case Intel_PresentMon::FrameType::Unspecified: return L"Unspecified";
case Intel_PresentMon::FrameType::Original: return L"Original";
case Intel_PresentMon::FrameType::Repeated: return L"Repeated";
- case Intel_PresentMon::FrameType::AMD_AFMF: return L"AMD_AFMF";
+ case Intel_PresentMon::FrameType::Intel_XEFG: return L"Intel XeSS-FG";
+ case Intel_PresentMon::FrameType::AMD_AFMF: return L"AMD AFMF";
}
assert(false);
@@ -191,10 +192,21 @@ void PrintFrameType(FrameType type)
case FrameType::Unspecified: wprintf(L"Unspecified"); break;
case FrameType::Application: wprintf(L"Application"); break;
case FrameType::Repeated: wprintf(L"Repeated"); break;
- case FrameType::AMD_AFMF: wprintf(L"AMD_AFMF"); break;
+ case FrameType::Intel_XEFG: wprintf(L"Intel XeSS-FG"); break;
+ case FrameType::AMD_AFMF: wprintf(L"AMD AFMF"); break;
default: wprintf(L"Unknown (%u)", type); assert(false); break;
}
}
+void PrintInputType(uint32_t type)
+{
+ using namespace Intel_PresentMon;
+ switch (type) {
+ case InputType::Unspecified: wprintf(L"Unspecified"); break;
+ case InputType::MouseClick: wprintf(L"MouseClick"); break;
+ case InputType::KeyboardClick: wprintf(L"KeyboardClick"); break;
+ default: wprintf(L"Unknown (%u)", type); assert(false); break;
+ }
+}
void PrintEventHeader(EVENT_HEADER const& hdr)
{
@@ -231,6 +243,7 @@ void PrintEventHeader(EVENT_RECORD* eventRecord, EventMetadata* metadata, char c
else if (propFunc == PrintDmaPacketType) PrintDmaPacketType(metadata->GetEventData(eventRecord, propName));
else if (propFunc == PrintPresentFlags) PrintPresentFlags(metadata->GetEventData(eventRecord, propName));
else if (propFunc == PrintPresentHistoryModel) PrintPresentHistoryModel(metadata->GetEventData(eventRecord, propName));
+ else if (propFunc == PrintInputType) PrintInputType(metadata->GetEventData(eventRecord, propName));
else assert(false);
}
wprintf(L"\n");
@@ -252,7 +265,6 @@ void FlushModifiedPresent()
}
FLUSH_MEMBER(PrintTimeDelta, TimeInPresent)
FLUSH_MEMBER(PrintTime, ReadyTime)
- FLUSH_MEMBER(PrintTime, ScreenTime)
FLUSH_MEMBER(PrintTime, InputTime)
FLUSH_MEMBER(PrintTime, MouseClickTime)
FLUSH_MEMBER(PrintTime, GPUStartTime)
@@ -278,9 +290,27 @@ void FlushModifiedPresent()
FLUSH_MEMBER(PrintBool, PresentFailed)
FLUSH_MEMBER(PrintBool, WaitingForPresentStop)
FLUSH_MEMBER(PrintBool, WaitingForFlipFrameType)
- FLUSH_MEMBER(PrintFrameType, FrameType)
+ FLUSH_MEMBER(PrintBool, DoneWaitingForFlipFrameType)
+ FLUSH_MEMBER(PrintBool, WaitingForFrameId)
#undef FLUSH_MEMBER
+ // Displayed
+ if (gModifiedPresent->Displayed != gOriginalPresentValues.Displayed) {
+ if (changedCount++ == 0) {
+ wprintf(L"%*hsp%u", 17 + 6 + 6, "", gModifiedPresent->FrameId);
+ }
+ wprintf(L" Displayed=");
+ auto first = true;
+ for (auto const& pr : gModifiedPresent->Displayed) {
+ wprintf(L"%c ", first ? L'[' : L',');
+ PrintFrameType(pr.first);
+ wprintf(L":");
+ PrintTime(pr.second);
+ first = false;
+ }
+ wprintf(L"%c]", first ? L'[' : L' ');
+ }
+
// PresentIds
if (gModifiedPresent->PresentIds != gOriginalPresentValues.PresentIds) {
if (changedCount++ == 0) {
@@ -407,7 +437,8 @@ void VerboseTraceEventImpl(PMTraceConsumer* pmConsumer, EVENT_RECORD* eventRecor
case Blit_Info::Id: PrintEventHeader(eventRecord, metadata, "Blit_Info", { L"hwnd", PrintU64x,
L"bRedirectedPresent", PrintU32 }); break;
case BlitCancel_Info::Id: PrintEventHeader(hdr, "BlitCancel_Info"); break;
- case FlipMultiPlaneOverlay_Info::Id: PrintEventHeader(hdr, "FlipMultiPlaneOverlay_Info"); break;
+ case FlipMultiPlaneOverlay_Info::Id: PrintEventHeader(eventRecord, metadata, "FlipMultiPlaneOverlay_Info", { L"VidPnSourceId", PrintU32,
+ L"LayerIndex", PrintU32 }); break;
case Present_Info::Id: PrintEventHeader(hdr, "DxgKrnl_Present_Info"); break;
case MMIOFlip_Info::Id: PrintEventHeader(eventRecord, metadata, "MMIOFlip_Info", { L"FlipSubmitSequence", PrintU64, }); break;
@@ -645,7 +676,68 @@ void VerboseTraceEventImpl(PMTraceConsumer* pmConsumer, EVENT_RECORD* eventRecor
}
}
}
- return;
+ if (pmConsumer->mTrackPMMeasurements) {
+ switch (hdr.EventDescriptor.Id) {
+ case MeasuredInput_Info::Id:
+ PrintEventHeader(eventRecord, metadata, "PM_Measurement_Input", { L"InputType", PrintInputType, L"Time", PrintU64x });
+ break;
+ case MeasuredScreenChange_Info::Id:
+ PrintEventHeader(eventRecord, metadata, "PM_Measurement_ScreenChange", { L"Time", PrintU64x });
+ break;
+ }
+ return;
+ }
+
+ if (pmConsumer->mTrackAppTiming) {
+ switch (hdr.EventDescriptor.Id) {
+ case Intel_PresentMon::AppSleepStart_Info::Id: {
+ DebugAssert(eventRecord->UserDataLength == sizeof(Intel_PresentMon::AppSleepStart_Info_Props));
+ PrintEventHeader(eventRecord, metadata, "PM_AppSleepStart", { L"FrameId", PrintU32 });
+ }
+ return;
+ case Intel_PresentMon::AppSleepEnd_Info::Id: {
+ DebugAssert(eventRecord->UserDataLength == sizeof(Intel_PresentMon::AppSleepEnd_Info_Props));
+ PrintEventHeader(eventRecord, metadata, "PM_AppSleepEnd", { L"FrameId", PrintU32 });
+ }
+ return;
+ case Intel_PresentMon::AppSimulationStart_Info::Id: {
+ DebugAssert(eventRecord->UserDataLength == sizeof(Intel_PresentMon::AppSimulationStart_Info_Props));
+ PrintEventHeader(eventRecord, metadata, "PM_AppSimulationStart", { L"FrameId", PrintU32 });
+ }
+ return;
+ case Intel_PresentMon::AppSimulationEnd_Info::Id: {
+ DebugAssert(eventRecord->UserDataLength == sizeof(Intel_PresentMon::AppSimulationEnd_Info_Props));
+ PrintEventHeader(eventRecord, metadata, "PM_AppSimulationEnd", { L"FrameId", PrintU32 });
+ }
+ return;
+ case Intel_PresentMon::AppRenderSubmitStart_Info::Id: {
+ DebugAssert(eventRecord->UserDataLength == sizeof(Intel_PresentMon::AppRenderSubmitStart_Info_Props));
+ PrintEventHeader(eventRecord, metadata, "PM_AppRenderSubmitStart", { L"FrameId", PrintU32 });
+ }
+ return;
+ case Intel_PresentMon::AppRenderSubmitEnd_Info::Id: {
+ DebugAssert(eventRecord->UserDataLength == sizeof(Intel_PresentMon::AppRenderSubmitEnd_Info_Props));
+ PrintEventHeader(eventRecord, metadata, "PM_AppRenderSubmitEnd", { L"FrameId", PrintU32 });
+ }
+ return;
+ case Intel_PresentMon::AppPresentStart_Info::Id: {
+ DebugAssert(eventRecord->UserDataLength == sizeof(Intel_PresentMon::AppPresentStart_Info_Props));
+ PrintEventHeader(eventRecord, metadata, "PM_AppPresentStart", { L"FrameId", PrintU32 });
+ }
+ return;
+ case Intel_PresentMon::AppPresentEnd_Info::Id: {
+ DebugAssert(eventRecord->UserDataLength == sizeof(Intel_PresentMon::AppPresentEnd_Info_Props));
+ PrintEventHeader(eventRecord, metadata, "PM_AppPresentEnd", { L"FrameId", PrintU32 });
+ }
+ return;
+ case Intel_PresentMon::AppInputSample_Info::Id: {
+ DebugAssert(eventRecord->UserDataLength == sizeof(Intel_PresentMon::AppInputSample_Info_Props));
+ PrintEventHeader(eventRecord, metadata, "PM_AppInputSample", { L"FrameId", PrintU32,
+ L"InputType", PrintInputType});
+ }
+ return;
+ }
+ }
}
if (hdr.ProviderId == NT_Process::GUID) {
diff --git a/PresentData/ETW/Intel_PresentMon.h b/PresentData/ETW/Intel_PresentMon.h
index 57b10bbb..8f7835a8 100644
--- a/PresentData/ETW/Intel_PresentMon.h
+++ b/PresentData/ETW/Intel_PresentMon.h
@@ -11,7 +11,9 @@ struct __declspec(uuid("{ECAA4712-4644-442F-B94C-A32F6CF8A499}")) GUID_STRUCT;
static const auto GUID = __uuidof(GUID_STRUCT);
enum class Keyword : uint64_t {
- FrameTypes = 0x1,
+ FrameTypes = 0x1,
+ Measurements = 0x2,
+ Application = 0x20,
};
enum class Level : uint8_t {
@@ -29,7 +31,18 @@ enum class Level : uint8_t {
static Keyword const Keyword = (Keyword) keyword_; \
}
-EVENT_DESCRIPTOR_DECL(FlipFrameType_Info , 0x0002, 0x00, 0x00, 0x04, 0x00, 0x0002, 0x0000000000000001);
+EVENT_DESCRIPTOR_DECL(AppInputSample_Info, 0x003a, 0x00, 0x00, 0x04, 0x00, 0x003a, 0x0000000000000020);
+EVENT_DESCRIPTOR_DECL(AppPresentEnd_Info, 0x0039, 0x00, 0x00, 0x04, 0x00, 0x0039, 0x0000000000000020);
+EVENT_DESCRIPTOR_DECL(AppPresentStart_Info, 0x0038, 0x00, 0x00, 0x04, 0x00, 0x0038, 0x0000000000000020);
+EVENT_DESCRIPTOR_DECL(AppRenderSubmitEnd_Info, 0x0037, 0x00, 0x00, 0x04, 0x00, 0x0037, 0x0000000000000020);
+EVENT_DESCRIPTOR_DECL(AppRenderSubmitStart_Info, 0x0036, 0x00, 0x00, 0x04, 0x00, 0x0036, 0x0000000000000020);
+EVENT_DESCRIPTOR_DECL(AppSimulationEnd_Info, 0x0035, 0x00, 0x00, 0x04, 0x00, 0x0035, 0x0000000000000020);
+EVENT_DESCRIPTOR_DECL(AppSimulationStart_Info, 0x0034, 0x00, 0x00, 0x04, 0x00, 0x0034, 0x0000000000000020);
+EVENT_DESCRIPTOR_DECL(AppSleepEnd_Info, 0x0033, 0x00, 0x00, 0x04, 0x00, 0x0033, 0x0000000000000020);
+EVENT_DESCRIPTOR_DECL(AppSleepStart_Info, 0x0032, 0x00, 0x00, 0x04, 0x00, 0x0032, 0x0000000000000020);
+EVENT_DESCRIPTOR_DECL(FlipFrameType_Info, 0x0002, 0x00, 0x00, 0x04, 0x00, 0x0002, 0x0000000000000001);
+EVENT_DESCRIPTOR_DECL(MeasuredInput_Info, 0x000a, 0x00, 0x00, 0x04, 0x00, 0x000a, 0x0000000000000002);
+EVENT_DESCRIPTOR_DECL(MeasuredScreenChange_Info, 0x000b, 0x00, 0x00, 0x04, 0x00, 0x000b, 0x0000000000000002);
EVENT_DESCRIPTOR_DECL(PresentFrameType_Info, 0x0001, 0x00, 0x00, 0x04, 0x00, 0x0001, 0x0000000000000001);
#undef EVENT_DESCRIPTOR_DECL
@@ -38,11 +51,64 @@ enum class FrameType : uint8_t {
Unspecified = 0,
Original = 1,
Repeated = 2,
+ Intel_XEFG = 50,
AMD_AFMF = 100,
};
+enum class InputType : uint32_t {
+ Unspecified = 0,
+ MouseClick = 1,
+ KeyboardClick = 2,
+};
+
#pragma pack(push, 1)
+struct AppInputSample_Info_Props {
+ uint32_t FrameId;
+ InputType InputType;
+};
+
+struct AppPresentEnd_Info_Props {
+ uint32_t FrameId;
+};
+
+struct AppPresentStart_Info_Props {
+ uint32_t FrameId;
+};
+
+struct AppRenderSubmitEnd_Info_Props {
+ uint32_t FrameId;
+};
+
+struct AppRenderSubmitStart_Info_Props {
+ uint32_t FrameId;
+};
+
+struct AppSimulationEnd_Info_Props {
+ uint32_t FrameId;
+};
+
+struct AppSimulationStart_Info_Props {
+ uint32_t FrameId;
+};
+
+struct AppSleepEnd_Info_Props {
+ uint32_t FrameId;
+};
+
+struct AppSleepStart_Info_Props {
+ uint32_t FrameId;
+};
+
+struct MeasuredInput_Info_Props {
+ uint64_t Time;
+ InputType InputType;
+};
+
+struct MeasuredScreenChange_Info_Props {
+ uint64_t Time;
+};
+
struct FlipFrameType_Info_Props {
uint32_t VidPnSourceId;
uint32_t LayerIndex;
diff --git a/PresentData/PresentMonTraceConsumer.cpp b/PresentData/PresentMonTraceConsumer.cpp
index 06bac1fd..0af68601 100644
--- a/PresentData/PresentMonTraceConsumer.cpp
+++ b/PresentData/PresentMonTraceConsumer.cpp
@@ -41,6 +41,7 @@ static inline FrameType ConvertPMPFrameTypeToFrameType(Intel_PresentMon::FrameTy
case Intel_PresentMon::FrameType::Unspecified: return FrameType::Unspecified;
case Intel_PresentMon::FrameType::Original: return FrameType::Application;
case Intel_PresentMon::FrameType::Repeated: return FrameType::Repeated;
+ case Intel_PresentMon::FrameType::Intel_XEFG: return FrameType::Intel_XEFG;
case Intel_PresentMon::FrameType::AMD_AFMF: return FrameType::AMD_AFMF;
}
@@ -48,6 +49,51 @@ static inline FrameType ConvertPMPFrameTypeToFrameType(Intel_PresentMon::FrameTy
return FrameType::Unspecified;
}
+// Returns true if a ScreenTime has been set for this present.
+static inline bool HasScreenTime(std::shared_ptr const& p)
+{
+ for (auto const& pr : p->Displayed) {
+ if (pr.second != 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Set a ScreenTime for this present.
+//
+// If a ScreenTime has not yet been set, add it to Displayed and set Presented.
+//
+// Otherwise, if the set ScreenTime has no FrameType, overwrite both ScreenTime and FrameType.
+//
+// Otherwise, if the set ScreenTime is zero, overwrite ScreenTime.
+//
+// Otherwise, if the call has a FrameType, add it to the list.
+static inline void SetScreenTime(std::shared_ptr const& p, uint64_t screenTime, FrameType frameType = FrameType::NotSet)
+{
+ DebugAssert(screenTime != 0);
+
+ auto displayedCount = p->Displayed.size();
+ if (displayedCount == 0) {
+ p->Displayed.emplace_back(frameType, screenTime);
+ p->FinalState = PresentResult::Presented;
+ } else if (p->Displayed.back().first == FrameType::NotSet) {
+ p->Displayed.back().first = frameType;
+ p->Displayed.back().second = screenTime;
+ } else if (p->Displayed.back().second == 0) {
+ DebugAssert(frameType == FrameType::NotSet);
+ for (size_t i = 0; i < displayedCount; ++i) {
+ if (p->Displayed[i].second == 0) {
+ p->Displayed.back().second = screenTime;
+ p->FinalState = PresentResult::Presented;
+ break;
+ }
+ }
+ } else if (frameType != FrameType::NotSet) {
+ p->Displayed.emplace_back(frameType, screenTime);
+ }
+}
+
PresentEvent::PresentEvent()
: PresentStartTime(0)
, ProcessId(0)
@@ -57,9 +103,19 @@ PresentEvent::PresentEvent()
, ReadyTime(0)
, GPUDuration(0)
, GPUVideoDuration(0)
- , ScreenTime(0)
, InputTime(0)
, MouseClickTime(0)
+ , AppFrameId(0)
+ , AppSleepStartTime(0)
+ , AppSleepEndTime(0)
+ , AppSimStartTime(0)
+ , AppSimEndTime(0)
+ , AppRenderSubmitStartTime(0)
+ , AppRenderSubmitEndTime(0)
+ , AppPresentStartTime(0)
+ , AppPresentEndTime(0)
+ , AppInputSample{ 0, InputDeviceType::None }
+
, SwapChainAddress(0)
, SyncInterval(-1)
, PresentFlags(0)
@@ -84,7 +140,6 @@ PresentEvent::PresentEvent()
, PresentMode(PresentMode::Unknown)
, FinalState(PresentResult::Unknown)
, InputType(InputDeviceType::None)
- , FrameType(FrameType::NotSet)
, SupportsTearing(false)
, WaitForFlipEvent(false)
@@ -100,6 +155,8 @@ PresentEvent::PresentEvent()
, WaitingForPresentStop(false)
, WaitingForFlipFrameType(false)
+ , DoneWaitingForFlipFrameType(false)
+ , WaitingForFrameId(false)
{
}
@@ -228,7 +285,7 @@ void PMTraceConsumer::HandleDxgkBlt(EVENT_HEADER const& hdr, uint64_t hwnd, bool
// QueuePacket_Start SubmitSequence MMIOFLIP bPresent=1
// QueuePacket_Stop SubmitSequence
// PresentStop
-void PMTraceConsumer::HandleDxgkFlip(EVENT_HEADER const& hdr, int32_t flipInterval, bool isMMIOFlip, bool isMPOFlip)
+std::shared_ptr PMTraceConsumer::HandleDxgkFlip(EVENT_HEADER const& hdr)
{
// First, lookup the in-progress present on the same thread.
//
@@ -263,8 +320,8 @@ void PMTraceConsumer::HandleDxgkFlip(EVENT_HEADER const& hdr, int32_t flipInterv
// If we did see a PresentStart, then use this present
if (presentEvent->Runtime != Runtime::Other) {
// There may be duplicate flip events for MPO situations, so only handle the first.
- if ( presentEvent->PresentMode != PresentMode::Unknown) {
- return;
+ if (presentEvent->PresentMode != PresentMode::Unknown) {
+ return nullptr;
}
break;
}
@@ -276,7 +333,7 @@ void PMTraceConsumer::HandleDxgkFlip(EVENT_HEADER const& hdr, int32_t flipInterv
// Create a new present for this flip
if (!IsProcessTrackedForFiltering(hdr.ProcessId)) {
- return;
+ return nullptr;
}
presentEvent = std::make_shared();
@@ -295,19 +352,6 @@ void PMTraceConsumer::HandleDxgkFlip(EVENT_HEADER const& hdr, int32_t flipInterv
presentEvent->PresentMode = PresentMode::Hardware_Legacy_Flip;
- if (flipInterval != -1) {
- presentEvent->SyncInterval = flipInterval;
- }
- if (isMMIOFlip) {
- presentEvent->WaitForFlipEvent = true;
- }
- if (isMPOFlip) {
- presentEvent->WaitForMPOFlipEvent = true;
- }
- if (!isMMIOFlip && flipInterval == 0) {
- presentEvent->SupportsTearing = true;
- }
-
// If this is the DWM thread, make any presents waiting for DWM dependent on it (i.e., they will
// be displayed when it is).
if (hdr.ThreadId == DwmPresentThreadId) {
@@ -318,6 +362,8 @@ void PMTraceConsumer::HandleDxgkFlip(EVENT_HEADER const& hdr, int32_t flipInterv
}
std::swap(presentEvent->DependentPresents, mPresentsWaitingForDWM);
}
+
+ return presentEvent;
}
void PMTraceConsumer::HandleDxgkQueueSubmit(
@@ -350,7 +396,7 @@ void PMTraceConsumer::HandleDxgkQueueSubmit(
present->SeenDxgkPresent = true;
// If the work is already done, complete it now.
- if (present->ScreenTime != 0) {
+ if (HasScreenTime(present)) {
CompletePresent(present);
}
}
@@ -426,8 +472,7 @@ void PMTraceConsumer::HandleDxgkQueueComplete(uint64_t timestamp, uint64_t hCont
pEvent->ReadyTime = timestamp;
}
- pEvent->ScreenTime = timestamp;
- pEvent->FinalState = PresentResult::Presented;
+ SetScreenTime(pEvent, timestamp);
// Sometimes, the queue packets associated with a present will complete
// before the DxgKrnl PresentInfo event is fired. For blit presents in
@@ -478,7 +523,6 @@ void PMTraceConsumer::HandleDxgkMMIOFlip(uint64_t timestamp, uint32_t submitSequ
{
auto pEvent = FindPresentBySubmitSequence(submitSequence);
if (pEvent != nullptr) {
-
VerboseTraceBeforeModifyingPresent(pEvent.get());
pEvent->ReadyTime = timestamp;
@@ -487,9 +531,9 @@ void PMTraceConsumer::HandleDxgkMMIOFlip(uint64_t timestamp, uint32_t submitSequ
}
if (flags & (uint32_t) Microsoft_Windows_DxgKrnl::SetVidPnSourceAddressFlags::FlipImmediate) {
- pEvent->FinalState = PresentResult::Presented;
- pEvent->ScreenTime = timestamp;
+ SetScreenTime(pEvent, timestamp);
pEvent->SupportsTearing = true;
+
if (pEvent->PresentMode == PresentMode::Hardware_Legacy_Flip) {
CompletePresent(pEvent);
}
@@ -505,8 +549,7 @@ void PMTraceConsumer::HandleDxgkSyncDPC(uint64_t timestamp, uint32_t submitSeque
if (pEvent != nullptr) {
VerboseTraceBeforeModifyingPresent(pEvent.get());
- pEvent->ScreenTime = timestamp;
- pEvent->FinalState = PresentResult::Presented;
+ SetScreenTime(pEvent, timestamp);
// For Hardware_Legacy_Flip, we are done tracking the present. If we
// aren't expecting a subsequent *SyncMultiPlaneDPC_Info event, then we
@@ -551,11 +594,15 @@ void PMTraceConsumer::HandleDxgkPresentHistory(
VerboseTraceBeforeModifyingPresent(presentEvent.get());
presentEvent->ReadyTime = 0;
- presentEvent->ScreenTime = 0;
presentEvent->SupportsTearing = false;
- presentEvent->FinalState = PresentResult::Unknown;
presentEvent->DxgkPresentHistoryToken = token;
+ if (presentEvent->Displayed.size() == 1 &&
+ presentEvent->Displayed[0].first == FrameType::NotSet) {
+ presentEvent->Displayed.clear();
+ presentEvent->FinalState = PresentResult::Unknown;
+ }
+
auto iter = mPresentByDxgkPresentHistoryToken.find(token);
if (iter != mPresentByDxgkPresentHistoryToken.end()) {
RemoveLostPresent(iter->second);
@@ -678,7 +725,16 @@ void PMTraceConsumer::HandleDXGKEvent(EVENT_RECORD* pEventRecord)
auto FlipInterval = desc[0].GetData();
auto MMIOFlip = desc[1].GetData