Skip to content

Commit 048d093

Browse files
committed
integrate NGFX with Nabla build system, delay load the DLL on windows target platforms
1 parent 639cf78 commit 048d093

File tree

4 files changed

+148
-58
lines changed

4 files changed

+148
-58
lines changed

3rdparty/ngfx/ngfx.cmake

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ if(NBL_BUILD_WITH_NGFX)
3737
set(NGFX_SDK_VERSION "${LATEST_NGFX_VERSION}" CACHE STRING "NGFX SDK Version")
3838
set_property(CACHE NGFX_SDK_VERSION PROPERTY STRINGS ${NGFX_VERSIONS})
3939

40-
set(NGFX_SDK_BASE "${NGFX_SDK}/$CACHE{NGFX_SDK_VERSION}")
40+
set(NGFX_SDK_VERSION "$CACHE{NGFX_SDK_VERSION}")
41+
set(NGFX_SDK_BASE "${NGFX_SDK}/${NGFX_SDK_VERSION}")
4142

4243
# TODO: wanna support more *host* platforms? (*)
4344
# NOTE: also I'm hardcoding windows x64 library requests till I know the answer for (*)
@@ -46,9 +47,9 @@ if(NBL_BUILD_WITH_NGFX)
4647
find_file(NBL_NGFX_INJECTION_IMPORT_LIBRARY NGFX_Injection.lib PATHS ${NGFX_SDK_BASE}/lib/x64)
4748

4849
if(NBL_NGFX_INJECTION_HEADER AND NBL_NGFX_INJECTION_DLL AND NBL_NGFX_INJECTION_IMPORT_LIBRARY)
49-
message(STATUS "Enabled build with NVIDIA Nsight Graphics SDK $CACHE{NGFX_SDK_VERSION}\nlocated in: \"${NGFX_SDK_BASE}\"")
50+
message(STATUS "Enabled build with NVIDIA Nsight Graphics SDK ${NGFX_SDK_VERSION}\nlocated in: \"${NGFX_SDK_BASE}\"")
5051
else()
51-
message(STATUS "Could not enable build with NVIDIA Nsight Graphics SDK $CACHE{NGFX_SDK_VERSION} - invalid components!")
52+
message(STATUS "Could not enable build with NVIDIA Nsight Graphics SDK ${NGFX_SDK_VERSION} - invalid components!")
5253
message(STATUS "Located in: \"${NGFX_SDK_BASE}\"")
5354
message(STATUS "NBL_NGFX_INJECTION_HEADER=\"${NBL_NGFX_INJECTION_HEADER}\"")
5455
message(STATUS "NBL_NGFX_INJECTION_DLL=\"${NBL_NGFX_INJECTION_DLL}\"")
@@ -60,4 +61,7 @@ if(NBL_BUILD_WITH_NGFX)
6061
target_sources(ngfx INTERFACE "${NBL_NGFX_INJECTION_HEADER}")
6162
target_include_directories(ngfx INTERFACE "${NGFX_SDK_BASE}/include")
6263
target_link_libraries(ngfx INTERFACE "${NBL_NGFX_INJECTION_IMPORT_LIBRARY}")
64+
target_link_options(ngfx INTERFACE "/DELAYLOAD:NGFX_Injection.dll")
65+
target_compile_definitions(ngfx INTERFACE NGFX_INJECTION_DLL_DIR="${NGFX_SDK_BASE}/lib/x64")
66+
target_compile_definitions(ngfx INTERFACE NGFX_VERSION="${NGFX_SDK_VERSION}")
6367
endif()

include/nbl/video/IAPIConnection.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,17 @@ class NBL_API2 IAPIConnection : public core::IReferenceCounted
7777
SDebuggerType m_debuggerType;
7878
renderdoc_api_t* m_rdoc_api;
7979

