omni/core/ModuleExports.h
File members: omni/core/ModuleExports.h
// Copyright (c) 2020-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 "IObject.h"
#include "../../carb/Interface.h"
#include <algorithm>
#include <cstring>
#include <type_traits>
namespace omni
{
namespace log
{
class ILog;
}
namespace structuredlog
{
class IStructuredLog;
using SchemaAddFn = bool (*)(IStructuredLog* log);
} // namespace structuredlog
namespace core
{
constexpr const char* const kModuleExportEntryTypeOnModuleLoad = "omniOnModuleLoad";
constexpr const char* const kModuleExportEntryTypeOnModuleStarted = "omniOnModuleStarted";
constexpr const char* const kModuleExportEntryTypeOnModuleCanUnload = "omniOnModuleCanUnload";
constexpr const char* const kModuleExportEntryTypeOnModuleUnload = "omniOnModuleUnload";
constexpr const char* const kModuleExportEntryTypeITypeFactory = "omniITypeFactory";
constexpr const char* const kModuleExportEntryTypeILog = "omniILog";
constexpr const char* const kModuleExportEntryTypeLogChannel = "omniLogChannel";
constexpr const char* const kModuleExportEntryTypeIStructuredLog = "omniIStructuredLog";
constexpr const char* const kModuleExportEntryTypeSchema = "omniSchema";
constexpr const char* const kModuleExportEntryTypeCarbClientName = "carbClientName";
constexpr const char* const kModuleExportEntryTypeCarbFramework = "carbFramework";
constexpr const char* const kModuleExportEntryTypeCarbIAssert = "carbIAssert";
constexpr const char* const kModuleExportEntryTypeCarbILogging = "carbILogging";
constexpr const char* const kModuleExportEntryTypeCarbIProfiler = "carbIProfiler";
constexpr const char* const kModuleExportEntryTypeCarbIL10n = "carbIL10n";
constexpr const char* const kModuleExportEntryTypeGetModuleDependencies = "omniGetModuleDependecies";
using ModuleExportEntryFlag = uint32_t;
constexpr ModuleExportEntryFlag fModuleExportEntryFlagNone = 0;
constexpr ModuleExportEntryFlag fModuleExportEntryFlagRequired = (1 << 0);
#define OMNI_MODULE_EXPORT_ENTRY_BEGIN(name_) \
struct name_ \
{ \
\
const char* type; \
\
ModuleExportEntryFlag flags; \
\
uint32_t byteCount; \
\
\
name_(const char* t, ModuleExportEntryFlag f) \
{ \
type = t; \
flags = f; \
byteCount = sizeof(*this); \
};
#define OMNI_MODULE_EXPORT_ENTRY_END(name_) \
} \
; \
CARB_ASSERT_INTEROP_SAFE(name_);
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntry)
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntry)
static_assert(sizeof(ModuleExportEntry) == (8 + sizeof(void*)), "unexpected ModuleExportEntry size");
struct InterfaceImplementation;
using OnModuleLoadFn = Result(const InterfaceImplementation** out, uint32_t* outCount);
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryOnModuleLoad)
OnModuleLoadFn* onModuleLoad;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryOnModuleLoad)
#define OMNI_MODULE_ON_MODULE_LOAD(exp_, fn_) OMNI_RETURN_IF_FAILED(exp_->addOnModuleLoad(fn_))
using OnModuleStartedFn = void();
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryOnModuleStarted)
OnModuleStartedFn* onModuleStarted;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryOnModuleStarted)
#define OMNI_MODULE_ON_MODULE_STARTED(exp_, fn_) OMNI_RETURN_IF_FAILED(exp_->addOnModuleStarted(fn_))
using OnModuleCanUnloadFn = bool();
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryOnModuleCanUnload)
OnModuleCanUnloadFn* onModuleCanUnload;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryOnModuleCanUnload)
#define OMNI_MODULE_ON_MODULE_CAN_UNLOAD(exp_, fn_) OMNI_RETURN_IF_FAILED(exp_->addOnModuleCanUnload(fn_))
using OnModuleUnloadFn = void();
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryOnModuleUnload)
OnModuleUnloadFn* onModuleUnload;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryOnModuleUnload)
#define OMNI_MODULE_ON_MODULE_UNLOAD(exp_, fn_) OMNI_RETURN_IF_FAILED(exp_->addOnModuleUnload(fn_))
OMNI_DECLARE_INTERFACE(ITypeFactory)
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryITypeFactory)
ITypeFactory** typeFactory;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryITypeFactory)
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryILog)
log::ILog** log;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryILog)
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryLogChannel)
const char* name;
int32_t* level;
const char* description;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryLogChannel)
#define OMNI_MODULE_ADD_LOG_CHANNEL(exp_, name_, level_, description_) \
OMNI_RETURN_IF_FAILED(exp_->addLogChannel(name_, level_, description_))
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryCarbClientName)
const char* clientName;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryCarbClientName)
#define OMNI_MODULE_REQUIRE_CARB_CLIENT_NAME(exp_) \
OMNI_RETURN_IF_FAILED(out->requireExport(omni::core::kModuleExportEntryTypeCarbClientName))
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryIStructuredLog)
omni::structuredlog::IStructuredLog** structuredLog;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryIStructuredLog)
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntrySchema)
omni::structuredlog::SchemaAddFn schemaAddFn;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntrySchema)
#define OMNI_MODULE_ADD_STRUCTURED_LOG_SCHEMA(exp_, fn_) OMNI_RETURN_IF_FAILED(exp_->addStructuredLogSchema(fn_))
} // namespace core
} // namespace omni
namespace carb
{
struct Framework;
namespace assert
{
struct IAssert;
} // namespace assert
namespace logging
{
struct ILogging;
} // namespace logging
namespace profiler
{
struct IProfiler;
} // namespace profiler
namespace l10n
{
struct IL10n;
struct LanguageTable;
struct LanguageIdentifier;
} // namespace l10n
} // namespace carb
namespace omni
{
namespace core
{
#ifndef DOXYGEN_BUILD
namespace detail
{
using CarbLogFn = void (*)(const char* source,
int32_t level,
const char* fileName,
const char* functionName,
int lineNumber,
const char* fmt,
...);
using CarbLogLevelFn = void(int32_t);
using CarbLocalizeStringFn = const char*(CARB_ABI*)(const carb::l10n::LanguageTable* table,
uint64_t id,
const carb::l10n::LanguageIdentifier* language);
} // namespace detail
#endif
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryCarbFramework)
carb::Framework** framework;
carb::Version version;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryCarbFramework)
#define OMNI_MODULE_REQUIRE_CARB_FRAMEWORK(exp_) \
OMNI_RETURN_IF_FAILED(out->requireExport(omni::core::kModuleExportEntryTypeCarbFramework))
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryCarbIAssert)
carb::assert::IAssert** assert;
carb::InterfaceDesc interfaceDesc;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryCarbIAssert)
#define OMNI_MODULE_REQUIRE_CARB_IASSERT(exp_) \
OMNI_RETURN_IF_FAILED(out->requireExport(omni::core::kModuleExportEntryTypeCarbIAssert))
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryCarbILogging)
carb::logging::ILogging** logging;
detail::CarbLogFn* logFn;
detail::CarbLogLevelFn* logLevelFn;
int32_t* logLevel;
carb::InterfaceDesc interfaceDesc;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryCarbILogging)
#define OMNI_MODULE_REQUIRE_CARB_ILOGGING(exp_) \
OMNI_RETURN_IF_FAILED(out->requireExport(omni::core::kModuleExportEntryTypeCarbILogging))
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryCarbIProfiler)
std::atomic<carb::profiler::IProfiler*>* profiler;
carb::InterfaceDesc interfaceDesc;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryCarbIProfiler)
#define OMNI_MODULE_REQUIRE_CARB_IPROFILER(exp_) \
OMNI_RETURN_IF_FAILED(out->requireExport(omni::core::kModuleExportEntryTypeCarbIProfiler))
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryCarbIL10n)
carb::l10n::IL10n** localization;
detail::CarbLocalizeStringFn* localizationFn;
carb::InterfaceDesc interfaceDesc;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryCarbIL10n)
using GetModuleDependenciesFn = Result(carb::InterfaceDesc** out, size_t* outCount);
OMNI_MODULE_EXPORT_ENTRY_BEGIN(ModuleExportEntryGetModuleDependencies)
GetModuleDependenciesFn* getModuleDependencies;
OMNI_MODULE_EXPORT_ENTRY_END(ModuleExportEntryGetModuleDependencies)
#define OMNI_MODULE_GET_MODULE_DEPENDENCIES(exp_, fn_) OMNI_RETURN_IF_FAILED(exp_->addGetModuleDependencies(fn_))
#define OMNI_MODULE_REQUIRE_CARB_IL10N(exp_) \
OMNI_RETURN_IF_FAILED(out->requireExport(omni::core::kModuleExportEntryTypeCarbIL10n))
constexpr uint16_t kModuleExportsMagic = 0x766e; // { 'n', 'v' }
constexpr uint16_t kModuleExportsVersion = 1;
struct ModuleExports
{
uint16_t magic;
uint16_t version;
uint32_t byteCount;
uint8_t* exportsBegin;
uint8_t* exportsEnd;
Result checkVersion(uint16_t moduleMagic, uint16_t moduleVersion)
{
// we can't log here, since we're to early in the module load process for logging to be available. pass back the
// magic number and version we were expecting so omni::core::ITypeFactory can print an appropriate message if
// the checks below fail.
std::swap(magic, moduleMagic);
std::swap(version, moduleVersion);
if (magic != moduleMagic)
{
return kResultVersionParseError;
}
if (version != moduleVersion)
{
return kResultVersionCheckFailure;
}
return kResultSuccess;
}
Result add(const ModuleExportEntry* entry)
{
uint32_t neededSize = uint32_t(exportsEnd - exportsBegin) + uint32_t(sizeof(ModuleExports)) + entry->byteCount;
if (neededSize > byteCount)
{
return kResultInsufficientBuffer;
}
std::memcpy(exportsEnd, entry, entry->byteCount);
exportsEnd += entry->byteCount;
return kResultSuccess;
}
ModuleExportEntry* find(const char* type)
{
if (!type)
{
return nullptr;
}
uint8_t* p = exportsBegin;
while (p < exportsEnd)
{
auto entry = reinterpret_cast<ModuleExportEntry*>(p);
if (0 == strcmp(type, entry->type))
{
return entry;
}
p += entry->byteCount;
}
return nullptr;
}
Result requireExport(const char* type)
{
auto entry = find(type);
if (entry)
{
entry->flags |= fModuleExportEntryFlagRequired;
return kResultSuccess;
}
return kResultNotFound;
}
Result addOnModuleLoad(OnModuleLoadFn* fn, ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryOnModuleLoad entry{ kModuleExportEntryTypeOnModuleLoad, flags };
entry.onModuleLoad = fn;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addOnModuleStarted(OnModuleStartedFn* fn, ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryOnModuleStarted entry{ kModuleExportEntryTypeOnModuleStarted, flags };
entry.onModuleStarted = fn;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addOnModuleCanUnload(OnModuleCanUnloadFn* fn, ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryOnModuleCanUnload entry{ kModuleExportEntryTypeOnModuleCanUnload, flags };
entry.onModuleCanUnload = fn;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addOnModuleUnload(OnModuleUnloadFn* fn, ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryOnModuleUnload entry{ kModuleExportEntryTypeOnModuleUnload, flags };
entry.onModuleUnload = fn;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addITypeFactory(ITypeFactory** typeFactory, ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryITypeFactory entry{ kModuleExportEntryTypeITypeFactory, flags };
entry.typeFactory = typeFactory;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addILog(log::ILog** log, ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryILog entry{ kModuleExportEntryTypeILog, flags };
entry.log = log;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addLogChannel(const char* channelName,
int32_t* level,
const char* description,
ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryLogChannel entry{ kModuleExportEntryTypeLogChannel, flags };
entry.name = channelName;
entry.level = level;
entry.description = description;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addIStructuredLog(omni::structuredlog::IStructuredLog** strucLog,
ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryIStructuredLog entry{ kModuleExportEntryTypeIStructuredLog, flags };
entry.structuredLog = strucLog;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addStructuredLogSchema(omni::structuredlog::SchemaAddFn fn,
ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntrySchema entry{ kModuleExportEntryTypeSchema, flags };
entry.schemaAddFn = fn;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addCarbClientName(const char* clientName, ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryCarbClientName entry{ kModuleExportEntryTypeCarbClientName, flags };
entry.clientName = clientName;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addCarbFramework(carb::Framework** carbFramework,
const carb::Version& ver,
ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryCarbFramework entry{ kModuleExportEntryTypeCarbFramework, flags };
entry.framework = carbFramework;
entry.version = ver;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addCarbIAssert(carb::assert::IAssert** assert,
const carb::InterfaceDesc& interfaceDesc,
ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryCarbIAssert entry{ kModuleExportEntryTypeCarbIAssert, flags };
entry.assert = assert;
entry.interfaceDesc = interfaceDesc;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addCarbILogging(carb::logging::ILogging** logging,
detail::CarbLogFn* logFn,
detail::CarbLogLevelFn* logLevelFn,
int32_t* logLevel,
const carb::InterfaceDesc& interfaceDesc,
ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryCarbILogging entry{ kModuleExportEntryTypeCarbILogging, flags };
entry.logging = logging;
entry.logFn = logFn;
entry.logLevelFn = logLevelFn;
entry.logLevel = logLevel;
entry.interfaceDesc = interfaceDesc;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addCarbIProfiler(std::atomic<carb::profiler::IProfiler*>* profiler,
const carb::InterfaceDesc& interfaceDesc,
ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryCarbIProfiler entry{ kModuleExportEntryTypeCarbIProfiler, flags };
entry.profiler = profiler;
entry.interfaceDesc = interfaceDesc;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addCarbIL10n(carb::l10n::IL10n** localization,
detail::CarbLocalizeStringFn* localizationFn,
const carb::InterfaceDesc& interfaceDesc,
ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryCarbIL10n entry{ kModuleExportEntryTypeCarbIL10n, flags };
entry.localization = localization;
entry.localizationFn = localizationFn;
entry.interfaceDesc = interfaceDesc;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
Result addGetModuleDependencies(GetModuleDependenciesFn* fn, ModuleExportEntryFlag flags = fModuleExportEntryFlagNone)
{
ModuleExportEntryGetModuleDependencies entry{ kModuleExportEntryTypeGetModuleDependencies, flags };
entry.getModuleDependencies = fn;
return add(reinterpret_cast<ModuleExportEntry*>(&entry));
}
};
CARB_ASSERT_INTEROP_SAFE(ModuleExports);
static_assert(sizeof(ModuleExports) == (8 + (2 * sizeof(void*))),
"unexpected ModuleExports size. do not change ModuleExports?");
using ModuleGetExportsFn = Result(ModuleExports* out);
constexpr const char* const kModuleGetExportsName = "omniModuleGetExports";
} // namespace core
} // namespace omni
#ifdef DOXYGEN_BUILD
omni::core::Result omniModuleGetExports(omni::core::ModuleExports* out);
#endif