carb/PluginCoreUtils.h

File members: carb/PluginCoreUtils.h

// Copyright (c) 2018-2024, 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 "Defines.h"

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

#include <cstddef>
#include <cstdint>

const char* const kCarbGetFrameworkVersionFnName = "carbGetFrameworkVersion";

const char* const kCarbOnPluginRegisterFnName = "carbOnPluginRegister";

const char* const kCarbOnPluginRegisterExFnName = "carbOnPluginRegisterEx";

const char* const kCarbOnPluginRegisterEx2FnName = "carbOnPluginRegisterEx2";

const char* const kCarbOnPluginPreStartupFnName = "carbOnPluginPreStartup";

const char* const kCarbOnPluginStartupFnName = "carbOnPluginStartup";

const char* const kCarbOnPluginStartupExFnName = "carbOnPluginStartupEx";

const char* const kCarbOnPluginShutdownFnName = "carbOnPluginShutdown";

const char* const kCarbOnPluginQuickShutdownFnName = "carbOnPluginQuickShutdown";

const char* const kCarbOnPluginPostShutdownFnName = "carbOnPluginPostShutdown";

const char* const kCarbGetPluginDepsFnName = "carbGetPluginDeps";

const char* const kCarbOnReloadDependencyFnName = "carbOnReloadDependency";

namespace omni
{
namespace core
{
OMNI_DECLARE_INTERFACE(ITypeFactory) // forward declaration
}
namespace log
{
class ILog; // forward declaration
}
} // namespace omni

#define OMNI_MODULE_GLOBALS_FOR_PLUGIN()                                                                               \
    namespace                                                                                                          \
    {                                                                                                                  \
    ::omni::core::ITypeFactory* s_omniTypeFactory = nullptr;                                                           \
    ::omni::log::ILog* s_omniLog = nullptr;                                                                            \
    ::omni::structuredlog::IStructuredLog* s_omniStructuredLog = nullptr;                                              \
    }                                                                                                                  \
    OMNI_MODULE_DEFINE_LOCATION_FUNCTIONS()                                                                            \
    OMNI_MODULE_GLOBALS_BUILD_CONFIG_SYMBOLS();                                                                        \
    OMNI_API void* omniGetBuiltInWithoutAcquire(::OmniBuiltIn type)                                                    \
    {                                                                                                                  \
        switch (type)                                                                                                  \
        {                                                                                                              \
            case ::OmniBuiltIn::eITypeFactory:                                                                         \
                return s_omniTypeFactory;                                                                              \
            case ::OmniBuiltIn::eILog:                                                                                 \
                return s_omniLog;                                                                                      \
            case ::OmniBuiltIn::eIStructuredLog:                                                                       \
                return s_omniStructuredLog;                                                                            \
            default:                                                                                                   \
                return nullptr;                                                                                        \
        }                                                                                                              \
    }

#define OMNI_MODULE_SET_GLOBALS_FOR_PLUGIN(in_)                                                                        \
    s_omniTypeFactory = (in_)->omniTypeFactory;                                                                        \
    s_omniLog = (in_)->omniLog;                                                                                        \
    s_omniStructuredLog = (in_)->omniStructuredLog;

#ifndef DOXYGEN_SHOULD_SKIP_THIS

