NVIDIA has some cool HLSL extensions, e.g. for measuring time inside of a ray tracing shader. The HLSL-side setup and usage is simple but I don’t know if or how I can do the CPU-side setup in Unity. I tried calling NvAPI_D3D12_SetNvShaderExtnSlotSpace and NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread in a native plugin in UnityGfxDeviceEventInitialize and got NVAPI_OK but the extensions are still not working. One problem might be that Unity forces me to bind an actual ComputeBuffer or GraphicsBuffer to the fake UAV slot used by NVAPI instead of leaving it empty. I don’t know if that’s the (only) problem though, I just know that I didn’t get it working so far. NvGetSpecial(NV_SPECIALOP_GLOBAL_TIMER_LO) seems to output garbage. I’m using DirectX 12 and an RTX 4070 Ti.
I’m aware that this is a very specific question but maybe someone here has done something similar before or has more experience with native plugins or DirectX 12 than I do. I’d appreciate any help I can get.
Plugin:
#include <d3d12.h>
#include <dxgi.h>
#include <sstream>
#include "nvapi/nvapi.h"
#include "nvapi/nvapi_lite_d3dext.h"
#include "unity/IUnityInterface.h"
#include "unity/IUnityGraphics.h"
#include "unity/IUnityGraphicsD3D12.h"
#include "unity/IUnityLog.h"
const NvU32 SLOT = 3;
const NvU32 SPACE = 0;
IUnityInterfaces* unity = NULL;
IUnityGraphics* unityGraphics = NULL;
IUnityGraphicsD3D12v2* unityD3D12 = NULL;
void Log(const char* message) {
auto debug = unity->Get<IUnityLog>();
debug->Log(kUnityLogTypeLog, message, "", 0);
}
void LogNvapiStatus(const char* message, NvAPI_Status status) {
std::stringstream s;
s << message << " " << status;
Log(s.str().c_str());
}
void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType) {
NvAPI_Status status = NVAPI_OK;
switch (eventType) {
case kUnityGfxDeviceEventInitialize:
unityD3D12 = unity->Get<IUnityGraphicsD3D12v2>();
status = NvAPI_Initialize();
LogNvapiStatus("NVAPI Init", status);
status = NvAPI_D3D12_SetNvShaderExtnSlotSpace(
unityD3D12->GetDevice(), SLOT, SPACE
);
LogNvapiStatus("NVAPI Enable", status);
status = NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread(
unityD3D12->GetDevice(), SLOT, SPACE
);
LogNvapiStatus("NVAPI Enable Local Thread", status);
break;
case kUnityGfxDeviceEventShutdown:
status = NvAPI_D3D12_SetNvShaderExtnSlotSpace(
unityD3D12->GetDevice(), ~0u, 0
);
LogNvapiStatus("NVAPI Disable", status);
status = NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread(
unityD3D12->GetDevice(), ~0u, 0
);
LogNvapiStatus("NVAPI Disable Local Thread", status);
break;
};
}
extern "C"
void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(
IUnityInterfaces* unityInterfaces
) {
unity = unityInterfaces;
Log("Load");
unityGraphics = unityInterfaces->Get<IUnityGraphics>();
unityGraphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
}
extern "C"
void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload() {
Log("Unload");
unityGraphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
}
RayTracingShader:
#define NV_SHADER_EXTN_SLOT u3
#define NV_SHADER_EXTN_REGISTER_SPACE space0
#include "nvHLSLExtns.hlsl"
...
uint time = NvGetSpecial(NV_SPECIALOP_GLOBAL_TIMER_LO);