XinJiangBBH_LBE/Plugins/Streamline/Docs/ProgrammingGuidePCL.md

191 lines
7.3 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Streamline - PCL Stats
=======================
>The focus of this guide is on using Streamline to integrate PCL (PC Latency) Stats into an application.
Version 2.4.0
=======
The application should not explicitly check for GPU HW, vendor, and driver version.
PCL Stats enables real time measurement of per-frame PC latency (PCL) during gameplay. E2E system latency = PCL + peripheral latency + display latency. And PCL = input sampling latency + simulation start to present + present to displayed.
Windows messages with ID == `sl::PclState::statsWindowMessage` are sent to the application periodically. The time this ping message is sent is recorded and is used to measure the latency between the simulated input and the application picking up the input. This is the input sampling latency.
Typically, the application's message pump would process keyboard and mouse input messages into a queue to be read in the upcoming frame. On seeing the ping message, the application must either call `slPclSetMarker` or `sl::PclMarker::ePCLatencyPing` to send the ping marker right away, or put it in the queue, or set a flag for the next simulation to send the ping marker.
> **NOTE:**
> The exact timing of the ping marker does not matter. It is the frame index parameter that identify which frame picks up the simulated input. For example, since the frame index is usually incremented at simulation start, in the case of the ping marker being sent at message pump before simulation start, use current frame index +1.
### 1.0 INITIALIZE AND SHUTDOWN
Call `slInit` as early as possible (before any dxgi/d3d11/d3d12 APIs are invoked). Similar to sl.common, PCL is loaded by default and doesn't need to be explicitly requested via `sl::Preferences::featuresToLoad` (as required for other plugins).
```cpp
#include <sl.h>
#include <sl_pcl.h>
sl::Preferences pref{};
pref.showConsole = true; // for debugging, set to false in production
pref.logLevel = sl::eLogLevelDefault;
pref.pathsToPlugins = {}; // change this if Streamline plugins are not located next to the executable
pref.numPathsToPlugins = 0; // change this if Streamline plugins are not located next to the executable
pref.pathToLogsAndData = {}; // change this to enable logging to a file
pref.logMessageCallback = myLogMessageCallback; // highly recommended to track warning/error messages in your callback
pref.applicationId = myId; // Provided by NVDA, required if using NGX components (DLSS 2/3)
pref.engineType = myEngine; // If using UE or Unity
pref.engineVersion = myEngineVersion; // Optional version
pref.projectId = myProjectId; // Optional project id
if(SL_FAILED(res, slInit(pref)))
{
// Handle error, check the logs
if(res == sl::Result::eErrorDriverOutOfDate) { /* inform user */}
// and so on ...
}
```
For more details please see [preferences](ProgrammingGuide.md#221-preferences)
Call `slShutdown()` before destroying dxgi/d3d11/d3d12/vk instances, devices and other components in your engine.
```cpp
if(SL_FAILED(res, slShutdown()))
{
// Handle error, check the logs
}
```
#### 1.1 SET THE CORRECT DEVICE
Once the main device is created call `slSetD3DDevice` or `slSetVulkanInfo`:
```cpp
if(SL_FAILED(res, slSetD3DDevice(nativeD3DDevice)))
{
// Handle error, check the logs
}
```
### 2.0 CHECK IF PCL STATS IS SUPPORTED
As soon as SL is initialized, you can check if PCL Stats is available for the specific adapter you want to use:
```cpp
Microsoft::WRL::ComPtr<IDXGIFactory> factory;
if (SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory)))
{
Microsoft::WRL::ComPtr<IDXGIAdapter> adapter{};
uint32_t i = 0;
while (factory->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND)
{
DXGI_ADAPTER_DESC desc{};
if (SUCCEEDED(adapter->GetDesc(&desc)))
{
sl::AdapterInfo adapterInfo{};
adapterInfo.deviceLUID = (uint8_t*)&desc.AdapterLuid;
adapterInfo.deviceLUIDSizeInBytes = sizeof(LUID);
if (SL_FAILED(result, slIsFeatureSupported(sl::kFeaturePCL, adapterInfo)))
{
// Requested feature is not supported on the system, fallback to the default method
switch (result)
{
case sl::Result::eErrorOSOutOfDate: // inform user to update OS
case sl::Result::eErrorDriverOutOfDate: // inform user to update driver
case sl::Result::eErrorNoSupportedAdapter: // cannot use this adapter (older or non-NVDA GPU etc)
// and so on ...
};
}
else
{
// Feature is supported on this adapter!
}
}
i++;
}
}
```
> **IMPORTANT:**
> **PCL Stats is supported on all GPU hardwares, vendors, and driver versions**. As long as `sl::kFeaturePCL` is supported, the application should always make the same `slPCLSetMarker` calls without any explicit GPU hardware, vendor, and driver version checks.
### 3.0 ADD SL PCL STATS TO THE RENDERING PIPELINE
Call `slPclSetMarker` at the appropriate locations where markers need to be injected:
```cpp
bool isPCLSupported = slIsFeatureSupported(sl::kFeaturePCL, adapterInfo);
if (!isPCLSupported)
{
return;
}
// Using helpers from sl_pcl.h
// Mark the section where specific activity is happening.
//
// Here for example we will make the simulation code.
//
// Starting new frane, grab handle from SL
sl::FrameToken* currentFrame{};
if(SL_FAILED(res, slGetNewFrameToken(&currentFrame))
{
// Handle error
}
// Simulation start
if(SL_FAILED(res, slPclSetMarker(sl::PclMarker::eSimulationStart, *currentFrame)))
{
// Handle error
}
// Simulation code goes here
// Simulation end
if(SL_FAILED(res, slPclSetMarker(sl::PclMarker::eSimulationEnd, *currentFrame)))
{
// Handle error
}
// When checking for custom low latency messages inside the Windows message loop
//
if(pclState.statsWindowMessage == msgId)
{
// PCL ping based on custom message
// First scenario, using current frame
if(SL_FAILED(res, slPclSetMarker(sl::PclMarker::ePCLatencyPing, *currentFrame)))
{
// Handle error
}
// Second scenario, sending ping BEFORE simulation started, need to advance to the next frame
sl::FrameToken* nextFrame{};
auto nextIndex = *currentFrame + 1;
if(SL_FAILED(res, slGetNewFrameToken(&nextFrame, &nextIndex))
{
// Handle error
}
if(SL_FAILED(res, slPclSetMarker(sl::PclMarker::ePCLatencyPing, *nextFrame)))
{
// Handle error
}
}
```
### 4.0 MIGRATING FROM SL REFLEX
PCL markers were part of SL Reflex in earlier versions of SL. If migrating from one of those releases, the following changes will be required:
- Make sure you copy the new `sl.pcl.dll` to your build (similar to `sl.common.dll`)
- PCL has its own `slIsFeatureSupported(sl::kFeaturePCL, ...)` distinct from `sl::kFeatureReflex` (which is still required if using SL Reflex)
- `slReflexSetMarker()` helper in `sl_reflex.h` is replaced with `slPCLSetMarker()` in sl_pcl.h
- Markers in `sl::ReflexMarker` enum are now in `sl::PCLMarker` enum *class*
- Markers are no longer in top-level `sl::` namespace, use `sl::PCLMarker::`
- If you were using the implicit cast to `uint32_t`, it will now need to be explicit
- `eInputSample` marker was removed, this was already deprecated and removed in the native Reflex SDK but was never propagated to SL