// This code contains NVIDIA Confidential Information and is disclosed to you // under a form of NVIDIA software license agreement provided separately to you. // // Notice // NVIDIA Corporation and its licensors retain all intellectual property and // proprietary rights in and to this software and related documentation and // any modifications thereto. Any use, reproduction, disclosure, or // distribution of this software and related documentation without an express // license agreement from NVIDIA Corporation is strictly prohibited. // // ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES // NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO // THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, // MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. // // Information and code furnished is believed to be accurate and reliable. // However, NVIDIA Corporation assumes no responsibility for the consequences of use of such // information or for any infringement of patents or other rights of third parties that may // result from its use. No license is granted by implication or otherwise under any patent // or patent rights of NVIDIA Corporation. Details are subject to change without notice. // This code supersedes and replaces all information previously supplied. // NVIDIA Corporation products are not authorized for use as critical // components in life support devices or systems without express written approval of // NVIDIA Corporation. // // Copyright 2016 NVIDIA Corporation. All rights reserved. #define ANSEL_SDK_DELAYLOAD #include "DelayLoader.h" #include #include #include #include #include #include #include #include namespace { HMODULE anselSDK = NULL; } namespace ansel { namespace { typedef SetConfigurationStatus(__cdecl *PFNSETCONFIGURATION)(const Configuration& cfg); typedef void(__cdecl *PFNUPDATECAMERA)(Camera& camera); typedef void(__cdecl *PFNSESSIONFUNC)(); typedef bool(__cdecl *PFNISANSELAVAILABLE)(); typedef void(__cdecl *PFNMARKHDRBUFFERBIND)(HintType, uint64_t); typedef void(__cdecl *PFNMARKHDRBUFFERFINISHED)(uint64_t); typedef UserControlStatus(__cdecl *PFNADDUSERCONTROL)(const UserControlDesc&); typedef UserControlStatus(__cdecl *PFNSETUSERCONTROLLABELLOCALIZATION)(uint32_t, const char*, const char*); typedef UserControlStatus(__cdecl *PFNREMOVEUSERCONTROL)(uint32_t); typedef UserControlStatus(__cdecl *PFNGETUSERCONTROLVALUE)(uint32_t, void*); PFNMARKHDRBUFFERFINISHED markHdrBufferFinishedFunc = nullptr; PFNMARKHDRBUFFERBIND markHdrBufferBindFunc = nullptr; PFNSESSIONFUNC stopSessionFunc = nullptr; PFNSESSIONFUNC startSessionFunc = nullptr; PFNUPDATECAMERA updateCameraFunc = nullptr; PFNSETCONFIGURATION setConfigurationFunc = nullptr; PFNADDUSERCONTROL addUserControlFunc = nullptr; PFNSETUSERCONTROLLABELLOCALIZATION setUserControlLabelLocalizationFunc = nullptr; PFNREMOVEUSERCONTROL removeUserControlFunc = nullptr; PFNGETUSERCONTROLVALUE getUserControlValueFunc = nullptr; DelayLoadStatus resolveFunctionPointers() { if (anselSDK == NULL) return kDelayLoadDllNotFound; setConfigurationFunc = reinterpret_cast(GetProcAddress(anselSDK, "setConfiguration")); stopSessionFunc = reinterpret_cast(GetProcAddress(anselSDK, "stopSession")); startSessionFunc = reinterpret_cast(GetProcAddress(anselSDK, "startSession")); updateCameraFunc = reinterpret_cast(GetProcAddress(anselSDK, "updateCamera")); markHdrBufferBindFunc = reinterpret_cast(GetProcAddress(anselSDK, "markHdrBufferBind")); markHdrBufferFinishedFunc = reinterpret_cast(GetProcAddress(anselSDK, "markHdrBufferFinished")); addUserControlFunc = reinterpret_cast(GetProcAddress(anselSDK, "addUserControl")); setUserControlLabelLocalizationFunc = reinterpret_cast(GetProcAddress(anselSDK, "setUserControlLabelLocalization")); removeUserControlFunc = reinterpret_cast(GetProcAddress(anselSDK, "removeUserControl")); getUserControlValueFunc = reinterpret_cast(GetProcAddress(anselSDK, "getUserControlValue")); if (setConfigurationFunc == nullptr || stopSessionFunc == nullptr || startSessionFunc == nullptr || updateCameraFunc == nullptr || markHdrBufferBindFunc == nullptr || markHdrBufferFinishedFunc == nullptr || addUserControlFunc == nullptr || setUserControlLabelLocalizationFunc == nullptr || removeUserControlFunc == nullptr || getUserControlValueFunc == nullptr) return kDelayLoadIncompatibleVersion; return kDelayLoadOk; } void makeQuaternionFromRotationMatrix(nv::Quat& q, const float r[3][3]) { float trace = r[0][0] + r[1][1] + r[2][2]; if (trace > 0.0f) { // |w| > 1/2, may as well choose w > 1/2 float s = sqrtf(trace + 1.0f); // 2w q.w = s * 0.5f; s = 0.5f / s; // 1/(4w) q.x = (r[2][1] - r[1][2]) * s; q.y = (r[0][2] - r[2][0]) * s; q.z = (r[1][0] - r[0][1]) * s; } else { // |w| <= 1/2 int i = 0; if (r[1][1] > r[0][0]) i = 1; if (r[2][2] > r[i][i]) i = 2; int j = (1 << i) & 3; // i + 1 modulo 3. int k = (1 << j) & 3; float s = sqrtf(r[i][i] - r[j][j] - r[k][k] + 1.0f); float* component = &q.x; component[i] = s * 0.5f; s = 0.5f / s; component[j] = (r[i][j] + r[j][i]) * s; component[k] = (r[k][i] + r[i][k]) * s; q.w = (r[k][j] - r[j][k]) * s; } } void makeRotationMatrixFromQuaternion(float rot[3][3], const nv::Quat& q) { float s = 2.0f; float xs = q.x * s; float ys = q.y * s; float zs = q.z * s; float wx = q.w * xs; float wy = q.w * ys; float wz = q.w * zs; float xx = q.x * xs; float xy = q.x * ys; float xz = q.x * zs; float yy = q.y * ys; float yz = q.y * zs; float zz = q.z * zs; rot[0][0] = 1.0f - (yy + zz); rot[0][1] = xy - wz; rot[0][2] = xz + wy; rot[1][0] = xy + wz; rot[1][1] = 1.0f - (xx + zz); rot[1][2] = yz - wx; rot[2][0] = xz - wy; rot[2][1] = yz + wx; rot[2][2] = 1.0f - (xx + yy); } // This may seem like a funky construct so allow me to explain. This code serves only // one purpose: to create a signaling object that Ansel (when loaded from driver shim) // can use to detect that a game has integrated the SDK. Note that this same object // will also be created by the SDK DLL when loaded but this is safe since creating // the same mutex again just provides a handle to the already existing mutex. class SdkMutex { public: SdkMutex() { DWORD id = GetCurrentProcessId(); char name[MAX_PATH]; sprintf_s(name, "NVIDIA/Ansel/%d", id); CreateMutexA(NULL, false, name); } }; SdkMutex s_mySdkMutex; } SetConfigurationStatus setConfiguration(const Configuration& config) { if (setConfigurationFunc) return setConfigurationFunc(config); else return kSetConfigurationSdkNotLoaded; } void updateCamera(ansel::Camera& cam) { if (updateCameraFunc) updateCameraFunc(cam); } void stopSession() { if (stopSessionFunc) stopSessionFunc(); } void startSession() { if (startSessionFunc) startSessionFunc(); } bool isAnselAvailable() { // search for NvCamera32/64 DLL in the process const char* moduleName = #if _M_AMD64 "NvCamera64.dll"; #else "NvCamera32.dll"; #endif return GetModuleHandleA(moduleName) != nullptr; } void markHdrBufferBind(HintType hintType, uint64_t threadId) { if (markHdrBufferBindFunc) markHdrBufferBindFunc(hintType, threadId); } void markHdrBufferFinished(uint64_t threadId) { if (markHdrBufferFinishedFunc) markHdrBufferFinishedFunc(threadId); } void quaternionToRotationMatrixVectors(const nv::Quat& q, nv::Vec3& right, nv::Vec3& up, nv::Vec3& forward) { float rot[3][3]; makeRotationMatrixFromQuaternion(rot, q); right = { rot[0][0], rot[1][0], rot[2][0] }; up = { rot[0][1], rot[1][1], rot[2][1] }; forward = { rot[0][2], rot[1][2], rot[2][2] }; } void rotationMatrixVectorsToQuaternion(const nv::Vec3& right, const nv::Vec3& up, const nv::Vec3& forward, nv::Quat& q) { const float rot[3][3] = { { right.x, up.x, forward.x }, { right.y, up.y, forward.y }, { right.z, up.z, forward.z } }; makeQuaternionFromRotationMatrix(q, rot); } UserControlStatus addUserControl(const UserControlDesc& desc) { if (addUserControlFunc) return addUserControlFunc(desc); return UserControlStatus::kUserControlInvalidCallback; } UserControlStatus setUserControlLabelLocalization(uint32_t userControlId, const char* lang, const char* labelUtf8) { if (setUserControlLabelLocalizationFunc) return setUserControlLabelLocalizationFunc(userControlId, lang, labelUtf8); return UserControlStatus::kUserControlInvalidCallback; } UserControlStatus removeUserControl(uint32_t userControlId) { if (removeUserControlFunc) return removeUserControlFunc(userControlId); return UserControlStatus::kUserControlInvalidCallback; } UserControlStatus getUserControlValue(uint32_t userControlId, void* value) { if (getUserControlValueFunc) return getUserControlValueFunc(userControlId, value); return UserControlStatus::kUserControlInvalidCallback; } } DelayLoadStatus loadAnselSDKLibrary(const char* pathToLibraryUtf8) { if (anselSDK == NULL) { if (pathToLibraryUtf8) { // convert from utf8 to wchar_t: std::wstring_convert> converter; std::wstring pathWstring = converter.from_bytes(pathToLibraryUtf8); anselSDK = LoadLibraryW(pathWstring.c_str()); } else { #if defined(_M_IX86) #define ANSEL_BITNESS "32" #elif defined(_M_AMD64) #define ANSEL_BITNESS "64" #endif #if defined(_DEBUG) #define ANSEL_RUNTIME_FLAVOR "d" #else #define ANSEL_RUNTIME_FLAVOR "" #endif const char* libName = "AnselSDK" ANSEL_BITNESS ANSEL_RUNTIME_FLAVOR ".dll"; anselSDK = LoadLibraryA(libName); } if (anselSDK == NULL) return kDelayLoadDllNotFound; else return ansel::resolveFunctionPointers(); } return kDelayLoadOk; }