// FOR_EACH macro implementation, use as FOR_EACH(OTHER_MACRO, p0, p1, p2,)
#    define EXPAND(x) x
#    define FE_1(WHAT, X) EXPAND(WHAT(X))
#    define FE_2(WHAT, X, ...) EXPAND(WHAT(X) FE_1(WHAT, __VA_ARGS__))
#    define FE_3(WHAT, X, ...) EXPAND(WHAT(X) FE_2(WHAT, __VA_ARGS__))
#    define FE_4(WHAT, X, ...) EXPAND(WHAT(X) FE_3(WHAT, __VA_ARGS__))
#    define FE_5(WHAT, X, ...) EXPAND(WHAT(X) FE_4(WHAT, __VA_ARGS__))
#    define FE_6(WHAT, X, ...) EXPAND(WHAT(X) FE_5(WHAT, __VA_ARGS__))
#    define FE_7(WHAT, X, ...) EXPAND(WHAT(X) FE_6(WHAT, __VA_ARGS__))
#    define FE_8(WHAT, X, ...) EXPAND(WHAT(X) FE_7(WHAT, __VA_ARGS__))
#    define FE_9(WHAT, X, ...) EXPAND(WHAT(X) FE_8(WHAT, __VA_ARGS__))
#    define FE_10(WHAT, X, ...) EXPAND(WHAT(X) FE_9(WHAT, __VA_ARGS__))
#    define FE_11(WHAT, X, ...) EXPAND(WHAT(X) FE_10(WHAT, __VA_ARGS__))
#    define FE_12(WHAT, X, ...) EXPAND(WHAT(X) FE_11(WHAT, __VA_ARGS__))
#    define FE_13(WHAT, X, ...) EXPAND(WHAT(X) FE_12(WHAT, __VA_ARGS__))
#    define FE_14(WHAT, X, ...) EXPAND(WHAT(X) FE_13(WHAT, __VA_ARGS__))
#    define FE_15(WHAT, X, ...) EXPAND(WHAT(X) FE_14(WHAT, __VA_ARGS__))
#    define FE_16(WHAT, X, ...) EXPAND(WHAT(X) FE_15(WHAT, __VA_ARGS__))
#    define FE_17(WHAT, X, ...) EXPAND(WHAT(X) FE_16(WHAT, __VA_ARGS__))
#    define FE_18(WHAT, X, ...) EXPAND(WHAT(X) FE_17(WHAT, __VA_ARGS__))
#    define FE_19(WHAT, X, ...) EXPAND(WHAT(X) FE_18(WHAT, __VA_ARGS__))
#    define FE_20(WHAT, X, ...) EXPAND(WHAT(X) FE_19(WHAT, __VA_ARGS__))
#    define FE_21(WHAT, X, ...) EXPAND(WHAT(X) FE_20(WHAT, __VA_ARGS__))
#    define FE_22(WHAT, X, ...) EXPAND(WHAT(X) FE_21(WHAT, __VA_ARGS__))
#    define FE_23(WHAT, X, ...) EXPAND(WHAT(X) FE_22(WHAT, __VA_ARGS__))
#    define FE_24(WHAT, X, ...) EXPAND(WHAT(X) FE_23(WHAT, __VA_ARGS__))
#    define FE_25(WHAT, X, ...) EXPAND(WHAT(X) FE_24(WHAT, __VA_ARGS__))
#    define FE_26(WHAT, X, ...) EXPAND(WHAT(X) FE_25(WHAT, __VA_ARGS__))
#    define FE_27(WHAT, X, ...) EXPAND(WHAT(X) FE_26(WHAT, __VA_ARGS__))
#    define FE_28(WHAT, X, ...) EXPAND(WHAT(X) FE_27(WHAT, __VA_ARGS__))
#    define FE_29(WHAT, X, ...) EXPAND(WHAT(X) FE_28(WHAT, __VA_ARGS__))
#    define FE_30(WHAT, X, ...) EXPAND(WHAT(X) FE_29(WHAT, __VA_ARGS__))
#    define FE_31(WHAT, X, ...) EXPAND(WHAT(X) FE_30(WHAT, __VA_ARGS__))
#    define FE_32(WHAT, X, ...) EXPAND(WHAT(X) FE_31(WHAT, __VA_ARGS__))

//... repeat as needed
#    define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21,  \
                      _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, NAME, ...)                                \
        NAME
#    define FOR_EACH(action, ...)                                                                                      \
        EXPAND(GET_MACRO(__VA_ARGS__, FE_32, FE_31, FE_30, FE_29, FE_28, FE_27, FE_26, FE_25, FE_24, FE_23, FE_22,     \
                         FE_21, FE_20, FE_19, FE_18, FE_17, FE_16, FE_15, FE_14, FE_13, FE_12, FE_11, FE_10, FE_9,     \
                         FE_8, FE_7, FE_6, FE_5, FE_4, FE_3, FE_2, FE_1)(action, __VA_ARGS__))

#    define DECLARE_FILL_FUNCTION(X) void fillInterface(X& iface);

