carb/ClientUtils.h

File members: carb/ClientUtils.h

// Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, 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.
//

#pragma once

#include "Framework.h"
#include "assert/AssertUtils.h"
#include "crashreporter/CrashReporterUtils.h"
#include "l10n/L10nUtils.h"
#include "logging/Log.h"
#include "logging/StandardLogger.h"
#include "profiler/Profile.h"

#include "../omni/core/Omni.h"

#include <vector>

namespace carb
{

#ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace detail
{
inline void registerBuiltinFileSystem(Framework* f)
{
    f->registerPlugin(g_carbClientName, f->getBuiltinFileSystemDesc());
}

inline void registerBuiltinLogging(Framework* f)
{
    f->registerPlugin(g_carbClientName, f->getBuiltinLoggingDesc());
}

inline void registerBuiltinAssert(Framework* f)
{
    f->registerPlugin(g_carbClientName, f->getBuiltinAssertDesc());
}

inline void registerBuiltinThreadUtil(Framework* f)
{
    f->registerPlugin(g_carbClientName, f->getBuiltinThreadUtilDesc());
}

inline void registerAtexitHandler()
{
#    if CARB_PLATFORM_WINDOWS && !defined _DLL
    // Since we're not using the dynamic runtime, we need to notify carb.dll if the executable's atexit() functions run.
    // We only do this if this is compiled into the executable here, so check that
    auto exeHandle = GetModuleHandleW(NULL);
    HMODULE myHandle;
    if (GetModuleHandleExW(
            CARBWIN_GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | CARBWIN_GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
            (LPCWSTR)&registerAtexitHandler, &myHandle) &&
        myHandle == exeHandle)
    {
        // Verified that this function is compiled into the executable and without dynamic runtime.
        auto carbHandle = GetModuleHandleW(L"carb.dll");
        auto proc = (void (*)(void*))(carbHandle ? GetProcAddress(carbHandle, "carbControlAtexit") : nullptr);
        if (proc)
        {
            // Call our undocumented function and pass our atexit() function so that carb.dll can register a callback
            // to know when the first-chance (executable) atexit happens.
            proc((void*)&atexit);
        }
    }
#    endif
}
} // namespace detail
#endif

inline Framework* acquireFrameworkAndRegisterBuiltins(const OmniCoreStartArgs* args = nullptr)
{
    // Acquire framework and set into global variable
    Framework* framework = acquireFramework(g_carbClientName);
    if (framework)
    {
        g_carbFramework = framework;

        static_assert(
            kFrameworkVersion.major == 0,
            "The framework automatically registers builtins now; the registerXXX functions can be removed once the framework version changes.");

        detail::registerAtexitHandler();

        // Starting up logging
        detail::registerBuiltinLogging(framework);
        logging::registerLoggingForClient();

        // Starting up filesystem
        detail::registerBuiltinFileSystem(framework);
        detail::registerBuiltinAssert(framework);
        detail::registerBuiltinThreadUtil(framework);

        // grab the assertion helper interface.
        assert::registerAssertForClient();

        // grab the l10n interface.
        l10n::registerLocalizationForClient();

        // start up ONI
        OMNI_CORE_START(args);
    }
    return framework;
}

inline void releaseFrameworkAndDeregisterBuiltins()
{
    if (isFrameworkValid())
    {
        logging::deregisterLoggingForClient();
        assert::deregisterAssertForClient();
        l10n::deregisterLocalizationForClient();
        // Release structured log before unloading plugins
        omniReleaseStructuredLog();
        g_carbFramework->unloadAllPlugins();
        OMNI_CORE_STOP();
        releaseFramework();
    }
    g_carbFramework = nullptr;
}

} // namespace carb

#define CARB_GLOBALS(clientName) CARB_GLOBALS_EX(clientName, nullptr)

#define CARB_GLOBALS_EX(clientName, clientDescription)                                                                 \
    CARB_FRAMEWORK_GLOBALS(clientName)                                                                                 \
    CARB_LOG_GLOBALS()                                                                                                 \
    CARB_PROFILER_GLOBALS()                                                                                            \
    CARB_ASSERT_GLOBALS()                                                                                              \
    CARB_LOCALIZATION_GLOBALS()                                                                                        \
    CARB_CRASH_REPORTER_GLOBALS()                                                                                      \
    OMNI_GLOBALS_ADD_DEFAULT_CHANNEL(clientName, clientDescription)