@@ -25,40 +25,92 @@ class IApplicationFramework : public core::IReferenceCounted
2525 // this is safe to call multiple times
2626 static bool GlobalsInit ()
2727 {
28- #ifdef _NBL_PLATFORM_WINDOWS_
29- #ifdef NBL_CPACK_PACKAGE_DXC_DLL_DIR
30- #ifdef NBL_CPACK_NO_BUILD_DIRECTORY_MODULES
31- const HRESULT dxcLoad = CSystemWin32::delayLoadDLL (" dxcompiler.dll" , { NBL_CPACK_PACKAGE_DXC_DLL_DIR });
32- #else
33- const HRESULT dxcLoad = CSystemWin32::delayLoadDLL (" dxcompiler.dll" , { path (_DXC_DLL_).parent_path (), NBL_CPACK_PACKAGE_DXC_DLL_DIR });
34- #endif
28+ // TODO: update CMake and rename "DLL" in all of those defines here to "MODULE" or "RUNTIME"
29+
30+ auto getEnvInstallDirectory = []()
31+ {
32+ const char * sdk = std::getenv (" NBL_INSTALL_DIRECTORY" );
33+
34+ if (sdk)
35+ {
36+ const auto directory = system::path (sdk);
37+
38+ if (std::filesystem::exists (directory))
39+ return directory;
40+ }
41+
42+ return system::path (" " );
43+ };
44+
45+ constexpr struct
46+ {
47+ std::string_view nabla, dxc;
48+ } module =
49+ {
50+ #ifdef _NBL_SHARED_BUILD_
51+ _NABLA_DLL_NAME_
3552 #else
36- const HRESULT dxcLoad = CSystemWin32::delayLoadDLL ( " dxcompiler.dll " , { path (_DXC_DLL_). parent_path () });
53+ " "
3754 #endif
55+ ,
56+ " dxcompiler"
57+ };
3858
39- if (FAILED (dxcLoad))
40- return false ;
41-
42- #ifdef _NBL_SHARED_BUILD_
43- // if there was no DLL next to the executable, then try from the Nabla build directory
44- // else if nothing in the build dir, then try looking for Nabla in the CURRENT BUILD'S INSTALL DIR
45- // and in CPack package install directory
46-
47- #ifdef NBL_CPACK_PACKAGE_NABLA_DLL_DIR
48- #ifdef NBL_CPACK_NO_BUILD_DIRECTORY_MODULES
49- const HRESULT nablaLoad = CSystemWin32::delayLoadDLL (_NABLA_DLL_NAME_, { _NABLA_INSTALL_DIR_, NBL_CPACK_PACKAGE_NABLA_DLL_DIR });
50- #else
51- const HRESULT nablaLoad = CSystemWin32::delayLoadDLL (_NABLA_DLL_NAME_, { _NABLA_OUTPUT_DIR_,_NABLA_INSTALL_DIR_, NBL_CPACK_PACKAGE_NABLA_DLL_DIR });
52- #endif
53- #else
54- const HRESULT nablaLoad = CSystemWin32::delayLoadDLL (_NABLA_DLL_NAME_, { _NABLA_OUTPUT_DIR_,_NABLA_INSTALL_DIR_ });
55- #endif
56-
57- if (FAILED (nablaLoad))
59+ const auto sdk = getEnvInstallDirectory ();
60+
61+ struct
62+ {
63+ system::path nabla, dxc;
64+ } install, env, build, rel;
65+
66+ install.nabla = std::filesystem::absolute (system::path (_NABLA_INSTALL_DIR_) / NBL_CPACK_PACKAGE_NABLA_DLL_DIR_ABS_KEY);
67+ install.dxc = std::filesystem::absolute (system::path (_NABLA_INSTALL_DIR_) / NBL_CPACK_PACKAGE_DXC_DLL_DIR_ABS_KEY);
68+
69+ env.nabla = sdk / NBL_CPACK_PACKAGE_NABLA_DLL_DIR_ABS_KEY;
70+ env.dxc = sdk / NBL_CPACK_PACKAGE_DXC_DLL_DIR_ABS_KEY;
71+
72+ #ifdef _NBL_SHARED_BUILD_
73+ build.nabla = _NABLA_OUTPUT_DIR_;
74+ #endif
75+ build.dxc = path (_DXC_DLL_).parent_path ();
76+
77+ #ifdef NBL_CPACK_PACKAGE_NABLA_DLL_DIR
78+ rel.nabla = NBL_CPACK_PACKAGE_NABLA_DLL_DIR;
79+ #endif
80+
81+ #ifdef NBL_CPACK_PACKAGE_DXC_DLL_DIR
82+ rel.dxc = NBL_CPACK_PACKAGE_DXC_DLL_DIR;
83+ #endif
84+
85+ auto load = [](std::string_view moduleName, const std::vector<system::path>& searchPaths)
86+ {
87+ #ifdef _NBL_PLATFORM_WINDOWS_
88+ const bool isAlreadyLoaded = GetModuleHandleA (moduleName.data ());
89+
90+ if (not isAlreadyLoaded)
91+ {
92+ const HRESULT hook = system::CSystemWin32::delayLoadDLL (moduleName.data (), searchPaths);
93+
94+ // ! 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,
95+ // ! proc addresses will be resolved correctly but status may scream "FAILED" due to lack of a PDB to load
96+
97+ if (FAILED (hook))
5898 return false ;
59- #endif // _NBL_SHARED_BUILD_
60- #else
61- // nothing else needs to be done cause we have RPath
99+ }
100+ #else
101+ // nothing else needs to be done cause we have RPath
102+ // TODO: to be checked when time comes
103+ #endif
104+
105+ return true ;
106+ };
107+
108+ if (not load (module .dxc , { install.dxc , env.dxc , build.dxc , rel.dxc }))
109+ return false ;
110+
111+ #ifdef _NBL_SHARED_BUILD_
112+ if (not load (module .nabla , { install.nabla , env.nabla , build.nabla , rel.nabla }))
113+ return false ;
62114 #endif
63115
64116 return true ;
@@ -70,9 +122,13 @@ class IApplicationFramework : public core::IReferenceCounted
70122 {
71123 path CWD = system::path (argv[0 ]).parent_path ().generic_string () + " /" ;
72124 auto app = core::make_smart_refctd_ptr<CRTP>(CWD/" ../" ,CWD,CWD/" ../../media/" ,CWD/" ../../tmp/" );
125+
73126 for (auto i=0 ; i<argc; i++)
74127 app->argv .emplace_back (argv[i]);
75128
129+ if (not app->isAPILoaded ())
130+ app->onAPILoadFailure ();
131+
76132 if (!app->onAppInitialized (nullptr ))
77133 return -1 ;
78134 while (app->keepRunning ())
@@ -95,11 +151,9 @@ class IApplicationFramework : public core::IReferenceCounted
95151
96152 // needs to be public because of how constructor forwarding works
97153 IApplicationFramework (const path& _localInputCWD, const path& _localOutputCWD, const path& _sharedInputCWD, const path& _sharedOutputCWD) :
98- localInputCWD (_localInputCWD), localOutputCWD(_localOutputCWD), sharedInputCWD(_sharedInputCWD), sharedOutputCWD(_sharedOutputCWD)
99- {
100- const bool status = GlobalsInit ();
101- assert (status);
102- }
154+ localInputCWD (_localInputCWD), localOutputCWD(_localOutputCWD), sharedInputCWD(_sharedInputCWD), sharedOutputCWD(_sharedOutputCWD), m_apiLoaded(GlobalsInit()) {}
155+
156+ virtual bool onAPILoadFailure () { return m_apiLoaded = false ; }
103157
104158 // DEPRECATED
105159 virtual void setSystem (core::smart_refctd_ptr<ISystem>&& system) {}
@@ -112,6 +166,9 @@ class IApplicationFramework : public core::IReferenceCounted
112166 virtual void workLoopBody () = 0;
113167 virtual bool keepRunning () = 0;
114168
169+ // ! returns status of global initialization - on false you are supposed to terminate the application with non-zero code (otherwise you enter undefined behavior zone)
170+ inline bool isAPILoaded () { return m_apiLoaded; }
171+
115172 protected:
116173 // need this one for skipping the whole constructor chain
117174 IApplicationFramework () = default ;
@@ -130,7 +187,6 @@ class IApplicationFramework : public core::IReferenceCounted
130187 *******************************************************************
131188 */
132189
133-
134190 /*
135191 This is a CWD which is used for reading app-local assets.
136192 Do NOT try writing to this path if you wan't your app to work on Android because on Android this CWD is located inside a readonly APK archive.
@@ -153,6 +209,8 @@ class IApplicationFramework : public core::IReferenceCounted
153209 This CWD is used to output data that can be shared between apps e.g. quantization cache
154210 */
155211 path sharedOutputCWD;
212+
213+ bool m_apiLoaded;
156214};
157215
158216}
0 commit comments