// carbOnPluginRegisterEx2() was added with carbonite version 0.5 without changing the carbonite version number.
// Therefore, this exists only to support older carbonite version 0.5 instances that are not aware of
// carbOnPluginRegisterEx2. This macro can be safely removed when Framework version 0.5 is no longer supported.
static_assert(carb::kFrameworkVersion.major == 0, "Remove CARB_PLUGIN_IMPL_WITH_INIT_0_5");
#    define CARB_PLUGIN_IMPL_WITH_INIT_0_5(impl, ...)                                                                  \
        FOR_EACH(DECLARE_FILL_FUNCTION, __VA_ARGS__)                                                                   \
        template <typename T1>                                                                                         \
        void fillInterface0_5(carb::PluginRegistryEntry::Interface* interfaces)                                        \
        {                                                                                                              \
            interfaces[0].desc = T1::getLatestInterfaceDesc();                                                         \
            static T1 s_pluginInterface{};                                                                             \
            fillInterface(s_pluginInterface);                                                                          \
            interfaces[0].ptr = &s_pluginInterface;                                                                    \
            interfaces[0].size = sizeof(T1);                                                                           \
        }                                                                                                              \
        template <typename T1, typename T2, typename... Types>                                                         \
        void fillInterface0_5(carb::PluginRegistryEntry::Interface* interfaces)                                        \
        {                                                                                                              \
            fillInterface0_5<T1>(interfaces);                                                                          \
            fillInterface0_5<T2, Types...>(interfaces + 1);                                                            \
        }                                                                                                              \
        template <typename... Types>                                                                                   \
        static void onPluginRegister0_5(carb::PluginFrameworkDesc* frameworkDesc, carb::PluginRegistryEntry* outEntry) \
        {                                                                                                              \
            static carb::PluginRegistryEntry::Interface s_interfaces[sizeof...(Types)] = {};                           \
            fillInterface0_5<Types...>(s_interfaces);                                                                  \
            outEntry->interfaces = s_interfaces;                                                                       \
            outEntry->interfaceCount = sizeof(s_interfaces) / sizeof(s_interfaces[0]);                                 \
            outEntry->implDesc = impl;                                                                                 \
                                                                                                                       \
            g_carbFramework = frameworkDesc->framework;                                                                \
            g_carbClientName = impl.name;                                                                              \
            OMNI_MODULE_SET_GLOBALS_FOR_PLUGIN(frameworkDesc)                                                          \
        }                                                                                                              \
        CARB_EXPORT void carbOnPluginRegisterEx(                                                                       \
            carb::PluginFrameworkDesc* frameworkDesc, carb::PluginRegistryEntry* outEntry)                             \
        {                                                                                                              \
            onPluginRegister0_5<__VA_ARGS__>(frameworkDesc, outEntry);                                                 \
        }

#    define CARB_PLUGIN_IMPL_WITH_INIT_0_5_EX(impl, ...)                                                                                                   \
        template <typename T1>                                                                                                                             \
        void fillInterface0_5(carb::PluginRegistryEntry::Interface* interfaces)                                                                            \
        {                                                                                                                                                  \
            interfaces->desc = T1::getLatestInterfaceDesc();                                                                                               \
            static void* s_pluginInterface[(sizeof(T1) / sizeof(void*)) + 1] = {};                                                                         \
            carb::Version ver = interfaces->desc.version;                                                                                                  \
            bool b = fillInterface<T1>(&ver, s_pluginInterface);                                                                                           \
            CARB_FATAL_UNLESS(b, "Failed to construct interface for type %s", interfaces->desc.name);                                                      \
            CARB_FATAL_UNLESS(                                                                                                                             \
                ver == interfaces->desc.version,                                                                                                           \
                "Interface %s constructor requested version %u.%u but got %u.%u (must match exactly as the interface declared itself to be this version)", \
                interfaces[0].desc.name, interfaces->desc.version.major, interfaces->desc.version.minor, ver.major,                                        \
                ver.minor);                                                                                                                                \
            interfaces->ptr = &s_pluginInterface;                                                                                                          \
            interfaces->size = sizeof(T1);                                                                                                                 \
        }                                                                                                                                                  \
        template <typename T1, typename T2, typename... Types>                                                                                             \
        void fillInterface0_5(carb::PluginRegistryEntry::Interface* interfaces)                                                                            \
        {                                                                                                                                                  \
            fillInterface0_5<T1>(interfaces);                                                                                                              \
            fillInterface0_5<T2, Types...>(interfaces + 1);                                                                                                \
        }                                                                                                                                                  \
        template <typename... Types>                                                                                                                       \
        static void onPluginRegister0_5(carb::PluginFrameworkDesc* frameworkDesc, carb::PluginRegistryEntry* outEntry)                                     \
        {                                                                                                                                                  \
            static carb::PluginRegistryEntry::Interface s_interfaces[sizeof...(Types)];                                                                    \
            fillInterface0_5<Types...>(s_interfaces);                                                                                                      \
            outEntry->interfaces = s_interfaces;                                                                                                           \
            outEntry->interfaceCount = sizeof(s_interfaces) / sizeof(s_interfaces[0]);                                                                     \
            outEntry->implDesc = impl;                                                                                                                     \
                                                                                                                                                           \
            g_carbFramework = frameworkDesc->framework;                                                                                                    \
            g_carbClientName = impl.name;                                                                                                                  \
            OMNI_MODULE_SET_GLOBALS_FOR_PLUGIN(frameworkDesc)                                                                                              \
        }                                                                                                                                                  \
        CARB_EXPORT void carbOnPluginRegisterEx(                                                                                                           \
            carb::PluginFrameworkDesc* frameworkDesc, carb::PluginRegistryEntry* outEntry)                                                                 \
        {                                                                                                                                                  \
            onPluginRegister0_5<__VA_ARGS__>(frameworkDesc, outEntry);                                                                                     \
        }