80-
struct SNGFXIntegration {
81-
bool useNGFX;
80+
struct SNGFXIntegration
81+
{
82+
SNGFXIntegration();
83+
84+
bool useNGFX = false;
8285

8386
bool injectNGFXToProcess();
8487
bool executeNGFXCommand();
88+
inline bool isAPILoaded() { return m_loaded; }
89+
private:
90+
const bool m_loaded;
8591
};
8692
using ngfx_api_t = SNGFXIntegration;
8793
ngfx_api_t m_ngfx_api;

src/nbl/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,21 @@ write_source_definitions("${_NBL_DEFINE_FILE_WRAPPER_}" "${_NBL_SOURCE_DEFINITIO
659659
# git version tracking
660660
target_link_libraries(Nabla PUBLIC gtml)
661661

662+
# NGFX
663+
if(TARGET ngfx)
664+
if(NBL_STATIC_BUILD)
665+
target_link_libraries(Nabla INTERFACE ngfx)
666+
else()
667+
target_link_libraries(Nabla PRIVATE ngfx)
668+
endif()
669+
670+
target_include_directories(Nabla PRIVATE $<TARGET_PROPERTY:ngfx,INTERFACE_INCLUDE_DIRECTORIES>)
671+
target_compile_definitions(Nabla
672+
PRIVATE NBL_BUILD_WITH_NGFX
673+
PRIVATE $<TARGET_PROPERTY:ngfx,INTERFACE_COMPILE_DEFINITIONS>
674+
)
675+
endif()
676+
662677
#on MSVC it won't compile without this option!
663678
if (MSVC)
664679
target_compile_options(Nabla PUBLIC /bigobj)

src/nbl/video/IAPIConnection.cpp

Lines changed: 118 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
#include "nbl/video/IPhysicalDevice.h"
44
#include "nbl/video/utilities/renderdoc.h"
5-
#include "nbl/video/utilities/ngfx.h"
65

7-
// TODO: temporary hopefully
8-
#include "C:\Program Files\NVIDIA Corporation\Nsight Graphics 2024.1.0\SDKs\NsightGraphicsSDK\0.8.0\include\NGFX_Injection.h"
6+
#include "nbl/system/CSystemWin32.h"
7+
8+
#ifdef NBL_BUILD_WITH_NGFX
9+
#include "NGFX_Injection.h"
10+
#endif
911

1012
#if defined(_NBL_POSIX_API_)
1113
#include <dlfcn.h>
@@ -14,7 +16,6 @@
1416
namespace nbl::video
1517
{
1618

17-
1819
std::span<IPhysicalDevice* const> IAPIConnection::getPhysicalDevices() const
1920
{
2021
static_assert(sizeof(std::unique_ptr<IPhysicalDevice>) == sizeof(void*));
@@ -59,70 +60,134 @@ IAPIConnection::IAPIConnection(const SFeatures& enabledFeatures)
5960

6061
bool IAPIConnection::SNGFXIntegration::injectNGFXToProcess()
6162
{
62-
uint32_t numInstallations = 0;
63-
auto result = NGFX_Injection_EnumerateInstallations(&numInstallations, nullptr);
64-
if (numInstallations == 0 || NGFX_INJECTION_RESULT_OK != result)
63+
#ifdef NBL_BUILD_WITH_NGFX
64+
if (m_loaded) //! this check is mandatory!
6565
{
66-
useNGFX = false;
67-
return false;
68-
}
66+
uint32_t numInstallations = 0;
67+
auto result = NGFX_Injection_EnumerateInstallations(&numInstallations, nullptr);
68+
if (numInstallations == 0 || NGFX_INJECTION_RESULT_OK != result)
69+
{
70+
useNGFX = false;
71+
return false;
72+
}
6973

70-
std::vector<NGFX_Injection_InstallationInfo> installations(numInstallations);
71-
result = NGFX_Injection_EnumerateInstallations(&numInstallations, installations.data());
72-
if (numInstallations == 0 || NGFX_INJECTION_RESULT_OK != result)
73-
{
74-
useNGFX = false;
75-
return false;
76-
}
74+
std::vector<NGFX_Injection_InstallationInfo> installations(numInstallations);
75+
result = NGFX_Injection_EnumerateInstallations(&numInstallations, installations.data());
76+
if (numInstallations == 0 || NGFX_INJECTION_RESULT_OK != result)
77+
{
78+
useNGFX = false;
79+
return false;
80+
}
7781

78-
// get latest installation
79-
NGFX_Injection_InstallationInfo versionInfo = installations.back();
82+
// get latest installation
83+
NGFX_Injection_InstallationInfo versionInfo = installations.back();
8084

81-
uint32_t numActivities = 0;
82-
result = NGFX_Injection_EnumerateActivities(&versionInfo, &numActivities, nullptr);
83-
if (numActivities == 0 || NGFX_INJECTION_RESULT_OK != result)
84-
{
85-
useNGFX = false;
86-
return false;
87-
}
85+
uint32_t numActivities = 0;
86+
result = NGFX_Injection_EnumerateActivities(&versionInfo, &numActivities, nullptr);
87+
if (numActivities == 0 || NGFX_INJECTION_RESULT_OK != result)
88+
{
89+
useNGFX = false;
90+
return false;
91+
}
8892

89-
std::vector<NGFX_Injection_Activity> activities(numActivities);
90-
result = NGFX_Injection_EnumerateActivities(&versionInfo, &numActivities, activities.data());
91-
if (NGFX_INJECTION_RESULT_OK != result)
92-
{
93-
useNGFX = false;
94-
return false;
95-
}
93+
std::vector<NGFX_Injection_Activity> activities(numActivities);
94+
result = NGFX_Injection_EnumerateActivities(&versionInfo, &numActivities, activities.data());
95+
if (NGFX_INJECTION_RESULT_OK != result)
96+
{
97+
useNGFX = false;
98+
return false;
99+
}
96100

97-
const NGFX_Injection_Activity* pActivityToInject = nullptr;
98-
for (const NGFX_Injection_Activity& activity : activities)
99-
{
100-
if (activity.type == NGFX_INJECTION_ACTIVITY_FRAME_DEBUGGER) // only want frame debugger
101+
const NGFX_Injection_Activity* pActivityToInject = nullptr;
102+
for (const NGFX_Injection_Activity& activity : activities)
101103
{
102-
pActivityToInject = &activity;
103-
break;
104+
if (activity.type == NGFX_INJECTION_ACTIVITY_FRAME_DEBUGGER) // only want frame debugger
105+
{
106+
pActivityToInject = &activity;
107+
break;
108+
}
104109
}
105-
}
106110

107-
if (!pActivityToInject) {
108-
useNGFX = false;
109-
return false;
110-
}
111+
if (!pActivityToInject) {
112+
useNGFX = false;
113+
return false;
114+
}
111115

112-
result = NGFX_Injection_InjectToProcess(&versionInfo, pActivityToInject);
113-
if (NGFX_INJECTION_RESULT_OK != result)
114-
{
115-
useNGFX = false;
116-
return false;
117-
}
116+
result = NGFX_Injection_InjectToProcess(&versionInfo, pActivityToInject);
117+
if (NGFX_INJECTION_RESULT_OK != result)
118+
{
119+
useNGFX = false;
120+
return false;
121+
}
122+
123+
useNGFX = true;
124+
125+
return true;
126+
} // optional TOOD: could log on "else"
127+
#endif // NBL_BUILD_WITH_NGFX
118128

119-
useNGFX = true;
120-
return true;
129+
return false;
121130
}
122131

123132
bool IAPIConnection::SNGFXIntegration::executeNGFXCommand()
124133
{
125-
return NGFX_Injection_ExecuteActivityCommand() == NGFX_INJECTION_RESULT_OK;
134+
#ifdef NBL_BUILD_WITH_NGFX
135+
if(m_loaded) //! this check is mandatory!
136+
return NGFX_Injection_ExecuteActivityCommand() == NGFX_INJECTION_RESULT_OK; // optional TOOD: could log on "else"
137+
#endif // NBL_BUILD_WITH_NGFX
138+
139+
return false;
126140
}
127141

142+
IAPIConnection::SNGFXIntegration::SNGFXIntegration()
143+
: useNGFX(false /*??*/), m_loaded([]() -> bool
144+
{
145+
#ifdef NBL_BUILD_WITH_NGFX
146+
//! absolute path to official install NGFX SDK runtime directory
147+
auto getOfficialRuntimeDirectory = []()
148+
{
149+
const char* sdk = std::getenv("NGFX_SDK");
150+
const char* version = std::getenv("NGFX_VERSION");
151+
const bool composed = sdk && version;
152+
153+
if (composed)
154+
{
155+
const auto directory = system::path(sdk) / system::path(version) / "lib" / "x64";
156+
157+
if (std::filesystem::exists(directory))
158+
return directory;
159+
}
160+
161+
return system::path("");
162+
};
163+
164+
//! batch request with priority order & custom Nabla runtime search, I'm assuming we are loading the runtime from official SDK not custom location
165+
//! one question is if we should have any constraints for min/max version, maybe force the "version"
166+
//! to match the "NGFX_VERSION" define so to "what we built with", or don't have any - just like now
167+
168+
#if defined(_NBL_PLATFORM_WINDOWS_)
169+
static constexpr std::string_view NGFXMODULE = "NGFX_Injection.dll";
170+
HMODULE isAlreadyLoaded = GetModuleHandleA(NGFXMODULE.data());
171+
172+
if (!isAlreadyLoaded)
173+
{
174+
const auto dll = getOfficialRuntimeDirectory() / NGFXMODULE.data();
175+
const HRESULT hook = system::CSystemWin32::delayLoadDLL(NGFXMODULE.data(), { NGFX_INJECTION_DLL_DIR, dll.parent_path() });
176+
177+
//! don't be scared if you see "No symbols loaded" - you will not hit "false" in this case, the DLL will get loaded if found,
178+
//! proc addresses will be resolved correctly but status will scream "FAILED" because we don't have any PDB to load
179+
if (FAILED(hook))
180+
return false;
181+
}
182+
#else
183+
#error "TODO!"
184+
#endif
185+
186+
return true;
187+
#else
188+
return false; // no NGFX build -> no API to load
189+
#endif
190+
}())
191+
{}
192+
128193
}

0 commit comments

Comments
 (0)