Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/jp7677/dxvk-nvapi.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Moss <amoss@nvidia.com>2021-09-27 20:47:19 +0300
committerJens Peters <jp7677@gmail.com>2021-09-27 21:30:51 +0300
commitc9eae842c5aa94d3b2871b2c4c39fb5f04401340 (patch)
tree27944f6fb808f588dcaabe617aa087e52ed883e5
parent383dc2c97c408c0bf78b6d2aeff24a37231e22fe (diff)
Implement the required NvAPI entrypoints for D3D11 DLSS support.
(To initialize DLSS successfully at runtime this also needs some corresponding DXVK changes.)
-rw-r--r--src/d3d11/nvapi_d3d11_device.cpp140
-rw-r--r--src/d3d11/nvapi_d3d11_device.h17
-rw-r--r--src/dxvk/dxvk_interfaces.cpp2
-rw-r--r--src/dxvk/dxvk_interfaces.h62
-rw-r--r--src/nvapi_d3d.cpp55
-rw-r--r--src/nvapi_d3d11.cpp159
-rw-r--r--src/nvapi_interface.cpp15
-rw-r--r--tests/nvapi_d3d.cpp34
-rw-r--r--tests/nvapi_d3d11.cpp158
-rw-r--r--tests/nvapi_d3d11_mocks.cpp11
10 files changed, 623 insertions, 30 deletions
diff --git a/src/d3d11/nvapi_d3d11_device.cpp b/src/d3d11/nvapi_d3d11_device.cpp
index c910d71..ef45972 100644
--- a/src/d3d11/nvapi_d3d11_device.cpp
+++ b/src/d3d11/nvapi_d3d11_device.cpp
@@ -46,43 +46,135 @@ namespace dxvk {
return true;
}
- Com<ID3D11VkExtContext> NvapiD3d11Device::GetSdbtDeviceContext(IUnknown* deviceOrContext) {
- std::scoped_lock lock(m_depthBoundsDeviceOrContextMutex);
- auto it = m_depthBoundsDeviceOrContextMap.find(deviceOrContext);
- if (it != m_depthBoundsDeviceOrContextMap.end())
- return it->second;
+ bool NvapiD3d11Device::CreateCubinComputeShaderWithName(ID3D11Device* pDevice, const void* pCubin, NvU32 size, NvU32 blockX, NvU32 blockY, NvU32 blockZ, const char* pShaderName, NVDX_ObjectHandle* phShader) {
+ // note - creating a cuda kernel is a one-shot thing, no need to add complexity by caching availability of the underlying extensions, we'll just let DXVK tell us if it failed.
+ Com<ID3D11VkExtDevice1> d3d11ExtDevice1;
+ if (FAILED(pDevice->QueryInterface(IID_PPV_ARGS(&d3d11ExtDevice1))))
+ return false;
- auto deviceContextExt = GetDeviceContextExt(deviceOrContext, D3D11_VK_EXT_DEPTH_BOUNDS);
- if (deviceContextExt != nullptr)
- m_depthBoundsDeviceOrContextMap.emplace(deviceOrContext, deviceContextExt.ptr());
+ return d3d11ExtDevice1->CreateCubinComputeShaderWithNameNVX(pCubin, size, blockX, blockY, blockZ, pShaderName, reinterpret_cast<IUnknown**>(phShader));
+ }
- return deviceContextExt;
+ bool NvapiD3d11Device::LaunchCubinShader(ID3D11DeviceContext* pDeviceContext, NVDX_ObjectHandle hShader, NvU32 gridX, NvU32 gridY, NvU32 gridZ, const void* pParams, NvU32 paramSize, const NVDX_ObjectHandle* pReadResources, NvU32 numReadResources, const NVDX_ObjectHandle* pWriteResources, NvU32 numWriteResources) {
+ auto binaryImportDeviceContext = GetBinaryImportDeviceContext(pDeviceContext);
+ if (binaryImportDeviceContext == nullptr)
+ return false;
+
+ return binaryImportDeviceContext->LaunchCubinShaderNVX(reinterpret_cast<IUnknown*>(hShader), gridX, gridY, gridZ, pParams, paramSize, reinterpret_cast<void* const*>(pReadResources), numReadResources, reinterpret_cast<void* const*>(pWriteResources), numWriteResources);
}
- Com<ID3D11VkExtContext> NvapiD3d11Device::GetBarrierControlDeviceContext(IUnknown* deviceOrContext) {
- std::scoped_lock lock(m_barrierControlDeviceOrContextMutex);
- auto it = m_barrierControlDeviceOrContextMap.find(deviceOrContext);
- if (it != m_barrierControlDeviceOrContextMap.end())
- return it->second;
+ bool NvapiD3d11Device::DestroyCubinShader(ID3D11Device* /*unused*/, NVDX_ObjectHandle hShader) {
+ IUnknown* cushader = reinterpret_cast<IUnknown*>(hShader);
+ if (cushader)
+ cushader->Release();
- auto deviceContextExt = GetDeviceContextExt(deviceOrContext, D3D11_VK_EXT_BARRIER_CONTROL);
- if (deviceContextExt != nullptr)
- m_barrierControlDeviceOrContextMap.emplace(deviceOrContext, deviceContextExt.ptr());
+ return cushader != nullptr;
+ }
- return deviceContextExt;
+ bool NvapiD3d11Device::GetResourceDriverHandle(ID3D11Device* /*unused*/, ID3D11Resource* pResource, NVDX_ObjectHandle* phObject) {
+ // This trivial implementation is here instead of in DXVK for performance reasons; DXVK will assume that this is a straight cast though, so if either layer has to change that assumption then they will have to be upgraded in lockstep.
+ *phObject = reinterpret_cast<NVDX_ObjectHandle>(pResource);
+ return true;
+ }
+
+ bool NvapiD3d11Device::GetResourceHandleGPUVirtualAddressAndSize(ID3D11Device* pDevice, NVDX_ObjectHandle hObject, NvU64* gpuVAStart, NvU64* gpuVASize) {
+ Com<ID3D11VkExtDevice1> d3d11ExtDevice1;
+ if (FAILED(pDevice->QueryInterface(IID_PPV_ARGS(&d3d11ExtDevice1))))
+ return false;
+
+ return d3d11ExtDevice1->GetResourceHandleGPUVirtualAddressAndSizeNVX(reinterpret_cast<void*>(hObject), reinterpret_cast<uint64_t*>(gpuVAStart), reinterpret_cast<uint64_t*>(gpuVASize));
+ }
+
+ bool NvapiD3d11Device::CreateUnorderedAccessViewAndGetDriverHandle(ID3D11Device* pDevice, ID3D11Resource* pResource, const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, ID3D11UnorderedAccessView** ppUAV, NvU32* pDriverHandle) {
+ Com<ID3D11VkExtDevice1> d3d11ExtDevice1;
+ if (FAILED(pDevice->QueryInterface(IID_PPV_ARGS(&d3d11ExtDevice1))))
+ return false;
+
+ return d3d11ExtDevice1->CreateUnorderedAccessViewAndGetDriverHandleNVX(pResource, pDesc, ppUAV, reinterpret_cast<uint32_t*>(pDriverHandle));
+ }
+
+ bool NvapiD3d11Device::CreateShaderResourceViewAndGetDriverHandle(ID3D11Device* pDevice, ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRV, NvU32* pDriverHandle) {
+ Com<ID3D11VkExtDevice1> d3d11ExtDevice1;
+ if (FAILED(pDevice->QueryInterface(IID_PPV_ARGS(&d3d11ExtDevice1))))
+ return false;
+
+ return d3d11ExtDevice1->CreateShaderResourceViewAndGetDriverHandleNVX(pResource, pDesc, ppSRV, reinterpret_cast<uint32_t*>(pDriverHandle));
+ }
+
+ bool NvapiD3d11Device::GetCudaTextureObject(ID3D11Device* pDevice, uint32_t srvDriverHandle, uint32_t samplerDriverHandle, uint32_t* pCudaTextureHandle) {
+ // note - deriving a 'cuda texture object' is typically a one-shot thing, no need to add complexity by caching availability of the underlying extensions, we'll just let DXVK tell us if it failed.
+ Com<ID3D11VkExtDevice1> d3d11ExtDevice1;
+ if (FAILED(pDevice->QueryInterface(IID_PPV_ARGS(&d3d11ExtDevice1))))
+ return false;
+
+ return d3d11ExtDevice1->GetCudaTextureObjectNVX(srvDriverHandle, samplerDriverHandle, reinterpret_cast<uint32_t*>(pCudaTextureHandle));
+ }
+
+ bool NvapiD3d11Device::CreateSamplerStateAndGetDriverHandle(ID3D11Device* pDevice, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState, uint32_t* pDriverHandle) {
+ // note - getting the driver handle for a sampler state is typically a one-shot thing, no need to add complexity by caching availability of the underlying extensions, we'll just let DXVK tell us if it failed.
+ Com<ID3D11VkExtDevice1> d3d11ExtDevice1;
+ if (FAILED(pDevice->QueryInterface(IID_PPV_ARGS(&d3d11ExtDevice1))))
+ return false;
+
+ return d3d11ExtDevice1->CreateSamplerStateAndGetDriverHandleNVX(pSamplerDesc, ppSamplerState, pDriverHandle);
+ }
+
+ bool NvapiD3d11Device::IsFatbinPTXSupported(ID3D11Device* pDevice) {
+ return (GetBinaryImportDeviceContext(pDevice) != nullptr);
+ }
+
+ Com<ID3D11VkExtContext> NvapiD3d11Device::GetSdbtDeviceContext(IUnknown* deviceOrContext) {
+ std::scoped_lock lock(m_depthBoundsDeviceOrContextMutex);
+ return CacheDxvkDeviceContext(deviceOrContext, m_depthBoundsDeviceOrContextMap, D3D11_VK_EXT_DEPTH_BOUNDS);
+ }
+
+ Com<ID3D11VkExtContext> NvapiD3d11Device::GetBarrierControlDeviceContext(IUnknown* deviceOrContext) {
+ std::scoped_lock lock(m_barrierControlDeviceOrContextMutex);
+ return CacheDxvkDeviceContext(deviceOrContext, m_barrierControlDeviceOrContextMap, D3D11_VK_EXT_BARRIER_CONTROL);
}
Com<ID3D11VkExtContext> NvapiD3d11Device::GetMultiDrawDeviceContext(ID3D11DeviceContext* deviceContext) {
std::scoped_lock lock(m_multiDrawIndirectContextMutex);
- auto it = m_multiDrawIndirectContextMap.find(deviceContext);
- if (it != m_multiDrawIndirectContextMap.end())
+ return CacheDxvkDeviceContext(deviceContext, m_multiDrawIndirectContextMap, D3D11_VK_EXT_MULTI_DRAW_INDIRECT);
+ }
+
+ Com<ID3D11VkExtContext1> NvapiD3d11Device::GetBinaryImportDeviceContext(IUnknown* deviceOrContext) {
+ std::scoped_lock lock(m_binaryImportContextMutex);
+ auto context = CacheDxvkDeviceContext(deviceOrContext, m_binaryImportContextMap, D3D11_VK_NVX_BINARY_IMPORT);
+ if (context == nullptr)
+ return nullptr;
+
+ Com<ID3D11VkExtContext1> d3d11ExtContext1;
+ if (FAILED(context->QueryInterface(IID_PPV_ARGS(&d3d11ExtContext1))))
+ return nullptr;
+
+ return d3d11ExtContext1;
+ }
+
+ Com<ID3D11VkExtContext1> NvapiD3d11Device::GetImageViewHandleDeviceContext(ID3D11DeviceContext* deviceContext) {
+ std::scoped_lock lock(m_imageViewHandleContextMutex);
+ auto context = CacheDxvkDeviceContext(deviceContext, m_imageViewHandleContextMap, D3D11_VK_NVX_IMAGE_VIEW_HANDLE);
+ if (context == nullptr)
+ return nullptr;
+
+ Com<ID3D11VkExtContext1> d3d11ExtContext1;
+ if (FAILED(context->QueryInterface(IID_PPV_ARGS(&d3d11ExtContext1))))
+ return nullptr;
+
+ return d3d11ExtContext1;
+ }
+
+ Com<ID3D11VkExtContext> NvapiD3d11Device::CacheDxvkDeviceContext(IUnknown* deviceOrContext, std::unordered_map<IUnknown*, ID3D11VkExtContext*>& cacheMap, D3D11_VK_EXTENSION extension) {
+ auto it = cacheMap.find(deviceOrContext);
+ if (it != cacheMap.end())
return it->second;
- auto deviceContextExt = GetDeviceContextExt(deviceContext, D3D11_VK_EXT_MULTI_DRAW_INDIRECT);
- if (deviceContextExt != nullptr)
- m_multiDrawIndirectContextMap.emplace(deviceContext, deviceContextExt.ptr());
+ auto dxvkDeviceContext = GetDeviceContextExt(deviceOrContext, extension);
+ /* it could be beneficial to cache nullptrs, but it confuses the tests */
+ if (dxvkDeviceContext != nullptr)
+ cacheMap.emplace(deviceOrContext, dxvkDeviceContext.ptr());
- return deviceContextExt;
+ return dxvkDeviceContext;
}
Com<ID3D11VkExtContext> NvapiD3d11Device::GetDeviceContextExt(IUnknown* deviceOrContext, D3D11_VK_EXTENSION extension) {
diff --git a/src/d3d11/nvapi_d3d11_device.h b/src/d3d11/nvapi_d3d11_device.h
index ebe687b..57b3119 100644
--- a/src/d3d11/nvapi_d3d11_device.h
+++ b/src/d3d11/nvapi_d3d11_device.h
@@ -13,19 +13,36 @@ namespace dxvk {
static bool EndUAVOverlap(IUnknown* deviceOrContext);
static bool MultiDrawInstancedIndirect(ID3D11DeviceContext* deviceContext, NvU32 drawCount, ID3D11Buffer* buffer, NvU32 alignedByteOffsetForArgs, NvU32 alignedByteStrideForArgs);
static bool MultiDrawIndexedInstancedIndirect(ID3D11DeviceContext* deviceContext, NvU32 drawCount, ID3D11Buffer* buffer, NvU32 alignedByteOffsetForArgs, NvU32 alignedByteStrideForArgs);
+ static bool CreateCubinComputeShaderWithName(ID3D11Device* pDevice, const void* pCubin, NvU32 size, NvU32 blockX, NvU32 blockY, NvU32 blockZ, const char* pShaderName, NVDX_ObjectHandle* phShader);
+ static bool LaunchCubinShader(ID3D11DeviceContext* pDeviceContext, NVDX_ObjectHandle hShader, NvU32 gridX, NvU32 gridY, NvU32 gridZ, const void* pParams, NvU32 paramSize, const NVDX_ObjectHandle* pReadResources, NvU32 numReadResources, const NVDX_ObjectHandle* pWriteResources, NvU32 numWriteResources);
+ static bool DestroyCubinShader(ID3D11Device* pDevice, NVDX_ObjectHandle hShader);
+ static bool GetResourceDriverHandle(ID3D11Device* pDevice, ID3D11Resource* pResource, NVDX_ObjectHandle* phObject);
+ static bool GetResourceHandleGPUVirtualAddressAndSize(ID3D11Device* pDevice, NVDX_ObjectHandle hObject, NvU64* gpuVAStart, NvU64* gpuVASize);
+ static bool CreateUnorderedAccessViewAndGetDriverHandle(ID3D11Device* pDevice, ID3D11Resource* pResource, const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, ID3D11UnorderedAccessView** ppUAV, NvU32* pDriverHandle);
+ static bool CreateShaderResourceViewAndGetDriverHandle(ID3D11Device* pDevice, ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRV, NvU32* pDriverHandle);
+ static bool GetCudaTextureObject(ID3D11Device* pDevice, uint32_t srvDriverHandle, uint32_t samplerDriverHandle, uint32_t* pCudaTextureHandle);
+ static bool CreateSamplerStateAndGetDriverHandle(ID3D11Device* pDevice, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState, uint32_t* pDriverHandle);
+ static bool IsFatbinPTXSupported(ID3D11Device* pDevice);
private:
inline static std::unordered_map<IUnknown*, ID3D11VkExtContext*> m_depthBoundsDeviceOrContextMap;
inline static std::unordered_map<IUnknown*, ID3D11VkExtContext*> m_barrierControlDeviceOrContextMap;
inline static std::unordered_map<IUnknown*, ID3D11VkExtContext*> m_multiDrawIndirectContextMap;
+ inline static std::unordered_map<IUnknown*, ID3D11VkExtContext*> m_binaryImportContextMap;
+ inline static std::unordered_map<IUnknown*, ID3D11VkExtContext*> m_imageViewHandleContextMap;
inline static std::mutex m_depthBoundsDeviceOrContextMutex;
inline static std::mutex m_barrierControlDeviceOrContextMutex;
inline static std::mutex m_multiDrawIndirectContextMutex;
+ inline static std::mutex m_binaryImportContextMutex;
+ inline static std::mutex m_imageViewHandleContextMutex;
[[nodiscard]] static Com<ID3D11VkExtContext> GetSdbtDeviceContext(IUnknown* deviceOrContext);
[[nodiscard]] static Com<ID3D11VkExtContext> GetBarrierControlDeviceContext(IUnknown* deviceOrContext);
[[nodiscard]] static Com<ID3D11VkExtContext> GetMultiDrawDeviceContext(ID3D11DeviceContext* deviceContext);
+ [[nodiscard]] static Com<ID3D11VkExtContext1> GetBinaryImportDeviceContext(IUnknown* deviceOrContext);
+ [[nodiscard]] static Com<ID3D11VkExtContext1> GetImageViewHandleDeviceContext(ID3D11DeviceContext* deviceContext);
+ [[nodiscard]] static Com<ID3D11VkExtContext> CacheDxvkDeviceContext(IUnknown* deviceOrContext, std::unordered_map<IUnknown*, ID3D11VkExtContext*>& cacheMap, D3D11_VK_EXTENSION extension);
[[nodiscard]] static Com<ID3D11VkExtContext> GetDeviceContextExt(IUnknown* deviceOrContext, D3D11_VK_EXTENSION extension);
[[nodiscard]] static Com<ID3D11VkExtContext> GetDeviceContextExt(ID3D11DeviceContext* deviceContext, D3D11_VK_EXTENSION extension);
[[nodiscard]] static Com<ID3D11VkExtContext> GetDeviceContextExt(ID3D11Device* device, ID3D11DeviceContext* deviceContext, D3D11_VK_EXTENSION extension);
diff --git a/src/dxvk/dxvk_interfaces.cpp b/src/dxvk/dxvk_interfaces.cpp
index be4e68b..e4e5cf9 100644
--- a/src/dxvk/dxvk_interfaces.cpp
+++ b/src/dxvk/dxvk_interfaces.cpp
@@ -2,4 +2,6 @@
const GUID IDXGIVkInteropAdapter::guid = {0x3a6d8f2c,0xb0e8,0x4ab4,{0xb4,0xdc,0x4f,0xd2,0x48,0x91,0xbf,0xa5}};
const GUID ID3D11VkExtDevice::guid = {0x8a6e3c42,0xf74c,0x45b7,{0x82,0x65,0xa2,0x31,0xb6,0x77,0xca,0x17}};
+const GUID ID3D11VkExtDevice1::guid = {0xcfcf64ef,0x9586,0x46d0,{0xbc,0xa4,0x97,0xcf,0x2c,0xa6,0x1b,0x06}};
const GUID ID3D11VkExtContext::guid = {0xfd0bca13,0x5cb6,0x4c3a,{0x98,0x7e,0x47,0x50,0xde,0x2c,0xa7,0x91}};
+const GUID ID3D11VkExtContext1::guid = {0x874b09b2,0xae0b,0x41d8,{0x84,0x76,0x5f,0x3b,0x7a,0x0e,0x87,0x9d}};
diff --git a/src/dxvk/dxvk_interfaces.h b/src/dxvk/dxvk_interfaces.h
index 6a73caf..9a49516 100644
--- a/src/dxvk/dxvk_interfaces.h
+++ b/src/dxvk/dxvk_interfaces.h
@@ -14,6 +14,8 @@ enum D3D11_VK_EXTENSION : uint32_t {
D3D11_VK_EXT_MULTI_DRAW_INDIRECT_COUNT = 1,
D3D11_VK_EXT_DEPTH_BOUNDS = 2,
D3D11_VK_EXT_BARRIER_CONTROL = 3,
+ D3D11_VK_NVX_BINARY_IMPORT = 4,
+ D3D11_VK_NVX_IMAGE_VIEW_HANDLE = 5,
};
enum D3D11_VK_BARRIER_CONTROL : uint32_t {
@@ -55,6 +57,47 @@ ID3D11VkExtDevice : public IUnknown {
D3D11_VK_EXTENSION Extension) = 0;
};
+MIDL_INTERFACE("cfcf64ef-9586-46d0-bca4-97cf2ca61b06")
+ID3D11VkExtDevice1 : public ID3D11VkExtDevice {
+ static const GUID guid;
+
+ virtual bool STDMETHODCALLTYPE GetResourceHandleGPUVirtualAddressAndSizeNVX(
+ void* hObject,
+ uint64_t* gpuVAStart,
+ uint64_t* gpuVASize) = 0;
+
+ virtual bool STDMETHODCALLTYPE CreateUnorderedAccessViewAndGetDriverHandleNVX(
+ ID3D11Resource* pResource,
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
+ ID3D11UnorderedAccessView** ppUAV,
+ uint32_t* pDriverHandle) = 0;
+
+ virtual bool STDMETHODCALLTYPE CreateShaderResourceViewAndGetDriverHandleNVX(
+ ID3D11Resource* pResource,
+ const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
+ ID3D11ShaderResourceView** ppSRV,
+ uint32_t* pDriverHandle) = 0;
+
+ virtual bool STDMETHODCALLTYPE CreateSamplerStateAndGetDriverHandleNVX(
+ const D3D11_SAMPLER_DESC* pSamplerDesc,
+ ID3D11SamplerState** ppSamplerState,
+ uint32_t* pDriverHandle) = 0;
+
+ virtual bool STDMETHODCALLTYPE CreateCubinComputeShaderWithNameNVX(
+ const void* pCubin,
+ uint32_t size,
+ uint32_t blockX,
+ uint32_t blockY,
+ uint32_t blockZ,
+ const char* pShaderName,
+ IUnknown** phShader) = 0;
+
+ virtual bool STDMETHODCALLTYPE GetCudaTextureObjectNVX(
+ uint32_t srvDriverHandle,
+ uint32_t samplerDriverHandle,
+ uint32_t* pCudaTextureHandle) = 0;
+};
+
MIDL_INTERFACE("fd0bca13-5cb6-4c3a-987e-4750de2ca791")
ID3D11VkExtContext : public IUnknown {
static const GUID guid;
@@ -96,6 +139,25 @@ ID3D11VkExtContext : public IUnknown {
UINT ControlFlags) = 0;
};
+MIDL_INTERFACE("874b09b2-ae0b-41d8-8476-5f3b7a0e879d")
+ID3D11VkExtContext1 : public ID3D11VkExtContext {
+ static const GUID guid;
+
+ virtual bool STDMETHODCALLTYPE LaunchCubinShaderNVX(
+ IUnknown* hShader,
+ uint32_t gridX,
+ uint32_t gridY,
+ uint32_t gridZ,
+ const void* pParams,
+ uint32_t paramSize,
+ void* const* pReadResources,
+ uint32_t numReadResources,
+ void* const* pWriteResources,
+ uint32_t numWriteResources) = 0;
+};
+
DXVK_DEFINE_GUID(IDXGIVkInteropAdapter)
DXVK_DEFINE_GUID(ID3D11VkExtDevice)
+DXVK_DEFINE_GUID(ID3D11VkExtDevice1)
DXVK_DEFINE_GUID(ID3D11VkExtContext)
+DXVK_DEFINE_GUID(ID3D11VkExtContext1)
diff --git a/src/nvapi_d3d.cpp b/src/nvapi_d3d.cpp
index fdfcb6d..3d8bdfc 100644
--- a/src/nvapi_d3d.cpp
+++ b/src/nvapi_d3d.cpp
@@ -6,7 +6,10 @@ extern "C" {
NvAPI_Status __cdecl NvAPI_D3D_GetObjectHandleForResource(IUnknown *pDevice, IUnknown *pResource, NVDX_ObjectHandle *pHandle) {
static bool alreadyLogged = false;
- return NoImplementation("NvAPI_D3D_GetObjectHandleForResource", alreadyLogged);
+ // Fake-implement with a dumb passthrough, though no other NvAPI entry points
+ // we're likely to implement should care about the actual handle value.
+ *pHandle = (NVDX_ObjectHandle)pResource;
+ return Ok("NvAPI_D3D_GetObjectHandleForResource", alreadyLogged);
}
NvAPI_Status __cdecl NvAPI_D3D_SetResourceHint(IUnknown *pDev, NVDX_ObjectHandle obj, NVAPI_D3D_SETRESOURCEHINT_CATEGORY dwHintCategory, NvU32 dwHintName, NvU32 *pdwHintValue) {
@@ -14,8 +17,20 @@ extern "C" {
return NoImplementation("NvAPI_D3D_SetResourceHint", alreadyLogged);
}
+ NvAPI_Status __cdecl NvAPI_D3D_BeginResourceRendering(IUnknown *pDeviceOrContext, NVDX_ObjectHandle obj, NvU32 Flags) {
+ static bool alreadyLogged = false;
+ // Synchronisation hints for SLI...
+ return Ok("NvAPI_D3D_BeginResourceRendering", alreadyLogged);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D_EndResourceRendering(IUnknown *pDeviceOrContext, NVDX_ObjectHandle obj, NvU32 Flags) {
+ static bool alreadyLogged = false;
+ return Ok("NvAPI_D3D_EndResourceRendering", alreadyLogged);
+ }
+
NvAPI_Status __cdecl NvAPI_D3D_GetCurrentSLIState(IUnknown *pDevice, NV_GET_CURRENT_SLI_STATE *pSliState) {
constexpr auto n = "NvAPI_D3D_GetCurrentSLIState";
+ static bool alreadyLoggedOk = false;
if (pDevice == nullptr || pSliState == nullptr)
return InvalidArgument(n);
@@ -34,6 +49,42 @@ extern "C" {
if (pSliState->version == NV_GET_CURRENT_SLI_STATE_VER2)
pSliState->numVRSLIGpus = 0;
- return Ok(n);
+ return Ok(n, alreadyLoggedOk);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D1x_GetGraphicsCapabilities(IUnknown *pDevice,
+ NvU32 structVersion,
+ NV_D3D1x_GRAPHICS_CAPS *pGraphicsCaps) {
+ constexpr auto n = "NvAPI_D3D1x_GetGraphicsCapabilities";
+ static bool alreadyLoggedOk = false;
+
+ switch(structVersion) {
+ case NV_D3D1x_GRAPHICS_CAPS_VER1:
+ memset(pGraphicsCaps, 0, sizeof(NV_D3D1x_GRAPHICS_CAPS_V1));
+ break;
+ case NV_D3D1x_GRAPHICS_CAPS_VER2:
+ memset(pGraphicsCaps, 0, sizeof(NV_D3D1x_GRAPHICS_CAPS_V2));
+ break;
+ default:
+ return IncompatibleStructVersion(n);
+ }
+
+ switch(structVersion) {
+ case NV_D3D1x_GRAPHICS_CAPS_VER2:
+ // bFastUAVClearSupported is reported mostly for the sake of DLSS.
+ // All NVIDIA Vulkan drivers support this.
+ (*reinterpret_cast<NV_D3D1x_GRAPHICS_CAPS_V2*>(pGraphicsCaps)).bFastUAVClearSupported = 1;
+ // dummy SM version number (unused by DLSS):
+ (*reinterpret_cast<NV_D3D1x_GRAPHICS_CAPS_V2*>(pGraphicsCaps)).majorSMVersion = 0;
+ (*reinterpret_cast<NV_D3D1x_GRAPHICS_CAPS_V2*>(pGraphicsCaps)).minorSMVersion = 0;
+
+ [[fallthrough]];
+
+ case NV_D3D1x_GRAPHICS_CAPS_VER1:
+ (*reinterpret_cast<NV_D3D1x_GRAPHICS_CAPS_V1*>(pGraphicsCaps)).bExclusiveScissorRectsSupported = 0;
+ (*reinterpret_cast<NV_D3D1x_GRAPHICS_CAPS_V1*>(pGraphicsCaps)).bVariablePixelRateShadingSupported = 0;
+ }
+
+ return Ok(n, alreadyLoggedOk);
}
}
diff --git a/src/nvapi_d3d11.cpp b/src/nvapi_d3d11.cpp
index 467aa62..c0a22e1 100644
--- a/src/nvapi_d3d11.cpp
+++ b/src/nvapi_d3d11.cpp
@@ -88,4 +88,163 @@ extern "C" {
return Ok(str::format(n, " ", code, " (", fromCode(code), ")"));
}
+
+ NvAPI_Status __cdecl NvAPI_D3D11_CreateCubinComputeShader(ID3D11Device* pDevice, const void* pCubin, NvU32 size, NvU32 blockX, NvU32 blockY, NvU32 blockZ, NVDX_ObjectHandle* phShader) {
+ constexpr auto n = "NvAPI_D3D11_CreateCubinComputeShader";
+
+ if (pDevice == nullptr || pCubin == nullptr || phShader == nullptr)
+ return InvalidArgument(n);
+
+ if (!NvapiD3d11Device::CreateCubinComputeShaderWithName(pDevice, pCubin, size, blockX, blockY, blockZ, nullptr, phShader))
+ return Error(n);
+
+ return Ok(n);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_CreateCubinComputeShaderWithName(ID3D11Device* pDevice, const void* pCubin, NvU32 size, NvU32 blockX, NvU32 blockY, NvU32 blockZ, const char* pShaderName, NVDX_ObjectHandle* phShader) {
+ constexpr auto n = "NvAPI_D3D11_CreateCubinComputeShaderWithName";
+
+ if (pDevice == nullptr || pCubin == nullptr || phShader == nullptr)
+ return InvalidArgument(n);
+
+ if (!NvapiD3d11Device::CreateCubinComputeShaderWithName(pDevice, pCubin, size, blockX, blockY, blockZ, pShaderName, phShader))
+ return Error(n);
+
+ return Ok(n);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_LaunchCubinShader(ID3D11DeviceContext* pDeviceContext, NVDX_ObjectHandle hShader, NvU32 gridX, NvU32 gridY, NvU32 gridZ, const void* pParams, NvU32 paramSize, const NVDX_ObjectHandle* pReadResources, NvU32 numReadResources, const NVDX_ObjectHandle* pWriteResources, NvU32 numWriteResources) {
+ constexpr auto n = "NvAPI_D3D11_LaunchCubinShader";
+ static bool alreadyLoggedError = false;
+ static bool alreadyLoggedOk = false;
+
+ if (pDeviceContext == nullptr)
+ return InvalidArgument(n);
+
+ if (!NvapiD3d11Device::LaunchCubinShader(pDeviceContext, hShader, gridX, gridY, gridZ, pParams, paramSize, pReadResources, numReadResources, pWriteResources, numWriteResources))
+ return Error(n, alreadyLoggedError);
+
+ return Ok(n, alreadyLoggedOk);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_DestroyCubinComputeShader(ID3D11Device* pDevice, NVDX_ObjectHandle hShader) {
+ constexpr auto n = "NvAPI_D3D11_DestroyCubinComputeShader";
+
+ if (pDevice == nullptr)
+ return InvalidArgument(n);
+
+ if (!NvapiD3d11Device::DestroyCubinShader(pDevice, hShader))
+ return Error(n);
+
+ return Ok(n);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_IsFatbinPTXSupported(ID3D11Device* pDevice, bool* pSupported) {
+ constexpr auto n = "NvAPI_D3D11_IsFatbinPTXSupported";
+ static bool alreadyLoggedOk = false;
+
+ if (pDevice == nullptr || pSupported == nullptr)
+ return InvalidArgument(n);
+
+ *pSupported = NvapiD3d11Device::IsFatbinPTXSupported(pDevice);
+
+ return Ok(n, alreadyLoggedOk);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_CreateUnorderedAccessView(ID3D11Device* pDevice, ID3D11Resource* pResource, const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, ID3D11UnorderedAccessView** ppUAV, NvU32* pDriverHandle) {
+ constexpr auto n = "NvAPI_D3D11_CreateUnorderedAccessView";
+
+ if (pDevice == nullptr || pResource == nullptr || pDesc == nullptr || ppUAV == nullptr || pDriverHandle == nullptr)
+ return InvalidArgument(n);
+
+ if (!NvapiD3d11Device::CreateUnorderedAccessViewAndGetDriverHandle(pDevice, pResource, pDesc, ppUAV, pDriverHandle))
+ return Error(n);
+
+ return Ok(n);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_CreateShaderResourceView(ID3D11Device* pDevice, ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRV, NvU32* pDriverHandle) {
+ constexpr auto n = "NvAPI_D3D11_CreateShaderResourceView";
+
+ if (pDevice == nullptr || pResource == nullptr || pDesc == nullptr || ppSRV == nullptr || pDriverHandle == nullptr)
+ return InvalidArgument(n);
+
+ if (!NvapiD3d11Device::CreateShaderResourceViewAndGetDriverHandle(pDevice, pResource, pDesc, ppSRV, pDriverHandle))
+ return Error(n);
+
+ return Ok(n);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_GetResourceHandle(ID3D11Device* pDevice, ID3D11Resource* pResource, NVDX_ObjectHandle* phObject) {
+ constexpr auto n = "NvAPI_D3D11_GetResourceHandle";
+ static bool alreadyLoggedOk = false;
+ static bool alreadyLoggedError = false;
+
+ if (pDevice == nullptr || pResource == nullptr || phObject == nullptr)
+ return InvalidArgument(n);
+
+ if (!NvapiD3d11Device::GetResourceDriverHandle(pDevice, pResource, phObject))
+ return Error(n, alreadyLoggedError);
+
+ return Ok(n, alreadyLoggedOk);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_GetResourceGPUVirtualAddress(ID3D11Device* pDevice, const NVDX_ObjectHandle hResource, NvU64* pGpuVA) {
+ constexpr auto n = "NvAPI_D3D11_GetResourceGPUVirtualAddress";
+ static bool alreadyLoggedOk = false;
+ static bool alreadyLoggedError = false;
+
+ if (pDevice == nullptr || hResource == NVDX_OBJECT_NONE || pGpuVA == nullptr)
+ return InvalidArgument(n);
+
+ NvU64 dummy;
+ if (!NvapiD3d11Device::GetResourceHandleGPUVirtualAddressAndSize(pDevice, hResource, pGpuVA, &dummy))
+ return Error(n, alreadyLoggedError);
+
+ return Ok(n, alreadyLoggedOk);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_GetResourceGPUVirtualAddressEx(ID3D11Device* pDevice, NV_GET_GPU_VIRTUAL_ADDRESS* pParams) {
+ constexpr auto n = "NvAPI_D3D11_GetResourceGPUVirtualAddressEx";
+ static bool alreadyLoggedOk = false;
+ static bool alreadyLoggedError = false;
+
+ if (pDevice == nullptr || pParams == nullptr)
+ return InvalidArgument(n);
+
+ if (pParams->version != NV_GET_GPU_VIRTUAL_ADDRESS_VER1)
+ return IncompatibleStructVersion(n);
+
+ if (pParams->hResource == NVDX_OBJECT_NONE)
+ return InvalidArgument(n);
+
+ if (!NvapiD3d11Device::GetResourceHandleGPUVirtualAddressAndSize(pDevice, pParams->hResource, &pParams->gpuVAStart, &pParams->gpuVASize))
+ return Error(n, alreadyLoggedError);
+
+ return Ok(n, alreadyLoggedOk);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_CreateSamplerState(ID3D11Device* pDevice, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState, NvU32* pDriverHandle) {
+ constexpr auto n = "NvAPI_D3D11_CreateSamplerState";
+
+ if (pDevice == nullptr || pSamplerDesc == nullptr || ppSamplerState == nullptr || pDriverHandle == nullptr)
+ return InvalidArgument(n);
+
+ if (!NvapiD3d11Device::CreateSamplerStateAndGetDriverHandle(pDevice, pSamplerDesc, ppSamplerState, reinterpret_cast<uint32_t*>(pDriverHandle)))
+ return Error(n);
+
+ return Ok(n);
+ }
+
+ NvAPI_Status __cdecl NvAPI_D3D11_GetCudaTextureObject(ID3D11Device* pDevice, NvU32 srvDriverHandle, NvU32 samplerDriverHandle, NvU32* pCudaTextureHandle) {
+ constexpr auto n = "NvAPI_D3D11_GetCudaTextureObject";
+
+ if (pDevice == nullptr)
+ return InvalidArgument(n);
+
+ if (!NvapiD3d11Device::GetCudaTextureObject(pDevice, srvDriverHandle, samplerDriverHandle, reinterpret_cast<uint32_t*>(pCudaTextureHandle)))
+ return Error(n);
+
+ return Ok(n);
+ }
}
diff --git a/src/nvapi_interface.cpp b/src/nvapi_interface.cpp
index 4a1eea5..723d31a 100644
--- a/src/nvapi_interface.cpp
+++ b/src/nvapi_interface.cpp
@@ -42,6 +42,19 @@ extern "C" {
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_MultiDrawInstancedIndirect)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_MultiDrawIndexedInstancedIndirect)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_IsNvShaderExtnOpCodeSupported)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_CreateCubinComputeShader)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_CreateCubinComputeShaderWithName)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_LaunchCubinShader)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_DestroyCubinComputeShader)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_IsFatbinPTXSupported)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_CreateUnorderedAccessView)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_CreateSamplerState)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_GetCudaTextureObject)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_CreateShaderResourceView)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_GetResourceHandle)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_GetResourceGPUVirtualAddress)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_GetResourceGPUVirtualAddressEx)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D1x_GetGraphicsCapabilities)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_IsNvShaderExtnOpCodeSupported)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_CreateCubinComputeShaderWithName)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_CreateCubinComputeShader)
@@ -55,6 +68,8 @@ extern "C" {
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_GetObjectHandleForResource)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetResourceHint)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_GetCurrentSLIState)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_BeginResourceRendering)
+ INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_EndResourceRendering)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetGPUType)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetPCIIdentifiers)
INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetFullName)
diff --git a/tests/nvapi_d3d.cpp b/tests/nvapi_d3d.cpp
index cdf4850..04c4c29 100644
--- a/tests/nvapi_d3d.cpp
+++ b/tests/nvapi_d3d.cpp
@@ -16,9 +16,9 @@ class UnknownMock : public mock_interface<IUnknown> {
TEST_CASE("D3D methods succeed", "[.d3d]") {
UnknownMock unknown;
- SECTION("GetObjectHandleForResource returns no-implementation") {
+ SECTION("GetObjectHandleForResource returns OK") {
NVDX_ObjectHandle handle;
- REQUIRE(NvAPI_D3D_GetObjectHandleForResource(&unknown, &unknown, &handle) == NVAPI_NO_IMPLEMENTATION);
+ REQUIRE(NvAPI_D3D_GetObjectHandleForResource(&unknown, &unknown, &handle) == NVAPI_OK);
}
SECTION("GetObjectHandleForResource returns no-implementation") {
@@ -26,6 +26,18 @@ TEST_CASE("D3D methods succeed", "[.d3d]") {
REQUIRE(NvAPI_D3D_SetResourceHint(&unknown, NVDX_ObjectHandle(), NVAPI_D3D_SRH_CATEGORY_SLI, 1, &value) == NVAPI_NO_IMPLEMENTATION);
}
+ SECTION("SetResourceHint returns NoImplementation") {
+ REQUIRE(NvAPI_D3D_SetResourceHint(&unknown, NVDX_ObjectHandle(), NVAPI_D3D_SRH_CATEGORY_SLI, 0, nullptr) == NVAPI_NO_IMPLEMENTATION);
+ }
+
+ SECTION("BeginResourceRendering returns OK") {
+ REQUIRE(NvAPI_D3D_BeginResourceRendering(&unknown, NVDX_ObjectHandle(), 0) == NVAPI_OK);
+ }
+
+ SECTION("BeginResourceRendering returns OK") {
+ REQUIRE(NvAPI_D3D_EndResourceRendering(&unknown, NVDX_ObjectHandle(), 0) == NVAPI_OK);
+ }
+
SECTION("GetCurrentSLIState returns OK") {
NV_GET_CURRENT_SLI_STATE state;
state.version = NV_GET_CURRENT_SLI_STATE_VER2;
@@ -38,4 +50,22 @@ TEST_CASE("D3D methods succeed", "[.d3d]") {
REQUIRE(state.bIsCurAFRGroupNew == false);
REQUIRE(state.numVRSLIGpus == 0);
}
+
+ SECTION("GetGraphicsCapabilities (V1) returns OK") {
+ NV_D3D1x_GRAPHICS_CAPS_V1 caps;
+ REQUIRE(NvAPI_D3D1x_GetGraphicsCapabilities(&unknown, NV_D3D1x_GRAPHICS_CAPS_VER1, reinterpret_cast<NV_D3D1x_GRAPHICS_CAPS*>(&caps)) == NVAPI_OK);
+ // returned bExclusiveScissorRectsSupported/bVariablePixelRateShadingSupported values not enforced by testing
+ }
+
+ SECTION("GetGraphicsCapabilities (V2) returns OK") {
+ NV_D3D1x_GRAPHICS_CAPS_V2 caps;
+ REQUIRE(NvAPI_D3D1x_GetGraphicsCapabilities(&unknown, NV_D3D1x_GRAPHICS_CAPS_VER2, reinterpret_cast<NV_D3D1x_GRAPHICS_CAPS*>(&caps)) == NVAPI_OK);
+ REQUIRE(caps.bFastUAVClearSupported == 1);
+ // returned minorSMVersion/majorSMVersion not enforced by testing since current returns are dummy values anyway
+ }
+
+ SECTION("GetGraphicsCapabilities (FUTURE VERSION) returns IncompatibleStructVersion") {
+ NV_D3D1x_GRAPHICS_CAPS caps;
+ REQUIRE(NvAPI_D3D1x_GetGraphicsCapabilities(&unknown, NV_D3D1x_GRAPHICS_CAPS_VER+1, reinterpret_cast<NV_D3D1x_GRAPHICS_CAPS*>(&caps)) == NVAPI_INCOMPATIBLE_STRUCT_VERSION);
+ }
}
diff --git a/tests/nvapi_d3d11.cpp b/tests/nvapi_d3d11.cpp
index 6115971..fe76783 100644
--- a/tests/nvapi_d3d11.cpp
+++ b/tests/nvapi_d3d11.cpp
@@ -7,6 +7,12 @@
using namespace trompeloeil;
+class UnknownMock : public mock_interface<IUnknown> {
+ MAKE_MOCK2 (QueryInterface, HRESULT(REFIID, void * *), override);
+ MAKE_MOCK0 (AddRef, ULONG(), override);
+ MAKE_MOCK0 (Release, ULONG(), override);
+};
+
TEST_CASE("D3D11 methods succeed", "[.d3d11]") {
D3D11DxvkDeviceMock device;
D3D11DxvkDeviceContextMock context;
@@ -21,6 +27,10 @@ TEST_CASE("D3D11 methods succeed", "[.d3d11]") {
.LR_SIDE_EFFECT(*_2 = static_cast<ID3D11VkExtDevice*>(&device))
.LR_SIDE_EFFECT(deviceRefCount++)
.RETURN(S_OK);
+ ALLOW_CALL(device, QueryInterface(ID3D11VkExtDevice1::guid, _))
+ .LR_SIDE_EFFECT(*_2 = static_cast<ID3D11VkExtDevice1*>(&device))
+ .LR_SIDE_EFFECT(deviceRefCount++)
+ .RETURN(S_OK);
ALLOW_CALL(device, AddRef())
.LR_SIDE_EFFECT(deviceRefCount++)
.RETURN(deviceRefCount);
@@ -43,6 +53,10 @@ TEST_CASE("D3D11 methods succeed", "[.d3d11]") {
.LR_SIDE_EFFECT(*_2 = static_cast<ID3D11VkExtContext*>(&context))
.LR_SIDE_EFFECT(contextRefCount++)
.RETURN(S_OK);
+ ALLOW_CALL(context, QueryInterface(ID3D11VkExtContext1::guid, _))
+ .LR_SIDE_EFFECT(*_2 = static_cast<ID3D11VkExtContext1*>(&context))
+ .LR_SIDE_EFFECT(contextRefCount++)
+ .RETURN(S_OK);
ALLOW_CALL(context, AddRef())
.LR_SIDE_EFFECT(contextRefCount++)
.RETURN(contextRefCount);
@@ -56,8 +70,12 @@ TEST_CASE("D3D11 methods succeed", "[.d3d11]") {
SECTION("D3D11 methods without DXVK return error") {
ALLOW_CALL(device, QueryInterface(ID3D11VkExtDevice::guid, _))
.RETURN(E_NOINTERFACE);
+ ALLOW_CALL(device, QueryInterface(ID3D11VkExtDevice1::guid, _))
+ .RETURN(E_NOINTERFACE);
ALLOW_CALL(context, QueryInterface(ID3D11VkExtContext::guid, _))
.RETURN(E_NOINTERFACE);
+ ALLOW_CALL(context, QueryInterface(ID3D11VkExtContext1::guid, _))
+ .RETURN(E_NOINTERFACE);
FORBID_CALL(context, SetDepthBoundsTest(_, _, _));
FORBID_CALL(context, SetBarrierControl(_));
FORBID_CALL(context, MultiDrawIndirect(_, _, _, _));
@@ -113,6 +131,95 @@ TEST_CASE("D3D11 methods succeed", "[.d3d11]") {
REQUIRE(contextRefCount == 0);
}
+ SECTION("LaunchCubinShader without DXVK extension support returns error") {
+ ALLOW_CALL(device, GetExtensionSupport(D3D11_VK_NVX_BINARY_IMPORT))
+ .RETURN(false);
+ FORBID_CALL(context, LaunchCubinShaderNVX(_, _, _, _, _, _, _, _, _, _));
+
+ REQUIRE(NvAPI_D3D11_LaunchCubinShader(static_cast<ID3D11DeviceContext*>(&context), NVDX_ObjectHandle(), 0,0,0, nullptr, 0, nullptr, 0, nullptr, 0) == NVAPI_ERROR);
+ REQUIRE(deviceRefCount == 0);
+ REQUIRE(contextRefCount == 0);
+ }
+
+ SECTION("Failing CreateCubinComputeShader/CreateCubinComputeShaderWithName inside DXVK returns error") {
+ ALLOW_CALL(device, CreateCubinComputeShaderWithNameNVX(_, _, _, _, _, _, _))
+ .RETURN(false);
+
+ NVDX_ObjectHandle objhandle;
+ REQUIRE(NvAPI_D3D11_CreateCubinComputeShaderWithName(static_cast<ID3D11Device*>(&device), "X", 1U, 0U,0U,0U, "foo", &objhandle) == NVAPI_ERROR);
+ REQUIRE(NvAPI_D3D11_CreateCubinComputeShader(static_cast<ID3D11Device*>(&device), "X", 1U, 0U,0U,0U, &objhandle) == NVAPI_ERROR);
+ REQUIRE(deviceRefCount == 0);
+ REQUIRE(contextRefCount == 0);
+ }
+
+ SECTION("LaunchCubinShader/CreateCubinComputeShader/CreateCubinComputeShaderWithName without extended DXVK interface returns error") {
+ ALLOW_CALL(device, QueryInterface(ID3D11VkExtDevice1::guid, _))
+ .RETURN(E_NOINTERFACE);
+ ALLOW_CALL(context, QueryInterface(ID3D11VkExtContext1::guid, _))
+ .RETURN(E_NOINTERFACE);
+ FORBID_CALL(context, LaunchCubinShaderNVX(_, _, _, _, _, _, _, _, _, _));
+ FORBID_CALL(device, CreateCubinComputeShaderWithNameNVX(_, _, _, _, _, _, _));
+
+ REQUIRE(NvAPI_D3D11_LaunchCubinShader(static_cast<ID3D11DeviceContext*>(&context), NVDX_ObjectHandle(), 0,0,0, nullptr, 0, nullptr, 0, nullptr, 0) == NVAPI_ERROR);
+ NVDX_ObjectHandle objhandle;
+ REQUIRE(NvAPI_D3D11_CreateCubinComputeShaderWithName(static_cast<ID3D11Device*>(&device), "X", 1U, 0U,0U,0U, "foo", &objhandle) == NVAPI_ERROR);
+ REQUIRE(NvAPI_D3D11_CreateCubinComputeShader(static_cast<ID3D11Device*>(&device), "X", 1U, 0U,0U,0U, &objhandle) == NVAPI_ERROR);
+ REQUIRE(deviceRefCount == 0);
+ REQUIRE(contextRefCount == 0);
+ }
+
+ SECTION("IsFatbinPTXSupported without DXVK extension succeeds but reports unsupported") {
+ ALLOW_CALL(device, GetExtensionSupport(D3D11_VK_NVX_BINARY_IMPORT))
+ .RETURN(false);
+
+ bool sup = true;
+ REQUIRE(NvAPI_D3D11_IsFatbinPTXSupported(static_cast<ID3D11Device*>(&device), &sup) == NVAPI_OK);
+ REQUIRE(sup == false);
+ REQUIRE(deviceRefCount == 0);
+ }
+
+ SECTION("IsFatbinPTXSupported without DXVK extension succeeds but reports unsupported") {
+ ALLOW_CALL(device, GetExtensionSupport(D3D11_VK_NVX_BINARY_IMPORT))
+ .RETURN(false);
+
+ bool sup = true;
+ REQUIRE(NvAPI_D3D11_IsFatbinPTXSupported(static_cast<ID3D11Device*>(&device), &sup) == NVAPI_OK);
+ REQUIRE(sup == false);
+ REQUIRE(deviceRefCount == 0);
+ }
+
+ SECTION("(NvAPI_D3D11_)CreateUnorderedAccessView/CreateShaderResourceView/GetResourceGPUVirtualAddress/GetResourceGPUVirtualAddressEx/GetCudaTextureObject/CreateSamplerState without extended DXVK interface returns error") {
+ ALLOW_CALL(device, QueryInterface(ID3D11VkExtDevice1::guid, _))
+ .RETURN(E_NOINTERFACE);
+ ALLOW_CALL(context, QueryInterface(ID3D11VkExtContext1::guid, _))
+ .RETURN(E_NOINTERFACE);
+ FORBID_CALL(device, CreateUnorderedAccessViewAndGetDriverHandleNVX(_, _, _, _));
+ FORBID_CALL(device, CreateShaderResourceViewAndGetDriverHandleNVX(_, _, _, _));
+ FORBID_CALL(device, GetResourceHandleGPUVirtualAddressAndSizeNVX(_, _, _));
+ FORBID_CALL(device, GetCudaTextureObjectNVX(_, _, _));
+ FORBID_CALL(device, CreateSamplerStateAndGetDriverHandleNVX(_, _, _));
+
+ D3D11BufferMock res;
+ NvU32 driverhandle;
+ D3D11_UNORDERED_ACCESS_VIEW_DESC uavdesc;
+ ID3D11UnorderedAccessView* pUAV;
+ REQUIRE(NvAPI_D3D11_CreateUnorderedAccessView(static_cast<ID3D11Device*>(&device), &res, &uavdesc, &pUAV, &driverhandle) == NVAPI_ERROR);
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvdesc;
+ ID3D11ShaderResourceView* pSRV;
+ REQUIRE(NvAPI_D3D11_CreateShaderResourceView(static_cast<ID3D11Device*>(&device), &res, &srvdesc, &pSRV, &driverhandle) == NVAPI_ERROR);
+ NvU64 gpuVAStart;
+ REQUIRE(NvAPI_D3D11_GetResourceGPUVirtualAddress(static_cast<ID3D11Device*>(&device), NVDX_ObjectHandle(1), &gpuVAStart) == NVAPI_ERROR);
+ NV_GET_GPU_VIRTUAL_ADDRESS gva;
+ gva.version = NV_GET_GPU_VIRTUAL_ADDRESS_VER1;
+ gva.hResource = NVDX_ObjectHandle(1);
+ REQUIRE(NvAPI_D3D11_GetResourceGPUVirtualAddressEx(static_cast<ID3D11Device*>(&device), &gva) == NVAPI_ERROR);
+ D3D11_SAMPLER_DESC samplerdesc;
+ ID3D11SamplerState* pSamplerState;
+ REQUIRE(NvAPI_D3D11_CreateSamplerState(static_cast<ID3D11Device*>(&device), &samplerdesc, &pSamplerState, &driverhandle) == NVAPI_ERROR);
+ REQUIRE(NvAPI_D3D11_GetCudaTextureObject(static_cast<ID3D11Device*>(&device), 0x1, 0x2, &driverhandle) == NVAPI_ERROR);
+ REQUIRE(deviceRefCount == 0);
+ }
+
// Test failing scenarios first because caches won't be reset between tests (we don't cache negatives)
SECTION("IsNvShaderExtnOpCodeSupported returns OK") {
@@ -178,4 +285,55 @@ TEST_CASE("D3D11 methods succeed", "[.d3d11]") {
REQUIRE(deviceRefCount == 0);
REQUIRE(contextRefCount == 0);
}
+
+ SECTION("DestroyCubinComputeShader treats handle as a COM object and releases it") {
+ // it's part of our contract with DXVK that cuda shader handles are really COM objects
+ UnknownMock comobj;
+ REQUIRE_CALL(comobj, Release())
+ .TIMES(1)
+ .RETURN(42);
+
+ NVDX_ObjectHandle handle = reinterpret_cast<NVDX_ObjectHandle>(&comobj);
+ REQUIRE(NvAPI_D3D11_DestroyCubinComputeShader(static_cast<ID3D11Device*>(&device), handle) == NVAPI_OK);
+ REQUIRE(deviceRefCount == 0);
+ REQUIRE(contextRefCount == 0);
+ }
+
+ SECTION("DestroyCubinComputeShader does not succeed (or crash) on a NULL or NVDX_OBJECT_NONE handle") {
+ // this also checks the assumption that NVDX_OBJECT_NONE casts <-> NULL, which should forever be true but will break some stuff in subtle ways if not, so ¯\_(ツ)_/¯
+ REQUIRE(NVDX_OBJECT_NONE == reinterpret_cast<NVDX_ObjectHandle>(NULL /* not nullptr which is castproofed */));
+ REQUIRE(reinterpret_cast<void*>(NVDX_OBJECT_NONE) == nullptr);
+ REQUIRE(NvAPI_D3D11_DestroyCubinComputeShader(static_cast<ID3D11Device*>(&device), nullptr) != NVAPI_OK);
+ REQUIRE(NvAPI_D3D11_DestroyCubinComputeShader(static_cast<ID3D11Device*>(&device), NVDX_OBJECT_NONE) != NVAPI_OK);
+ REQUIRE(deviceRefCount == 0);
+ REQUIRE(contextRefCount == 0);
+ }
+
+ SECTION("GetResourceHandle returns OK") {
+ // Test device call twice to ensure correct reference counting when hitting the device cache
+ D3D11BufferMock res;
+ NVDX_ObjectHandle handle = reinterpret_cast<NVDX_ObjectHandle>(&res);
+ REQUIRE(NvAPI_D3D11_GetResourceHandle(static_cast<ID3D11Device*>(&device), &res, &handle) == NVAPI_OK);
+ REQUIRE(NvAPI_D3D11_GetResourceHandle(static_cast<ID3D11Device*>(&device), &res, &handle) == NVAPI_OK);
+ REQUIRE(deviceRefCount == 0);
+ REQUIRE(contextRefCount == 0);
+ }
+
+ SECTION("GetResourceHandle with NULL argument returns InvalidArgument") {
+ D3D11BufferMock res;
+ NVDX_ObjectHandle handle;
+ REQUIRE(NvAPI_D3D11_GetResourceHandle(nullptr, &res, &handle) == NVAPI_INVALID_ARGUMENT);
+ REQUIRE(NvAPI_D3D11_GetResourceHandle(static_cast<ID3D11Device*>(&device), nullptr, &handle) == NVAPI_INVALID_ARGUMENT);
+ REQUIRE(NvAPI_D3D11_GetResourceHandle(static_cast<ID3D11Device*>(&device), &res, nullptr) == NVAPI_INVALID_ARGUMENT);
+ REQUIRE(deviceRefCount == 0);
+ REQUIRE(contextRefCount == 0);
+ }
+
+ SECTION("GetResourceHandle output handle is a simple recast of the input resource pointer") {
+ // While the handles returned by NvAPI are opaque with unspecified values, our interaction with DXVK *requires* that we implement them as a simple recast
+ D3D11BufferMock res;
+ NVDX_ObjectHandle handle;
+ REQUIRE(NvAPI_D3D11_GetResourceHandle(static_cast<ID3D11Device*>(&device), &res, &handle) == NVAPI_OK);
+ REQUIRE(reinterpret_cast<void*>(handle) == reinterpret_cast<void*>(&res));
+ }
}
diff --git a/tests/nvapi_d3d11_mocks.cpp b/tests/nvapi_d3d11_mocks.cpp
index 1620db9..a510a71 100644
--- a/tests/nvapi_d3d11_mocks.cpp
+++ b/tests/nvapi_d3d11_mocks.cpp
@@ -2,7 +2,7 @@
using namespace trompeloeil;
-class ID3D11DxvkDevice : public ID3D11Device, public ID3D11VkExtDevice {};
+class ID3D11DxvkDevice : public ID3D11Device, public ID3D11VkExtDevice1 {};
class D3D11DxvkDeviceMock : public mock_interface<ID3D11DxvkDevice> {
MAKE_MOCK2(QueryInterface, HRESULT(REFIID, void**), override);
@@ -49,9 +49,15 @@ class D3D11DxvkDeviceMock : public mock_interface<ID3D11DxvkDevice> {
IMPLEMENT_MOCK0(GetExceptionMode);
IMPLEMENT_MOCK1(GetImmediateContext);
IMPLEMENT_MOCK1(GetExtensionSupport);
+ IMPLEMENT_MOCK3(GetCudaTextureObjectNVX);
+ IMPLEMENT_MOCK7(CreateCubinComputeShaderWithNameNVX);
+ IMPLEMENT_MOCK4(CreateUnorderedAccessViewAndGetDriverHandleNVX);
+ IMPLEMENT_MOCK4(CreateShaderResourceViewAndGetDriverHandleNVX);
+ IMPLEMENT_MOCK3(CreateSamplerStateAndGetDriverHandleNVX);
+ IMPLEMENT_MOCK3(GetResourceHandleGPUVirtualAddressAndSizeNVX);
};
-class ID3D11DxvkDeviceContext : public ID3D11DeviceContext, public ID3D11VkExtContext {};
+class ID3D11DxvkDeviceContext : public ID3D11DeviceContext, public ID3D11VkExtContext1 {};
class D3D11DxvkDeviceContextMock : public mock_interface<ID3D11DxvkDeviceContext> {
MAKE_MOCK2(QueryInterface, HRESULT(REFIID, void**), override);
@@ -175,6 +181,7 @@ class D3D11DxvkDeviceContextMock : public mock_interface<ID3D11DxvkDeviceContext
IMPLEMENT_MOCK6(MultiDrawIndexedIndirectCount);
IMPLEMENT_MOCK3(SetDepthBoundsTest);
IMPLEMENT_MOCK1(SetBarrierControl);
+ IMPLEMENT_MOCK10(LaunchCubinShaderNVX);
};
class D3D11BufferMock : public mock_interface<ID3D11Buffer> {