#endif // DOXYGEN_SHOULD_SKIP_THIS

#define CARB_PLUGIN_IMPL_WITH_INIT(impl, ...)                                                                          \
                                                                                                                       \
    /* Forward declare fill functions for every interface */                                                           \
    FOR_EACH(DECLARE_FILL_FUNCTION, __VA_ARGS__)                                                                       \
                                                                                                                       \
    template <typename T1>                                                                                             \
    void populate(carb::PluginRegistryEntry2::Interface2* iface)                                                       \
    {                                                                                                                  \
        iface->sizeofThisStruct = sizeof(carb::PluginRegistryEntry2::Interface2);                                      \
        iface->desc = T1::getLatestInterfaceDesc();                                                                    \
        iface->size = sizeof(T1);                                                                                      \
        iface->align = alignof(T1);                                                                                    \
        iface->Constructor = [](void* p) { fillInterface(*new (p) T1); };                                              \
        iface->Destructor = [](void* p) { static_cast<T1*>(p)->~T1(); };                                               \
    }                                                                                                                  \
                                                                                                                       \
    template <typename T1, typename T2, typename... Types>                                                             \
    void populate(carb::PluginRegistryEntry2::Interface2* interfaces)                                                  \
    {                                                                                                                  \
        populate<T1>(interfaces);                                                                                      \
        populate<T2, Types...>(interfaces + 1);                                                                        \
    }                                                                                                                  \
                                                                                                                       \
    template <typename... Types>                                                                                       \
    static void registerPlugin(carb::PluginFrameworkDesc* frameworkDesc, carb::PluginRegistryEntry2* outEntry)         \
    {                                                                                                                  \
        outEntry->sizeofThisStruct = sizeof(carb::PluginRegistryEntry2);                                               \
        static carb::PluginRegistryEntry2::Interface2 s_interfaces[sizeof...(Types)] = {};                             \
        populate<Types...>(s_interfaces);                                                                              \
        outEntry->interfaces = s_interfaces;                                                                           \
        outEntry->interfaceCount = CARB_COUNTOF(s_interfaces);                                                         \
        outEntry->implDesc = impl;                                                                                     \
                                                                                                                       \
        g_carbFramework = frameworkDesc->framework;                                                                    \
        g_carbClientName = impl.name;                                                                                  \
        OMNI_MODULE_SET_GLOBALS_FOR_PLUGIN(frameworkDesc)                                                              \
    }                                                                                                                  \
                                                                                                                       \
    CARB_EXPORT void carbOnPluginRegisterEx2(                                                                          \
        carb::PluginFrameworkDesc* frameworkDesc, carb::PluginRegistryEntry2* outEntry)                                \
    {                                                                                                                  \
        registerPlugin<__VA_ARGS__>(frameworkDesc, outEntry);                                                          \
    }                                                                                                                  \
                                                                                                                       \
    CARB_EXPORT carb::Version carbGetFrameworkVersion()                                                                \
    {                                                                                                                  \
        return carb::kFrameworkVersion;                                                                                \
    }

