/* * Copyright (C) 2023 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 "graphics_context.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if (RENDER_HAS_VULKAN_BACKEND) #include #endif #include <3d/ecs/components/material_component.h> #include <3d/ecs/components/uri_component.h> #include <3d/ecs/systems/intf_render_system.h> #include <3d/implementation_uids.h> #include <3d/render/default_material_constants.h> #include <3d/render/intf_render_node_scene_util.h> #include <3d/util/intf_mesh_util.h> #include <3d/util/intf_scene_util.h> #include "gltf/gltf2.h" #include "render/render_node_scene_util.h" #include "util/mesh_builder.h" #include "util/mesh_util.h" #include "util/picking.h" #include "util/render_util.h" #include "util/scene_util.h" #include "util/uri_lookup.h" extern "C" void InitRegistry(CORE_NS::IPluginRegister& pluginRegistry); CORE3D_BEGIN_NAMESPACE() using namespace BASE_NS; using namespace CORE_NS; using namespace RENDER_NS; namespace { struct RegisterPathStrings { string_view protocol; string_view uri; }; static constexpr RegisterPathStrings RENDER_DATA_PATHS[] = { { "3dshaders", "rofs3D://shaders/" }, { "3dshaderstates", "rofs3D://shaderstates/" }, { "3dvertexinputdeclarations", "rofs3D://vertexinputdeclarations/" }, { "3dpipelinelayouts", "rofs3D://pipelinelayouts/" }, { "3drenderdataconfigurations", "rofs3D://renderdataconfigurations/" }, { "3drendernodegraphs", "rofs3D://rendernodegraphs/" }, }; static constexpr IShaderManager::ShaderFilePathDesc SHADER_FILE_PATHS { "3dshaders://", "3dshaderstates://", "3dpipelinelayouts://", "3dvertexinputdeclarations://", }; void CreateDefaultResources(IDevice& device, vector& defaultGpuResources) { // default material gpu images { GpuImageDesc desc { ImageType::CORE_IMAGE_TYPE_2D, ImageViewType::CORE_IMAGE_VIEW_TYPE_2D, Format::BASE_FORMAT_R8G8B8A8_SRGB, 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, 0, 2, 2, 1, 1, 1, SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT, {} }; IGpuResourceManager& gpuResourceMgr = device.GetGpuResourceManager(); constexpr uint32_t sizeOfUint32 = sizeof(uint32_t); constexpr const uint32_t rgbData[4u] = { 0xFFFFffff, 0xFFFFffff, 0xFFFFffff, 0xFFFFffff }; const auto rgbDataView = array_view(reinterpret_cast(rgbData), sizeOfUint32 * countof(rgbData)); defaultGpuResources.emplace_back( gpuResourceMgr.Create(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_BASE_COLOR, reinterpret_cast(desc), rgbDataView)); desc.format = Format::BASE_FORMAT_R8G8B8A8_UNORM; { constexpr const uint32_t normalData[4u] = { 0xFFFF7f7f, 0xFFFF7f7f, 0xFFFF7f7f, 0xFFFF7f7f }; const auto normalDataView = array_view(reinterpret_cast(normalData), sizeOfUint32 * countof(normalData)); defaultGpuResources.emplace_back(gpuResourceMgr.Create( DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_NORMAL, desc, normalDataView)); } defaultGpuResources.emplace_back(gpuResourceMgr.Create( DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_MATERIAL, desc, rgbDataView)); desc.format = Format::BASE_FORMAT_R8_UNORM; { constexpr const uint8_t byteData[4u] = { 0xff, 0xff, 0xff, 0xff }; const auto byteDataView = array_view(reinterpret_cast(byteData), sizeof(uint8_t) * countof(byteData)); defaultGpuResources.emplace_back(gpuResourceMgr.Create( DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_AO, desc, byteDataView)); } // env cubemaps desc.imageViewType = ImageViewType::CORE_IMAGE_VIEW_TYPE_CUBE; desc.format = Format::BASE_FORMAT_R8G8B8A8_SRGB; desc.createFlags = ImageCreateFlagBits::CORE_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; desc.layerCount = 6u; { // Env color is currently in rgbd format (alpha channel is used as a divider for the rgb values). const vector cubeData(4u * 6u, 0xFFFFffff); const array_view cubeDataView( reinterpret_cast(cubeData.data()), cubeData.size() * sizeOfUint32); defaultGpuResources.emplace_back(gpuResourceMgr.Create( DefaultMaterialGpuResourceConstants::CORE_DEFAULT_RADIANCE_CUBEMAP, desc, cubeDataView)); // Skybox is currently in rgbd format (alpha channel is used as a divider for the rgb values). defaultGpuResources.emplace_back(gpuResourceMgr.Create( DefaultMaterialGpuResourceConstants::CORE_DEFAULT_SKYBOX_CUBEMAP, desc, cubeDataView)); } } } } // namespace // Core Rofs Data. extern "C" { extern const void* const BINARY_DATA_FOR_3D[]; extern const uint64_t SIZE_OF_DATA_FOR_3D; } array_view GetRenderDataStores3D(); array_view GetRenderNodes3D(); array_view GetComponentManagers3D(); array_view GetSystems3D(); struct Agp3DPluginState { IRenderContext& renderContext; unique_ptr context; Picking picker; RenderNodeSceneUtilImpl renderNodeSceneUtil; InterfaceTypeInfo interfaces[4] = { InterfaceTypeInfo { this, UID_MESH_BUILDER, CORE_NS::GetName().data(), [](IClassFactory&, PluginToken token) -> IInterface* { return new MeshBuilder; }, nullptr, }, InterfaceTypeInfo { this, UID_PICKING, CORE_NS::GetName().data(), nullptr, [](IClassRegister& registry, PluginToken token) -> IInterface* { if (token) { Agp3DPluginState* state = static_cast(token); return &state->picker; } return nullptr; }, }, InterfaceTypeInfo { this, UID_RENDER_NODE_SCENE_UTIL, CORE_NS::GetName().data(), nullptr, [](IClassRegister& registry, PluginToken token) -> IInterface* { if (token) { Agp3DPluginState* state = static_cast(token); return &state->renderNodeSceneUtil; } return nullptr; }, }, InterfaceTypeInfo { this, UID_GRAPHICS_CONTEXT, CORE_NS::GetName().data(), [](IClassFactory& registry, PluginToken token) -> IInterface* { if (token) { Agp3DPluginState* state = static_cast(token); if (!state->context) { state->context = make_unique(*state, state->renderContext); } return state->context.get(); } return nullptr; }, [](IClassRegister& registry, PluginToken token) -> IInterface* { if (token) { Agp3DPluginState* state = static_cast(token); return state->context.get(); } return nullptr; }, }, }; void Destroy(IRenderContext& engine) { context.reset(); } }; GraphicsContext::GraphicsContext(struct Agp3DPluginState& factory, IRenderContext& context) : factory_(factory), context_(context) {} GraphicsContext ::~GraphicsContext() {} void GraphicsContext::Init() { if (initialized_) { return; } auto& engine = context_.GetEngine(); meshUtil_ = make_unique(engine); gltf2_ = make_unique(*this); CreateDefaultResources(context_.GetDevice(), defaultGpuResources_); auto* renderDataConfigurationLoader = GetInstance( *context_.GetInterface(), UID_RENDER_DATA_CONFIGURATION_LOADER); auto* dataStore = context_.GetRenderDataStoreManager().GetRenderDataStore("RenderDataStorePod"); if (renderDataConfigurationLoader && dataStore) { auto& fileMgr = engine.GetFileManager(); constexpr string_view ppPath = "3drenderdataconfigurations://postprocess/"; if (auto dir = fileMgr.OpenDirectory(ppPath); dir) { for (const auto& entry : dir->GetEntries()) { if (entry.type == IDirectory::Entry::Type::FILE) { const auto loadedPP = renderDataConfigurationLoader->LoadPostProcess(engine.GetFileManager(), ppPath + entry.name); if (loadedPP.loadResult.success) { auto pod = static_cast(dataStore); pod->CreatePod("PostProcess", loadedPP.name, arrayviewU8(loadedPP.postProcessConfiguration)); } } } } } sceneUtil_ = make_unique(*this); renderUtil_ = make_unique(*this); initialized_ = true; } IRenderContext& GraphicsContext::GetRenderContext() const { return context_; } array_view GraphicsContext::GetRenderNodeGraphs(const IEcs& ecs) const { // NOTE: gets the render node graphs from built-in RenderSystem if (IRenderSystem* rs = GetSystem(ecs); rs) { return rs->GetRenderNodeGraphs(); } else { return {}; } } ISceneUtil& GraphicsContext::GetSceneUtil() const { return *sceneUtil_; } IMeshUtil& GraphicsContext::GetMeshUtil() const { return *meshUtil_; } IGltf2& GraphicsContext::GetGltf() const { return *gltf2_; } IRenderUtil& GraphicsContext::GetRenderUtil() const { return *renderUtil_; } const IInterface* GraphicsContext::GetInterface(const Uid& uid) const { if (uid == IGraphicsContext::UID) { return this; } return nullptr; } IInterface* GraphicsContext::GetInterface(const Uid& uid) { if (uid == IGraphicsContext::UID) { return this; } return nullptr; } void GraphicsContext::Ref() { refcnt_++; } void GraphicsContext::Unref() { if (--refcnt_ == 0) { factory_.Destroy(context_); } } void RegisterTypes(IPluginRegister& pluginRegistry); void UnregisterTypes(IPluginRegister& pluginRegistry); namespace { PluginToken CreatePlugin3D(IRenderContext& context) { Agp3DPluginState* token = new Agp3DPluginState { context, {}, {}, {} }; auto& registry = *context.GetInterface(); for (const auto& info : token->interfaces) { registry.RegisterInterfaceType(info); } RegisterTypes(GetPluginRegister()); IFileManager& fileManager = context.GetEngine().GetFileManager(); #if (CORE3D_EMBEDDED_ASSETS_ENABLED == 1) // Create engine:// protocol that points to embedded asset files. fileManager.RegisterFilesystem("rofs3D", fileManager.CreateROFilesystem(BINARY_DATA_FOR_3D, SIZE_OF_DATA_FOR_3D)); #endif #if (CORE3D_EMBEDDED_ASSETS_ENABLED == 0) || (CORE3D_DEV_ENABLED == 1) const string assets = context.GetEngine().GetRootPath() + "../Lume3D/assets/3d/"; fileManager.RegisterPath("engine", assets, true); #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); } context.GetDevice().GetShaderManager().LoadShaderFiles(SHADER_FILE_PATHS); return token; } void DestroyPlugin3D(PluginToken token) { Agp3DPluginState* state = static_cast(token); IFileManager& fileManager = state->renderContext.GetEngine().GetFileManager(); state->renderContext.GetDevice().GetShaderManager().UnloadShaderFiles(SHADER_FILE_PATHS); #if (CORE3D_EMBEDDED_ASSETS_ENABLED == 1) fileManager.UnregisterFilesystem("rofs3D"); #endif #if (CORE3D_EMBEDDED_ASSETS_ENABLED == 0) || (CORE3D_DEV_ENABLED == 1) const string assets = state->renderContext.GetEngine().GetRootPath() + "../Lume3D/assets/3d/"; fileManager.UnregisterPath("engine", assets); #endif for (uint32_t idx = 0; idx < countof(RENDER_DATA_PATHS); ++idx) { fileManager.UnregisterPath(RENDER_DATA_PATHS[idx].protocol, RENDER_DATA_PATHS[idx].uri); } UnregisterTypes(GetPluginRegister()); auto& registry = *state->renderContext.GetInterface(); for (const auto& info : state->interfaces) { registry.UnregisterInterfaceType(info); } delete state; } PluginToken CreateEcsPlugin3D(IEcs& ecs) { return {}; } void DestroyEcsPlugin3D(PluginToken token) {} constexpr IRenderPlugin RENDER_PLUGIN(CreatePlugin3D, DestroyPlugin3D); constexpr IEcsPlugin ECS_PLUGIN(CreateEcsPlugin3D, DestroyEcsPlugin3D); } // namespace PluginToken RegisterInterfaces3D(IPluginRegister& pluginRegistry) { InitRegistry(pluginRegistry); pluginRegistry.RegisterTypeInfo(RENDER_PLUGIN); pluginRegistry.RegisterTypeInfo(ECS_PLUGIN); return &pluginRegistry; } void UnregisterInterfaces3D(PluginToken token) { IPluginRegister* pluginRegistry = static_cast(token); pluginRegistry->UnregisterTypeInfo(ECS_PLUGIN); pluginRegistry->UnregisterTypeInfo(RENDER_PLUGIN); } CORE3D_END_NAMESPACE()