1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "graphics_context.h"
17
18 #include <base/containers/string_view.h>
19 #include <base/containers/unordered_map.h>
20 #include <base/util/uid.h>
21 #include <core/ecs/intf_ecs.h>
22 #include <core/ecs/intf_entity_manager.h>
23 #include <core/intf_engine.h>
24 #include <core/io/intf_file_manager.h>
25 #include <core/log.h>
26 #include <core/plugin/intf_plugin.h>
27 #include <core/plugin/intf_plugin_register.h>
28 #include <core/property/intf_property_handle.h>
29 #include <render/datastore/intf_render_data_store_manager.h>
30 #include <render/datastore/intf_render_data_store_pod.h>
31 #include <render/device/intf_device.h>
32 #include <render/device/intf_gpu_resource_manager.h>
33 #include <render/device/intf_shader_manager.h>
34 #include <render/implementation_uids.h>
35 #include <render/intf_plugin.h>
36 #include <render/intf_render_context.h>
37 #include <render/loader/intf_render_data_configuration_loader.h>
38 #include <render/nodecontext/intf_render_node_graph_manager.h>
39
40 #if (RENDER_HAS_VULKAN_BACKEND)
41 #include <render/vulkan/intf_device_vk.h>
42 #endif
43
44 #include <3d/ecs/components/material_component.h>
45 #include <3d/ecs/components/uri_component.h>
46 #include <3d/ecs/systems/intf_render_system.h>
47 #include <3d/implementation_uids.h>
48 #include <3d/render/default_material_constants.h>
49 #include <3d/render/intf_render_node_scene_util.h>
50 #include <3d/util/intf_mesh_util.h>
51 #include <3d/util/intf_scene_util.h>
52
53 #include "gltf/gltf2.h"
54 #include "render/render_node_scene_util.h"
55 #include "util/mesh_builder.h"
56 #include "util/mesh_util.h"
57 #include "util/picking.h"
58 #include "util/render_util.h"
59 #include "util/scene_util.h"
60 #include "util/uri_lookup.h"
61
62 extern "C" void InitRegistry(CORE_NS::IPluginRegister& pluginRegistry);
63
64 CORE3D_BEGIN_NAMESPACE()
65 using namespace BASE_NS;
66 using namespace CORE_NS;
67 using namespace RENDER_NS;
68
69 namespace {
70 struct RegisterPathStrings {
71 string_view protocol;
72 string_view uri;
73 };
74 static constexpr RegisterPathStrings RENDER_DATA_PATHS[] = {
75 { "3dshaders", "rofs3D://shaders/" },
76 { "3dshaderstates", "rofs3D://shaderstates/" },
77 { "3dvertexinputdeclarations", "rofs3D://vertexinputdeclarations/" },
78 { "3dpipelinelayouts", "rofs3D://pipelinelayouts/" },
79 { "3drenderdataconfigurations", "rofs3D://renderdataconfigurations/" },
80 { "3drendernodegraphs", "rofs3D://rendernodegraphs/" },
81 };
82
83 static constexpr IShaderManager::ShaderFilePathDesc SHADER_FILE_PATHS {
84 "3dshaders://",
85 "3dshaderstates://",
86 "3dpipelinelayouts://",
87 "3dvertexinputdeclarations://",
88 };
89
CreateDefaultResources(IDevice & device,vector<RenderHandleReference> & defaultGpuResources)90 void CreateDefaultResources(IDevice& device, vector<RenderHandleReference>& defaultGpuResources)
91 {
92 // default material gpu images
93 {
94 GpuImageDesc desc { ImageType::CORE_IMAGE_TYPE_2D, ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,
95 Format::BASE_FORMAT_R8G8B8A8_SRGB, ImageTiling::CORE_IMAGE_TILING_OPTIMAL,
96 ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT | ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSFER_DST_BIT,
97 MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0, 2, 2, 1, 1, 1,
98 SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT, {} };
99
100 IGpuResourceManager& gpuResourceMgr = device.GetGpuResourceManager();
101 constexpr uint32_t sizeOfUint32 = sizeof(uint32_t);
102 constexpr const uint32_t rgbData[4u] = { 0xFFFFffff, 0xFFFFffff, 0xFFFFffff, 0xFFFFffff };
103 const auto rgbDataView = array_view(reinterpret_cast<const uint8_t*>(rgbData), sizeOfUint32 * countof(rgbData));
104 defaultGpuResources.emplace_back(
105 gpuResourceMgr.Create(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_BASE_COLOR,
106 reinterpret_cast<GpuImageDesc&>(desc), rgbDataView));
107
108 desc.format = Format::BASE_FORMAT_R8G8B8A8_UNORM;
109 {
110 constexpr const uint32_t normalData[4u] = { 0xFFFF7f7f, 0xFFFF7f7f, 0xFFFF7f7f, 0xFFFF7f7f };
111 const auto normalDataView =
112 array_view(reinterpret_cast<const uint8_t*>(normalData), sizeOfUint32 * countof(normalData));
113 defaultGpuResources.emplace_back(gpuResourceMgr.Create(
114 DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_NORMAL, desc, normalDataView));
115 }
116 defaultGpuResources.emplace_back(gpuResourceMgr.Create(
117 DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_MATERIAL, desc, rgbDataView));
118
119 desc.format = Format::BASE_FORMAT_R8_UNORM;
120 {
121 constexpr const uint8_t byteData[4u] = { 0xff, 0xff, 0xff, 0xff };
122 const auto byteDataView =
123 array_view(reinterpret_cast<const uint8_t*>(byteData), sizeof(uint8_t) * countof(byteData));
124 defaultGpuResources.emplace_back(gpuResourceMgr.Create(
125 DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_AO, desc, byteDataView));
126 }
127
128 // env cubemaps
129 desc.imageViewType = ImageViewType::CORE_IMAGE_VIEW_TYPE_CUBE;
130 desc.format = Format::BASE_FORMAT_R8G8B8A8_SRGB;
131 desc.createFlags = ImageCreateFlagBits::CORE_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
132 desc.layerCount = 6u;
133 {
134 // Env color is currently in rgbd format (alpha channel is used as a divider for the rgb values).
135 const vector<uint32_t> cubeData(4u * 6u, 0xFFFFffff);
136 const array_view<const uint8_t> cubeDataView(
137 reinterpret_cast<const uint8_t*>(cubeData.data()), cubeData.size() * sizeOfUint32);
138 defaultGpuResources.emplace_back(gpuResourceMgr.Create(
139 DefaultMaterialGpuResourceConstants::CORE_DEFAULT_RADIANCE_CUBEMAP, desc, cubeDataView));
140
141 // Skybox is currently in rgbd format (alpha channel is used as a divider for the rgb values).
142 defaultGpuResources.emplace_back(gpuResourceMgr.Create(
143 DefaultMaterialGpuResourceConstants::CORE_DEFAULT_SKYBOX_CUBEMAP, desc, cubeDataView));
144 }
145 }
146 }
147 } // namespace
148
149 // Core Rofs Data.
150 extern "C" {
151 extern const void* const BINARY_DATA_FOR_3D[];
152 extern const uint64_t SIZE_OF_DATA_FOR_3D;
153 }
154
155 array_view<const RenderDataStoreTypeInfo> GetRenderDataStores3D();
156 array_view<const RenderNodeTypeInfo> GetRenderNodes3D();
157 array_view<const ComponentManagerTypeInfo> GetComponentManagers3D();
158 array_view<const SystemTypeInfo> GetSystems3D();
159
160 struct Agp3DPluginState {
161 IRenderContext& renderContext;
162 unique_ptr<GraphicsContext> context;
163
164 Picking picker;
165 RenderNodeSceneUtilImpl renderNodeSceneUtil;
166 InterfaceTypeInfo interfaces[4] = {
167 InterfaceTypeInfo {
168 this,
169 UID_MESH_BUILDER,
170 CORE_NS::GetName<IMeshBuilder>().data(),
__anon4aa43ab70202Agp3DPluginState171 [](IClassFactory&, PluginToken token) -> IInterface* { return new MeshBuilder; },
172 nullptr,
173 },
174 InterfaceTypeInfo {
175 this,
176 UID_PICKING,
177 CORE_NS::GetName<IPicking>().data(),
178 nullptr,
__anon4aa43ab70302Agp3DPluginState179 [](IClassRegister& registry, PluginToken token) -> IInterface* {
180 if (token) {
181 Agp3DPluginState* state = static_cast<Agp3DPluginState*>(token);
182 return &state->picker;
183 }
184 return nullptr;
185 },
186 },
187 InterfaceTypeInfo {
188 this,
189 UID_RENDER_NODE_SCENE_UTIL,
190 CORE_NS::GetName<IRenderNodeSceneUtil>().data(),
191 nullptr,
__anon4aa43ab70402Agp3DPluginState192 [](IClassRegister& registry, PluginToken token) -> IInterface* {
193 if (token) {
194 Agp3DPluginState* state = static_cast<Agp3DPluginState*>(token);
195 return &state->renderNodeSceneUtil;
196 }
197 return nullptr;
198 },
199 },
200 InterfaceTypeInfo {
201 this,
202 UID_GRAPHICS_CONTEXT,
203 CORE_NS::GetName<IGraphicsContext>().data(),
__anon4aa43ab70502Agp3DPluginState204 [](IClassFactory& registry, PluginToken token) -> IInterface* {
205 if (token) {
206 Agp3DPluginState* state = static_cast<Agp3DPluginState*>(token);
207 if (!state->context) {
208 state->context = make_unique<GraphicsContext>(*state, state->renderContext);
209 }
210 return state->context.get();
211 }
212 return nullptr;
213 },
__anon4aa43ab70602Agp3DPluginState214 [](IClassRegister& registry, PluginToken token) -> IInterface* {
215 if (token) {
216 Agp3DPluginState* state = static_cast<Agp3DPluginState*>(token);
217 return state->context.get();
218 }
219 return nullptr;
220 },
221 },
222 };
223
DestroyAgp3DPluginState224 void Destroy(IRenderContext& engine)
225 {
226 context.reset();
227 }
228 };
229
GraphicsContext(struct Agp3DPluginState & factory,IRenderContext & context)230 GraphicsContext::GraphicsContext(struct Agp3DPluginState& factory, IRenderContext& context)
231 : factory_(factory), context_(context)
232 {}
233
~GraphicsContext()234 GraphicsContext ::~GraphicsContext() {}
235
Init()236 void GraphicsContext::Init()
237 {
238 if (initialized_) {
239 return;
240 }
241 auto& engine = context_.GetEngine();
242
243 meshUtil_ = make_unique<MeshUtil>(engine);
244 gltf2_ = make_unique<Gltf2>(*this);
245 CreateDefaultResources(context_.GetDevice(), defaultGpuResources_);
246
247 auto* renderDataConfigurationLoader = GetInstance<IRenderDataConfigurationLoader>(
248 *context_.GetInterface<IClassRegister>(), UID_RENDER_DATA_CONFIGURATION_LOADER);
249 auto* dataStore = context_.GetRenderDataStoreManager().GetRenderDataStore("RenderDataStorePod");
250 if (renderDataConfigurationLoader && dataStore) {
251 auto& fileMgr = engine.GetFileManager();
252 constexpr string_view ppPath = "3drenderdataconfigurations://postprocess/";
253 if (auto dir = fileMgr.OpenDirectory(ppPath); dir) {
254 for (const auto& entry : dir->GetEntries()) {
255 if (entry.type == IDirectory::Entry::Type::FILE) {
256 const auto loadedPP =
257 renderDataConfigurationLoader->LoadPostProcess(engine.GetFileManager(), ppPath + entry.name);
258 if (loadedPP.loadResult.success) {
259 auto pod = static_cast<IRenderDataStorePod*>(dataStore);
260 pod->CreatePod("PostProcess", loadedPP.name, arrayviewU8(loadedPP.postProcessConfiguration));
261 }
262 }
263 }
264 }
265 }
266 sceneUtil_ = make_unique<SceneUtil>(*this);
267 renderUtil_ = make_unique<RenderUtil>(*this);
268
269 initialized_ = true;
270 }
271
GetRenderContext() const272 IRenderContext& GraphicsContext::GetRenderContext() const
273 {
274 return context_;
275 }
276
GetRenderNodeGraphs(const IEcs & ecs) const277 array_view<const RenderHandleReference> GraphicsContext::GetRenderNodeGraphs(const IEcs& ecs) const
278 {
279 // NOTE: gets the render node graphs from built-in RenderSystem
280 if (IRenderSystem* rs = GetSystem<IRenderSystem>(ecs); rs) {
281 return rs->GetRenderNodeGraphs();
282 } else {
283 return {};
284 }
285 }
286
GetSceneUtil() const287 ISceneUtil& GraphicsContext::GetSceneUtil() const
288 {
289 return *sceneUtil_;
290 }
291
GetMeshUtil() const292 IMeshUtil& GraphicsContext::GetMeshUtil() const
293 {
294 return *meshUtil_;
295 }
296
GetGltf() const297 IGltf2& GraphicsContext::GetGltf() const
298 {
299 return *gltf2_;
300 }
301
GetRenderUtil() const302 IRenderUtil& GraphicsContext::GetRenderUtil() const
303 {
304 return *renderUtil_;
305 }
306
GetInterface(const Uid & uid) const307 const IInterface* GraphicsContext::GetInterface(const Uid& uid) const
308 {
309 if (uid == IGraphicsContext::UID) {
310 return this;
311 }
312 return nullptr;
313 }
314
GetInterface(const Uid & uid)315 IInterface* GraphicsContext::GetInterface(const Uid& uid)
316 {
317 if (uid == IGraphicsContext::UID) {
318 return this;
319 }
320 return nullptr;
321 }
322
Ref()323 void GraphicsContext::Ref()
324 {
325 refcnt_++;
326 }
327
Unref()328 void GraphicsContext::Unref()
329 {
330 if (--refcnt_ == 0) {
331 factory_.Destroy(context_);
332 }
333 }
334
335 void RegisterTypes(IPluginRegister& pluginRegistry);
336 void UnregisterTypes(IPluginRegister& pluginRegistry);
337
338 namespace {
CreatePlugin3D(IRenderContext & context)339 PluginToken CreatePlugin3D(IRenderContext& context)
340 {
341 Agp3DPluginState* token = new Agp3DPluginState { context, {}, {}, {} };
342 auto& registry = *context.GetInterface<IClassRegister>();
343 for (const auto& info : token->interfaces) {
344 registry.RegisterInterfaceType(info);
345 }
346
347 RegisterTypes(GetPluginRegister());
348
349 IFileManager& fileManager = context.GetEngine().GetFileManager();
350 #if (CORE3D_EMBEDDED_ASSETS_ENABLED == 1)
351 // Create engine:// protocol that points to embedded asset files.
352 fileManager.RegisterFilesystem("rofs3D", fileManager.CreateROFilesystem(BINARY_DATA_FOR_3D, SIZE_OF_DATA_FOR_3D));
353 #endif
354 #if (CORE3D_EMBEDDED_ASSETS_ENABLED == 0) || (CORE3D_DEV_ENABLED == 1)
355 const string assets = context.GetEngine().GetRootPath() + "../Lume3D/assets/3d/";
356 fileManager.RegisterPath("engine", assets, true);
357 #endif
358 for (uint32_t idx = 0; idx < countof(RENDER_DATA_PATHS); ++idx) {
359 fileManager.RegisterPath(RENDER_DATA_PATHS[idx].protocol, RENDER_DATA_PATHS[idx].uri, false);
360 }
361 context.GetDevice().GetShaderManager().LoadShaderFiles(SHADER_FILE_PATHS);
362
363 return token;
364 }
365
DestroyPlugin3D(PluginToken token)366 void DestroyPlugin3D(PluginToken token)
367 {
368 Agp3DPluginState* state = static_cast<Agp3DPluginState*>(token);
369 IFileManager& fileManager = state->renderContext.GetEngine().GetFileManager();
370
371 state->renderContext.GetDevice().GetShaderManager().UnloadShaderFiles(SHADER_FILE_PATHS);
372 #if (CORE3D_EMBEDDED_ASSETS_ENABLED == 1)
373 fileManager.UnregisterFilesystem("rofs3D");
374 #endif
375 #if (CORE3D_EMBEDDED_ASSETS_ENABLED == 0) || (CORE3D_DEV_ENABLED == 1)
376 const string assets = state->renderContext.GetEngine().GetRootPath() + "../Lume3D/assets/3d/";
377 fileManager.UnregisterPath("engine", assets);
378 #endif
379 for (uint32_t idx = 0; idx < countof(RENDER_DATA_PATHS); ++idx) {
380 fileManager.UnregisterPath(RENDER_DATA_PATHS[idx].protocol, RENDER_DATA_PATHS[idx].uri);
381 }
382
383 UnregisterTypes(GetPluginRegister());
384
385 auto& registry = *state->renderContext.GetInterface<IClassRegister>();
386 for (const auto& info : state->interfaces) {
387 registry.UnregisterInterfaceType(info);
388 }
389
390 delete state;
391 }
392
CreateEcsPlugin3D(IEcs & ecs)393 PluginToken CreateEcsPlugin3D(IEcs& ecs)
394 {
395 return {};
396 }
397
DestroyEcsPlugin3D(PluginToken token)398 void DestroyEcsPlugin3D(PluginToken token) {}
399
400 constexpr IRenderPlugin RENDER_PLUGIN(CreatePlugin3D, DestroyPlugin3D);
401 constexpr IEcsPlugin ECS_PLUGIN(CreateEcsPlugin3D, DestroyEcsPlugin3D);
402 } // namespace
403
RegisterInterfaces3D(IPluginRegister & pluginRegistry)404 PluginToken RegisterInterfaces3D(IPluginRegister& pluginRegistry)
405 {
406 InitRegistry(pluginRegistry);
407 pluginRegistry.RegisterTypeInfo(RENDER_PLUGIN);
408 pluginRegistry.RegisterTypeInfo(ECS_PLUGIN);
409
410 return &pluginRegistry;
411 }
412
UnregisterInterfaces3D(PluginToken token)413 void UnregisterInterfaces3D(PluginToken token)
414 {
415 IPluginRegister* pluginRegistry = static_cast<IPluginRegister*>(token);
416 pluginRegistry->UnregisterTypeInfo(ECS_PLUGIN);
417 pluginRegistry->UnregisterTypeInfo(RENDER_PLUGIN);
418 }
419 CORE3D_END_NAMESPACE()
420