#define CARB_PLUGIN_IMPL_WITH_INIT_EX(impl, ...)                                                                       \
    /* forward declare fillInterface function */                                                                       \
    template <class T1>                                                                                                \
    bool fillInterface(carb::Version*, void*);                                                                         \
    template <class T1>                                                                                                \
    void destroyInterface(carb::Version, void*)                                                                        \
    {                                                                                                                  \
    }                                                                                                                  \
                                                                                                                       \
    template <typename T1>                                                                                             \
    void populate(carb::PluginRegistryEntry2::Interface2* iface)                                                       \
    {                                                                                                                  \
        iface->sizeofThisStruct = sizeof(carb::PluginRegistryEntry2::Interface2);                                      \
        iface->desc = T1::getLatestInterfaceDesc();                                                                    \
        iface->size = sizeof(T1);                                                                                      \
        iface->align = alignof(T1);                                                                                    \
        iface->Constructor = nullptr;                                                                                  \
        iface->Destructor = nullptr;                                                                                   \
        iface->VersionedConstructor = &fillInterface<T1>;                                                              \
        iface->VersionedDestructor = &destroyInterface<T1>;                                                            \
    }                                                                                                                  \
                                                                                                                       \
    template <typename T1, typename T2, typename... Types>                                                             \
    void populate(carb::PluginRegistryEntry2::Interface2* interfaces)                                                  \
    {                                                                                                                  \
        populate<T1>(interfaces);                                                                                      \
        populate<T2, Types...>(interfaces + 1);                                                                        \
    }                                                                                                                  \
                                                                                                                       \
    template <typename... Types>                                                                                       \
    static void registerPlugin(carb::PluginFrameworkDesc* frameworkDesc, carb::PluginRegistryEntry2* outEntry)         \
    {                                                                                                                  \
        outEntry->sizeofThisStruct = sizeof(carb::PluginRegistryEntry2);                                               \
        static carb::PluginRegistryEntry2::Interface2 s_interfaces[sizeof...(Types)] = {};                             \
        populate<Types...>(s_interfaces);                                                                              \
        outEntry->interfaces = s_interfaces;                                                                           \
        outEntry->interfaceCount = CARB_COUNTOF(s_interfaces);                                                         \
        outEntry->implDesc = impl;                                                                                     \
                                                                                                                       \
        g_carbFramework = frameworkDesc->framework;                                                                    \
        g_carbClientName = impl.name;                                                                                  \
        OMNI_MODULE_SET_GLOBALS_FOR_PLUGIN(frameworkDesc)                                                              \
    }                                                                                                                  \
                                                                                                                       \
    CARB_EXPORT void carbOnPluginRegisterEx2(                                                                          \
        carb::PluginFrameworkDesc* frameworkDesc, carb::PluginRegistryEntry2* outEntry)                                \
    {                                                                                                                  \
        registerPlugin<__VA_ARGS__>(frameworkDesc, outEntry);                                                          \
    }                                                                                                                  \
                                                                                                                       \
    CARB_EXPORT carb::Version carbGetFrameworkVersion()                                                                \
    {                                                                                                                  \
        return carb::kFrameworkVersion;                                                                                \
    }

#if CARB_COMPILER_MSC
#    pragma section(".state", read, write)
#endif

#define CARB_STATE                                                                                                     \
    CARB_DEPRECATED("hot reload has been removed") CARB_DECLSPEC(allocate(".state")) CARB_ATTRIBUTE(section(".state"))

// The below is for documentation only
#ifdef DOXYGEN_BUILD
CARB_EXPORT carb::Version carbGetFrameworkVersion();

CARB_EXPORT void carbOnPluginRegister(carb::Framework* framework, carb::PluginRegistryEntry* outEntry);

CARB_EXPORT void carbOnPluginRegisterEx(carb::PluginFrameworkDesc* frameworkDesc, carb::PluginRegistryEntry* outEntry);

CARB_EXPORT void carbOnPluginRegisterEx2(carb::PluginFrameworkDesc* frameworkDesc, carb::PluginRegistryEntry2* outEntry);

CARB_EXPORT void carbOnPluginPreStartup();

CARB_EXPORT void carbOnPluginStartup();

CARB_EXPORT bool carbOnPluginStartupEx();

CARB_EXPORT void carbOnPluginShutdown();

CARB_EXPORT void carbOnPluginQuickShutdown();

CARB_EXPORT void carbOnPluginPostShutdown();

CARB_EXPORT void carbGetPluginDeps(struct carb::InterfaceDesc** deps, size_t* count);

CARB_EXPORT void carbOnReloadDependency(carb::PluginReloadState reloadState,
                                        void* pluginInterface,
                                        carb::PluginImplDesc desc);

struct InterfaceType
{
    CARB_PLUGIN_INTERFACE("carb::InterfaceType", 1, 0);
};

void fillInterface(InterfaceType& iface);

template <class T>
bool fillInterface(carb::Version* v, void* buf);

template <class T>
void destroyInterface(Version v, void* buf);
#endif