/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "render_context.h"
#include
#include
#include
#include
#include
#if (RENDER_PERF_ENABLED == 1)
#include
#endif
#include "datastore/render_data_store_default_acceleration_structure_staging.h"
#include "datastore/render_data_store_default_gpu_resource_data_copy.h"
#include "datastore/render_data_store_default_staging.h"
#include "datastore/render_data_store_manager.h"
#include "datastore/render_data_store_pod.h"
#include "datastore/render_data_store_post_process.h"
#include "datastore/render_data_store_shader_passes.h"
#include "default_engine_constants.h"
#include "device/device.h"
#include "device/shader_manager.h"
#include "loader/render_data_loader.h"
#include "node/core_render_node_factory.h"
#include "nodecontext/render_node_graph_manager.h"
#include "nodecontext/render_node_graph_node_store.h"
#include "nodecontext/render_node_manager.h"
#include "nodecontext/render_node_post_process_util.h"
#include "renderer.h"
#include "util/render_util.h"
#if RENDER_HAS_VULKAN_BACKEND
#include "vulkan/device_vk.h"
#endif
#if (RENDER_HAS_GL_BACKEND) || (RENDER_HAS_GLES_BACKEND)
#include "gles/device_gles.h"
#include "gles/swapchain_gles.h"
#endif
#include
using namespace BASE_NS;
using namespace CORE_NS;
RENDER_BEGIN_NAMESPACE()
namespace {
struct RegisterPathStrings {
string_view protocol;
string_view uri;
};
static constexpr RegisterPathStrings RENDER_DATA_PATHS[] = {
{ "rendershaders", "rofsRndr://shaders/" },
{ "rendershaderstates", "rofsRndr://shaderstates/" },
{ "rendervertexinputdeclarations", "rofsRndr://vertexinputdeclarations/" },
{ "renderpipelinelayouts", "rofsRndr://pipelinelayouts/" },
{ "renderrenderdataconfigurations", "rofsRndr://renderdataconfigurations/" },
{ "renderrendernodegraphs", "rofsRndr://rendernodegraphs/" },
};
#if (RENDER_EMBEDDED_ASSETS_ENABLED == 1)
// Core Rofs Data.
extern "C" const uint64_t SIZEOFDATAFORRENDER;
extern "C" const void* const BINARYDATAFORRENDER[];
#endif
// This is defined in the CMake generated version.cpp
void LogRenderBuildInfo()
{
#define RENDER_TO_STRING_INTERNAL(x) #x
#define RENDER_TO_STRING(x) RENDER_TO_STRING_INTERNAL(x)
PLUGIN_LOG_I("RENDER_VALIDATION_ENABLED=" RENDER_TO_STRING(RENDER_VALIDATION_ENABLED));
PLUGIN_LOG_I("RENDER_DEV_ENABLED=" RENDER_TO_STRING(RENDER_DEV_ENABLED));
}
template
RenderDataStoreTypeInfo FillRenderDataStoreTypeInfo()
{
return {
{ RenderDataStoreTypeInfo::UID },
RenderDataStoreType::UID,
RenderDataStoreType::TYPE_NAME,
RenderDataStoreType::Create,
RenderDataStoreType::Destroy,
};
}
void RegisterCoreRenderDataStores(RenderDataStoreManager& renderDataStoreManager)
{
renderDataStoreManager.AddRenderDataStoreFactory(FillRenderDataStoreTypeInfo());
renderDataStoreManager.AddRenderDataStoreFactory(
FillRenderDataStoreTypeInfo());
renderDataStoreManager.AddRenderDataStoreFactory(FillRenderDataStoreTypeInfo());
renderDataStoreManager.AddRenderDataStoreFactory(
FillRenderDataStoreTypeInfo());
renderDataStoreManager.AddRenderDataStoreFactory(FillRenderDataStoreTypeInfo());
renderDataStoreManager.AddRenderDataStoreFactory(FillRenderDataStoreTypeInfo());
}
template
IRenderDataStore* CreateDataStore(IRenderDataStoreManager& renderDataStoreManager, const string_view name)
{
IRenderDataStore* renderDataStore = renderDataStoreManager.Create(DataStoreType::UID, name.data());
PLUGIN_ASSERT(renderDataStore);
return renderDataStore;
}
void CreateDefaultRenderDataStores(IRenderDataStoreManager& renderDataStoreManager, RenderDataLoader& renderDataLoader)
{
// add pod store
{
auto renderDataStorePod =
CreateDataStore(renderDataStoreManager, RenderDataStorePod::TYPE_NAME);
if (renderDataStorePod) {
IRenderDataStorePod* renderDataStorePodTyped = static_cast(renderDataStorePod);
NodeGraphBackBufferConfiguration backBufferConfig {};
const auto len =
DefaultEngineGpuResourceConstants::CORE_DEFAULT_BACKBUFFER.copy(backBufferConfig.backBufferName,
NodeGraphBackBufferConfiguration::CORE_MAX_BACK_BUFFER_NAME_LENGTH - 1);
backBufferConfig.backBufferName[len] = '\0';
renderDataStorePodTyped->CreatePod(
"NodeGraphConfiguration", "NodeGraphBackBufferConfiguration", arrayviewU8(backBufferConfig));
// load and store configurations
renderDataLoader.Load("render", *renderDataStorePodTyped);
}
}
CreateDataStore(
renderDataStoreManager, RenderDataStoreDefaultAccelerationStructureStaging::TYPE_NAME);
CreateDataStore(renderDataStoreManager, RenderDataStoreDefaultStaging::TYPE_NAME);
CreateDataStore(
renderDataStoreManager, RenderDataStoreDefaultGpuResourceDataCopy::TYPE_NAME);
CreateDataStore(renderDataStoreManager, RenderDataStoreShaderPasses::TYPE_NAME);
CreateDataStore(renderDataStoreManager, RenderDataStorePostProcess::TYPE_NAME);
}
void CreateDefaultBuffers(IGpuResourceManager& gpuResourceMgr, vector& defaultGpuResources)
{
defaultGpuResources.push_back(gpuResourceMgr.Create(DefaultEngineGpuResourceConstants::CORE_DEFAULT_GPU_BUFFER,
GpuBufferDesc { CORE_BUFFER_USAGE_TRANSFER_SRC_BIT | CORE_BUFFER_USAGE_TRANSFER_DST_BIT |
CORE_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | CORE_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT | CORE_BUFFER_USAGE_STORAGE_BUFFER_BIT |
CORE_BUFFER_USAGE_INDEX_BUFFER_BIT | CORE_BUFFER_USAGE_VERTEX_BUFFER_BIT |
CORE_BUFFER_USAGE_INDIRECT_BUFFER_BIT | CORE_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT |
CORE_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT,
(CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), 0u, 1024u }));
}
void CreateDefaultTextures(IGpuResourceManager& gpuResourceMgr, vector& defaultGpuResources)
{
GpuImageDesc desc { ImageType::CORE_IMAGE_TYPE_2D, ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,
Format::BASE_FORMAT_R8G8B8A8_UNORM, ImageTiling::CORE_IMAGE_TILING_OPTIMAL,
ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT | ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSFER_DST_BIT,
MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
0, // ImageCreateFlags
0, // EngineImageCreationFlags
2, 2, 1, 1, 1, SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT, {} };
constexpr uint32_t sizeOfUint32 = sizeof(uint32_t);
constexpr const uint32_t rgbData[4u] = { 0x0, 0x0, 0x0, 0x0 };
const auto rgbDataView = array_view(reinterpret_cast(rgbData), sizeOfUint32 * countof(rgbData));
defaultGpuResources.push_back(
gpuResourceMgr.Create(DefaultEngineGpuResourceConstants::CORE_DEFAULT_GPU_IMAGE, desc, rgbDataView));
constexpr const uint32_t rgbDataWhite[4u] = { 0xFFFFffff, 0xFFFFffff, 0xFFFFffff, 0xFFFFffff };
const auto rgbDataViewWhite =
array_view(reinterpret_cast(rgbDataWhite), sizeOfUint32 * countof(rgbDataWhite));
defaultGpuResources.push_back(
gpuResourceMgr.Create(DefaultEngineGpuResourceConstants::CORE_DEFAULT_GPU_IMAGE_WHITE, desc, rgbDataViewWhite));
}
void CreateDefaultTargets(IGpuResourceManager& gpuResourceMgr, vector& defaultGpuResources)
{
{
// hard-coded default backbuffer
// all presentations and swapchain semaphore syncs are done automatically for this client handle
GpuImageDesc desc {
ImageType::CORE_IMAGE_TYPE_2D,
ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,
Format::BASE_FORMAT_R8G8B8A8_UNORM,
ImageTiling::CORE_IMAGE_TILING_OPTIMAL,
ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
0, // ImageCreateFlags
EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS |
EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS, // EngineImageCreationFlags
2,
2,
1,
1,
1,
SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,
{},
};
GpuResourceManager& gpuResourceMgrImpl = (GpuResourceManager&)gpuResourceMgr;
// create as a swapchain image to get correct handle flags for fast check-up for additional processing
defaultGpuResources.push_back(gpuResourceMgrImpl.CreateSwapchainImage(
{}, DefaultEngineGpuResourceConstants::CORE_DEFAULT_BACKBUFFER, desc));
}
{
GpuImageDesc desc {
ImageType::CORE_IMAGE_TYPE_2D,
ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,
Format::BASE_FORMAT_D16_UNORM,
ImageTiling::CORE_IMAGE_TILING_OPTIMAL,
ImageUsageFlagBits::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT,
0, // ImageCreateFlags
EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS, // EngineImageCreationFlags
2,
2,
1,
1,
1,
SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,
{},
};
defaultGpuResources.push_back(
gpuResourceMgr.Create(DefaultEngineGpuResourceConstants::CORE_DEFAULT_BACKBUFFER_DEPTH, desc));
}
}
void CreateDefaultSamplers(IGpuResourceManager& gpuResourceMgr, vector& defaultGpuResources)
{
defaultGpuResources.push_back(
gpuResourceMgr.Create(DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_NEAREST_REPEAT,
GpuSamplerDesc {
Filter::CORE_FILTER_NEAREST, // magFilter
Filter::CORE_FILTER_NEAREST, // minFilter
Filter::CORE_FILTER_NEAREST, // mipMapMode
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_REPEAT, // addressModeU
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_REPEAT, // addressModeV
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_REPEAT, // addressModeW
}));
defaultGpuResources.push_back(
gpuResourceMgr.Create(DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_NEAREST_CLAMP,
GpuSamplerDesc {
Filter::CORE_FILTER_NEAREST, // magFilter
Filter::CORE_FILTER_NEAREST, // minFilter
Filter::CORE_FILTER_NEAREST, // mipMapMode
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
}));
defaultGpuResources.push_back(
gpuResourceMgr.Create(DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_REPEAT,
GpuSamplerDesc {
Filter::CORE_FILTER_LINEAR, // magFilter
Filter::CORE_FILTER_LINEAR, // minFilter
Filter::CORE_FILTER_LINEAR, // mipMapMode
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_REPEAT, // addressModeU
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_REPEAT, // addressModeV
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_REPEAT, // addressModeW
}));
defaultGpuResources.push_back(
gpuResourceMgr.Create(DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP,
GpuSamplerDesc {
Filter::CORE_FILTER_LINEAR, // magFilter
Filter::CORE_FILTER_LINEAR, // minFilter
Filter::CORE_FILTER_LINEAR, // mipMapMode
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
}));
GpuSamplerDesc linearMipmapRepeat {
Filter::CORE_FILTER_LINEAR, // magFilter
Filter::CORE_FILTER_LINEAR, // minFilter
Filter::CORE_FILTER_LINEAR, // mipMapMode
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_REPEAT, // addressModeU
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_REPEAT, // addressModeV
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_REPEAT, // addressModeW
};
linearMipmapRepeat.minLod = 0.0f;
linearMipmapRepeat.maxLod = 32.0f;
defaultGpuResources.push_back(gpuResourceMgr.Create(
DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_REPEAT, linearMipmapRepeat));
GpuSamplerDesc linearMipmapClamp {
Filter::CORE_FILTER_LINEAR, // magFilter
Filter::CORE_FILTER_LINEAR, // minFilter
Filter::CORE_FILTER_LINEAR, // mipMapMode
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
};
linearMipmapClamp.minLod = 0.0f;
linearMipmapClamp.maxLod = 32.0f;
defaultGpuResources.push_back(gpuResourceMgr.Create(
DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_CLAMP, linearMipmapClamp));
}
string_view GetPipelineCacheUri(DeviceBackendType backendType)
{
switch (backendType) {
case DeviceBackendType::VULKAN:
return "cache://deviceVkCache.bin";
case DeviceBackendType::OPENGLES:
return "cache://deviceGLESCache.bin";
case DeviceBackendType::OPENGL:
return "cache://deviceGLCache.bin";
default:
break;
}
return "";
}
} // namespace
IRenderContext* RenderPluginState::CreateInstance(IEngine& engine)
{
if (!context_) {
context_ = IRenderContext::Ptr { new RenderContext(*this, engine) };
}
return context_.get();
}
IRenderContext* RenderPluginState::GetInstance()
{
return context_.get();
}
void RenderPluginState::Destroy()
{
context_.reset();
}
RenderContext::RenderContext(RenderPluginState& pluginState, IEngine& engine)
: pluginState_(pluginState), engine_(engine), fileManager_(&engine.GetFileManager())
{
for (const auto& ref : interfaceInfos_) {
RegisterInterfaceType(ref);
}
LogRenderBuildInfo();
RegisterDefaultPaths();
}
RenderContext::~RenderContext()
{
GetPluginRegister().RemoveListener(*this);
if (device_) {
device_->WaitForIdle();
}
for (auto& info : plugins_) {
if (info.second && info.second->destroyPlugin) {
info.second->destroyPlugin(info.first);
}
}
// NOTE: device needs to be active for render resources (e.g. with GLES)
if (device_) {
device_->Activate();
if (device_->GetDeviceConfiguration().configurationFlags & CORE_DEVICE_CONFIGURATION_PIPELINE_CACHE_BIT) {
vector pipelineCache = device_->GetPipelineCache();
if (auto file = fileManager_->CreateFile(GetPipelineCacheUri(device_->GetBackendType())); file) {
file->Write(pipelineCache.data(), pipelineCache.size());
}
}
}
defaultGpuResources_.clear();
renderer_.reset();
renderNodeGraphMgr_.reset();
renderDataStoreMgr_.reset();
renderUtil_.reset(); // GLES semaphore/fence destruction device needs to be active
if (device_) {
device_->Deactivate();
}
}
RenderResultCode RenderContext::Init(const RenderCreateInfo& createInfo)
{
PLUGIN_LOG_D("Render init.");
createInfo_ = createInfo;
device_ = CreateDevice(createInfo_.deviceCreateInfo);
if (!device_) {
PLUGIN_LOG_E("device not created successfully, invalid render interface");
return RenderResultCode::RENDER_ERROR;
} else {
device_->Activate();
// Initialize the pipeline/ program cache.
if (device_->GetDeviceConfiguration().configurationFlags & CORE_DEVICE_CONFIGURATION_PIPELINE_CACHE_BIT) {
vector pipelineCache;
if (auto file = fileManager_->OpenFile(GetPipelineCacheUri(device_->GetBackendType())); file) {
pipelineCache.resize(static_cast(file->GetLength()));
file->Read(pipelineCache.data(), pipelineCache.size());
}
device_->InitializePipelineCache(pipelineCache);
}
// set engine file manager with registered paths
ShaderManager& shaderMgr = (ShaderManager&)device_->GetShaderManager();
shaderMgr.SetFileManager(engine_.GetFileManager());
{
IShaderManager::ShaderFilePathDesc desc;
desc.shaderPath = "rendershaders://";
desc.pipelineLayoutPath = "renderpipelinelayouts://";
// NOTE: does not have states and vids
shaderMgr.LoadShaderFiles(desc);
}
// make sure shaders found above have been created
shaderMgr.HandlePendingAllocations();
renderDataStoreMgr_ = make_unique(*this);
RegisterCoreRenderDataStores(*renderDataStoreMgr_);
// Add render data stores from plugins
for (auto info : CORE_NS::GetPluginRegister().GetTypeInfos(RenderDataStoreTypeInfo::UID)) {
renderDataStoreMgr_->AddRenderDataStoreFactory(*static_cast(info));
}
auto loader = RenderDataLoader(*fileManager_);
CreateDefaultRenderDataStores(*renderDataStoreMgr_, loader);
renderNodeGraphMgr_ = make_unique(*device_, *fileManager_);
auto& renderNodeMgr = renderNodeGraphMgr_->GetRenderNodeManager();
RegisterCoreRenderNodes(renderNodeMgr);
// Add render nodes from plugins
for (auto info : CORE_NS::GetPluginRegister().GetTypeInfos(RenderNodeTypeInfo::UID)) {
renderNodeMgr.AddRenderNodeFactory(*static_cast(info));
}
renderUtil_ = make_unique(*this);
renderer_ = make_unique(*this);
IGpuResourceManager& gpuResourceMgr = device_->GetGpuResourceManager();
CreateDefaultBuffers(gpuResourceMgr, defaultGpuResources_);
CreateDefaultTextures(gpuResourceMgr, defaultGpuResources_);
CreateDefaultTargets(gpuResourceMgr, defaultGpuResources_);
CreateDefaultSamplers(gpuResourceMgr, defaultGpuResources_);
device_->Deactivate();
GetPluginRegister().AddListener(*this);
for (auto info : CORE_NS::GetPluginRegister().GetTypeInfos(IRenderPlugin::UID)) {
if (auto renderPlugin = static_cast(info);
renderPlugin && renderPlugin->createPlugin) {
auto token = renderPlugin->createPlugin(*this);
plugins_.push_back({ token, renderPlugin });
}
}
return RenderResultCode::RENDER_SUCCESS;
}
}
IDevice& RenderContext::GetDevice() const
{
if (!device_) {
PLUGIN_LOG_E("Render Init not called or result was not success");
}
return *device_;
}
IRenderer& RenderContext::GetRenderer() const
{
if (!renderer_) {
PLUGIN_LOG_E("Render Init not called or result was not success");
}
return *renderer_;
}
IRenderDataStoreManager& RenderContext::GetRenderDataStoreManager() const
{
if (!renderDataStoreMgr_) {
PLUGIN_LOG_E("Render Init not called or result was not success");
}
return *renderDataStoreMgr_;
}
IRenderNodeGraphManager& RenderContext::GetRenderNodeGraphManager() const
{
if (!renderNodeGraphMgr_) {
PLUGIN_LOG_E("Render Init not called or result was not success");
}
return *renderNodeGraphMgr_;
}
IRenderUtil& RenderContext::GetRenderUtil() const
{
if (!renderUtil_) {
PLUGIN_LOG_E("Render Init not called or result was not success");
}
return *renderUtil_;
}
void RenderContext::RegisterDefaultPaths()
{
// Already handeled during plugin registration. If own filemanager instance is used then these are needed.
#if (RENDER_EMBEDDED_ASSETS_ENABLED == 1)
// Create engine:// protocol that points to embedded engine asset files.
PLUGIN_LOG_D("Registered core asset path: 'rofsRndr://render/'");
fileManager_->RegisterPath("render", "rofsRndr://render/", false);
#endif
for (uint32_t idx = 0; idx < countof(RENDER_DATA_PATHS); ++idx) {
fileManager_->RegisterPath(RENDER_DATA_PATHS[idx].protocol, RENDER_DATA_PATHS[idx].uri, false);
}
}
unique_ptr RenderContext::CreateDevice(const DeviceCreateInfo& createInfo)
{
switch (createInfo.backendType) {
case DeviceBackendType::OPENGL:
#if (RENDER_HAS_GL_BACKEND)
return CreateDeviceGL(*this, createInfo);
#else
return nullptr;
#endif
case DeviceBackendType::OPENGLES:
#if (RENDER_HAS_GLES_BACKEND)
return CreateDeviceGLES(*this, createInfo);
#else
return nullptr;
#endif
case DeviceBackendType::VULKAN:
#if (RENDER_HAS_VULKAN_BACKEND)
return CreateDeviceVk(*this, createInfo);
#else
return nullptr;
#endif
default:
break;
}
return nullptr;
}
IEngine& RenderContext::GetEngine() const
{
return engine_;
}
string_view RenderContext::GetVersion()
{
return {};
}
RenderCreateInfo RenderContext::GetCreateInfo() const
{
return createInfo_;
}
const IInterface* RenderContext::GetInterface(const Uid& uid) const
{
if ((uid == IRenderContext::UID) || (uid == IClassFactory::UID) || (uid == IInterface::UID)) {
return static_cast(this);
}
if (uid == IClassRegister::UID) {
return static_cast(this);
}
return nullptr;
}
IInterface* RenderContext::GetInterface(const Uid& uid)
{
if ((uid == IRenderContext::UID) || (uid == IClassFactory::UID) || (uid == IInterface::UID)) {
return static_cast(this);
}
if (uid == IClassRegister::UID) {
return static_cast(this);
}
return nullptr;
}
void RenderContext::Ref()
{
refCount_++;
}
void RenderContext::Unref()
{
if (--refCount_ == 1) {
pluginState_.Destroy();
delete this;
}
}
IInterface::Ptr RenderContext::CreateInstance(const Uid& uid)
{
const auto& data = GetInterfaceMetadata(uid);
if (data.createInterface) {
return IInterface::Ptr { data.createInterface(*this, data.token) };
}
return {};
}
void RenderContext::RegisterInterfaceType(const InterfaceTypeInfo& interfaceInfo)
{
// keep interfaceTypeInfos_ sorted according to UIDs
const auto pos = std::upper_bound(interfaceTypeInfos_.cbegin(), interfaceTypeInfos_.cend(), interfaceInfo.uid,
[](Uid value, const InterfaceTypeInfo* element) { return value < element->uid; });
interfaceTypeInfos_.insert(pos, &interfaceInfo);
}
void RenderContext::UnregisterInterfaceType(const InterfaceTypeInfo& interfaceInfo)
{
if (!interfaceTypeInfos_.empty()) {
const auto pos = std::lower_bound(interfaceTypeInfos_.cbegin(), interfaceTypeInfos_.cend(), interfaceInfo.uid,
[](const InterfaceTypeInfo* element, Uid value) { return element->uid < value; });
if ((pos != interfaceTypeInfos_.cend()) && (*pos)->uid == interfaceInfo.uid) {
interfaceTypeInfos_.erase(pos);
}
}
}
array_view RenderContext::GetInterfaceMetadata() const
{
return interfaceTypeInfos_;
}
const InterfaceTypeInfo& RenderContext::GetInterfaceMetadata(const Uid& uid) const
{
static InterfaceTypeInfo invalidType {};
if (!interfaceTypeInfos_.empty()) {
const auto pos = std::lower_bound(interfaceTypeInfos_.cbegin(), interfaceTypeInfos_.cend(), uid,
[](const InterfaceTypeInfo* element, Uid value) { return element->uid < value; });
if ((pos != interfaceTypeInfos_.cend()) && (*pos)->uid == uid) {
return *(*pos);
}
}
return invalidType;
}
IInterface* RenderContext::GetInstance(const Uid& uid) const
{
const auto& data = GetInterfaceMetadata(uid);
if (data.getInterface) {
return data.getInterface(const_cast(*this), data.token);
}
return nullptr;
}
void RenderContext::OnTypeInfoEvent(EventType type, array_view typeInfos)
{
auto& renderNodeMgr = renderNodeGraphMgr_->GetRenderNodeManager();
if (type == EventType::ADDED) {
for (const auto* info : typeInfos) {
if (info && info->typeUid == IRenderPlugin::UID && static_cast(info)->createPlugin) {
auto renderPlugin = static_cast(info);
if (std::none_of(plugins_.begin(), plugins_.end(),
[renderPlugin](const pair& pluginData) {
return pluginData.second == renderPlugin;
})) {
auto token = renderPlugin->createPlugin(*this);
plugins_.push_back({ token, renderPlugin });
}
} else if (info && info->typeUid == RenderDataStoreTypeInfo::UID) {
renderDataStoreMgr_->AddRenderDataStoreFactory(*static_cast(info));
} else if (info && info->typeUid == RenderNodeTypeInfo::UID) {
renderNodeMgr.AddRenderNodeFactory(*static_cast(info));
}
}
} else if (type == EventType::REMOVED) {
for (const auto* info : typeInfos) {
if (info && info->typeUid == IRenderPlugin::UID) {
auto renderPlugin = static_cast(info);
if (auto pos = std::find_if(plugins_.begin(), plugins_.end(),
[renderPlugin](const pair& pluginData) {
return pluginData.second == renderPlugin;
});
pos != plugins_.end()) {
if (renderPlugin->destroyPlugin) {
renderPlugin->destroyPlugin(pos->first);
}
plugins_.erase(pos);
}
} else if (info && info->typeUid == RenderDataStoreTypeInfo::UID) {
renderDataStoreMgr_->RemoveRenderDataStoreFactory(*static_cast(info));
} else if (info && info->typeUid == RenderNodeTypeInfo::UID) {
renderNodeGraphMgr_->Destroy(static_cast(info)->typeName);
renderNodeMgr.RemoveRenderNodeFactory(*static_cast(info));
}
}
}
}
RENDER_END_NAMESPACE()