1 /*
2  * Copyright (c) 2024 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 "loader/shader_loader.h"
17 
18 #include <cstring>
19 #include <set>
20 
21 #include <base/containers/array_view.h>
22 #include <base/containers/vector.h>
23 #include <core/io/intf_file_manager.h>
24 #include <render/device/gpu_resource_desc.h>
25 #include <render/device/pipeline_layout_desc.h>
26 #include <render/namespace.h>
27 
28 #include "device/shader_manager.h"
29 #include "loader/json_util.h"
30 #include "loader/pipeline_layout_loader.h"
31 #include "loader/shader_data_loader.h"
32 #include "loader/shader_state_loader.h"
33 #include "loader/vertex_input_declaration_loader.h"
34 #include "util/log.h"
35 
36 using namespace BASE_NS;
37 using namespace CORE_NS;
38 
39 RENDER_BEGIN_NAMESPACE()
40 namespace {
41 enum ShaderDataFileType : uint32_t {
42     UNDEFINED = 0,
43     SHADER = 1,
44     SHADER_STATE = 2,
45     VERTEX_INPUT_DECLARATION = 3,
46     PIPELINE_LAYOUT = 4,
47 };
48 
49 constexpr string_view ShaderDataFileExtensions[] {
50     "",
51     ".shader",
52     ".shadergs",
53     ".shadervid",
54     ".shaderpl",
55 };
56 
HasExtension(const char * ext,const string_view fileUri)57 bool HasExtension(const char* ext, const string_view fileUri)
58 {
59     if (auto const pos = fileUri.rfind(ext); pos != string_view::npos) {
60         return std::strlen(ext) == (fileUri.length() - pos);
61     }
62     return false;
63 }
64 
GetShaderDataFileType(IFileManager & fileMgr,const string_view fullFilename)65 ShaderDataFileType GetShaderDataFileType(IFileManager& fileMgr, const string_view fullFilename)
66 {
67     if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::SHADER].data(), fullFilename)) {
68         return ShaderDataFileType::SHADER;
69     } else if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::SHADER_STATE].data(), fullFilename)) {
70         return ShaderDataFileType::SHADER_STATE;
71     } else if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::PIPELINE_LAYOUT].data(), fullFilename)) {
72         return ShaderDataFileType::PIPELINE_LAYOUT;
73     } else if (HasExtension(
74                    ShaderDataFileExtensions[ShaderDataFileType::VERTEX_INPUT_DECLARATION].data(), fullFilename)) {
75         return ShaderDataFileType::VERTEX_INPUT_DECLARATION;
76     }
77     return ShaderDataFileType::UNDEFINED;
78 }
79 
ReadFile(IFile & file)80 vector<uint8_t> ReadFile(IFile& file)
81 {
82     auto fileData = vector<uint8_t>(static_cast<std::size_t>(file.GetLength()));
83     file.Read(fileData.data(), fileData.size());
84     return fileData;
85 }
86 } // namespace
87 
ShaderLoader(IFileManager & fileManager,ShaderManager & shaderManager,const DeviceBackendType type)88 ShaderLoader::ShaderLoader(IFileManager& fileManager, ShaderManager& shaderManager, const DeviceBackendType type)
89     : fileManager_(fileManager), shaderMgr_(shaderManager), type_(type)
90 {}
91 
Load(const ShaderManager::ShaderFilePathDesc & desc)92 void ShaderLoader::Load(const ShaderManager::ShaderFilePathDesc& desc)
93 {
94     if (!desc.shaderStatePath.empty()) {
95         auto const shaderStatesPath = fileManager_.OpenDirectory(desc.shaderStatePath);
96         if (shaderStatesPath) {
97             LoadShaderStates(desc.shaderStatePath, *shaderStatesPath);
98         } else {
99             PLUGIN_LOG_W("graphics state path (%s) not found.", desc.shaderStatePath.data());
100         }
101     }
102     if (!desc.vertexInputDeclarationPath.empty()) {
103         auto const vidsPath = fileManager_.OpenDirectory(desc.vertexInputDeclarationPath);
104         if (vidsPath) {
105             LoadVids(desc.vertexInputDeclarationPath, *vidsPath);
106         } else {
107             PLUGIN_LOG_W("vertex input declaration path (%s) not found.", desc.vertexInputDeclarationPath.data());
108         }
109     }
110     if (!desc.pipelineLayoutPath.empty()) {
111         auto const pipelineLayoutsPath = fileManager_.OpenDirectory(desc.pipelineLayoutPath);
112         if (pipelineLayoutsPath) {
113             LoadPipelineLayouts(desc.pipelineLayoutPath, *pipelineLayoutsPath);
114         } else {
115             PLUGIN_LOG_W("pipeline layout path (%s) not found.", desc.pipelineLayoutPath.data());
116         }
117     }
118     if (!desc.shaderPath.empty()) {
119         auto const shadersPath = fileManager_.OpenDirectory(desc.shaderPath);
120         if (shadersPath) {
121             RecurseDirectory(desc.shaderPath, *shadersPath);
122         } else {
123             PLUGIN_LOG_W("shader path (%s) not found.", desc.shaderPath.data());
124         }
125     }
126 }
127 
LoadFile(const string_view uri,const bool forceReload)128 void ShaderLoader::LoadFile(const string_view uri, const bool forceReload)
129 {
130     const IDirectory::Entry entry = fileManager_.GetEntry(uri);
131     if (entry.type == IDirectory::Entry::FILE) {
132         // NOTE: currently there's no info within the shader json files
133         // we do type evaluation based on some key names in the json
134         const ShaderDataFileType shaderDataFileType = GetShaderDataFileType(fileManager_, uri);
135         switch (shaderDataFileType) {
136             case ShaderDataFileType::SHADER: {
137                 // Force re-loads the shader module creation
138                 HandleShaderFile(uri, entry, forceReload);
139                 break;
140             }
141             case ShaderDataFileType::SHADER_STATE: {
142                 HandleShaderStateFile(uri, entry);
143                 break;
144             }
145             case ShaderDataFileType::PIPELINE_LAYOUT: {
146                 HandlePipelineLayoutFile(uri, entry);
147                 break;
148             }
149             case ShaderDataFileType::VERTEX_INPUT_DECLARATION: {
150                 HandleVertexInputDeclarationFile(uri, entry);
151                 break;
152             }
153             default: {
154                 break;
155             }
156         }
157     }
158 }
159 
HandleShaderFile(const string_view fullFileName,const IDirectory::Entry & entry,const bool forceReload)160 void ShaderLoader::HandleShaderFile(
161     const string_view fullFileName, const IDirectory::Entry& entry, const bool forceReload)
162 {
163     if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::SHADER].data(), entry.name)) {
164         ShaderDataLoader loader;
165         const auto result = loader.Load(fileManager_, fullFileName);
166         if (result.success) {
167             auto const handle = CreateShader(loader, forceReload);
168 #if (RENDER_DEV_ENABLED == 1)
169             const auto shaderVariants = loader.GetShaderVariants();
170             for (const auto& shaderVariant : shaderVariants) {
171                 // Dev related book-keeping for reloading of spv files
172                 auto const handleType = handle.GetHandleType();
173                 if (handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
174                     string compShader = shaderVariant.computeShader;
175                     PLUGIN_ASSERT(!compShader.empty());
176 
177                     auto& ref = fileToShaderNames_[move(compShader)];
178                     ref.shaderStageFlags = ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT;
179                     ref.shaderNames.emplace_back(fullFileName);
180                 } else if (handleType == RenderHandleType::SHADER_STATE_OBJECT) {
181                     string vertShader = shaderVariant.vertexShader;
182                     string fragShader = shaderVariant.fragmentShader;
183                     PLUGIN_ASSERT_MSG(
184                         (!vertShader.empty()) && (!fragShader.empty()), "shader name: %s", fullFileName.data());
185 
186                     auto& refVert = fileToShaderNames_[move(vertShader)];
187                     refVert.shaderStageFlags = ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT;
188                     refVert.shaderNames.emplace_back(fullFileName);
189                     auto& refFrag = fileToShaderNames_[move(fragShader)];
190                     refFrag.shaderStageFlags = ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT;
191                     refFrag.shaderNames.emplace_back(fullFileName);
192                 }
193             }
194 #endif
195         } else {
196             PLUGIN_LOG_E("unable to load shader json %s : %s", fullFileName.data(), result.error.c_str());
197         }
198     }
199 }
200 
HandleShaderStateFile(const string_view fullFileName,const IDirectory::Entry & entry)201 void ShaderLoader::HandleShaderStateFile(const string_view fullFileName, const IDirectory::Entry& entry)
202 {
203     if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::SHADER_STATE].data(), entry.name)) {
204         ShaderStateLoader loader;
205         const auto result = loader.Load(fileManager_, fullFileName);
206         if (result.success) {
207             CreateShaderStates(loader.GetUri(), loader.GetGraphicsStateVariantData(), loader.GetGraphicsStates());
208         } else {
209             PLUGIN_LOG_E("unable to load shader state json %s : %s", fullFileName.data(), result.error.c_str());
210         }
211     }
212 }
213 
HandlePipelineLayoutFile(const string_view fullFileName,const IDirectory::Entry & entry)214 void ShaderLoader::HandlePipelineLayoutFile(const string_view fullFileName, const IDirectory::Entry& entry)
215 {
216     if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::PIPELINE_LAYOUT].data(), entry.name)) {
217         PipelineLayoutLoader loader;
218         const auto result = loader.Load(fileManager_, fullFileName);
219         if (result.success) {
220             auto const handle = CreatePipelineLayout(loader);
221             if (!handle) {
222                 PLUGIN_LOG_E(
223                     "pipeline layout could not be created (%s) (%s)", fullFileName.data(), loader.GetUri().data());
224             }
225         } else {
226             PLUGIN_LOG_E("unable to load pipeline layout json %s : %s", fullFileName.data(), result.error.c_str());
227         }
228     }
229 }
230 
HandleVertexInputDeclarationFile(const string_view fullFileName,const IDirectory::Entry & entry)231 void ShaderLoader::HandleVertexInputDeclarationFile(const string_view fullFileName, const IDirectory::Entry& entry)
232 {
233     if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::VERTEX_INPUT_DECLARATION].data(), entry.name)) {
234         VertexInputDeclarationLoader loader;
235         const auto result = loader.Load(fileManager_, fullFileName);
236         if (result.success) {
237             auto const vidName = loader.GetUri();
238             auto const handle = CreateVertexInputDeclaration(loader);
239             if (!handle) {
240                 PLUGIN_LOG_E(
241                     "vertex input declaration could not be created (%s) (%s)", fullFileName.data(), vidName.data());
242             }
243         } else {
244             PLUGIN_LOG_E(
245                 "unable to load vertex input declaration json %s : %s", fullFileName.data(), result.error.c_str());
246         }
247     }
248 }
249 
RecurseDirectory(const string_view currentPath,const IDirectory & directory)250 void ShaderLoader::RecurseDirectory(const string_view currentPath, const IDirectory& directory)
251 {
252     for (auto const& entry : directory.GetEntries()) {
253         switch (entry.type) {
254             default:
255             case IDirectory::Entry::Type::UNKNOWN:
256                 break;
257             case IDirectory::Entry::Type::FILE: {
258                 // does not force the shader module re-creations
259                 HandleShaderFile(currentPath + entry.name, entry, false);
260                 break;
261             }
262             case IDirectory::Entry::Type::DIRECTORY: {
263                 if (entry.name == "." || entry.name == "..") {
264                     continue;
265                 }
266                 auto nextDirectory = currentPath + entry.name + '/';
267                 auto dir = fileManager_.OpenDirectory(nextDirectory);
268                 if (dir) {
269                     RecurseDirectory(nextDirectory, *dir);
270                 }
271                 break;
272             }
273         }
274     }
275 }
276 
LoadShaderFile(const string_view shader,const ShaderStageFlags stageBits)277 ShaderLoader::ShaderFile ShaderLoader::LoadShaderFile(const string_view shader, const ShaderStageFlags stageBits)
278 {
279     ShaderLoader::ShaderFile info;
280     IFile::Ptr shaderFile;
281     switch (type_) {
282         case DeviceBackendType::VULKAN:
283             shaderFile = fileManager_.OpenFile(shader);
284             break;
285         case DeviceBackendType::OPENGLES:
286             shaderFile = fileManager_.OpenFile(shader + ".gles");
287             break;
288         case DeviceBackendType::OPENGL:
289             shaderFile = fileManager_.OpenFile(shader + ".gl");
290             break;
291         default:
292             break;
293     }
294     if (shaderFile) {
295         info.data = ReadFile(*shaderFile);
296 
297         if (IFile::Ptr reflectionFile = fileManager_.OpenFile(shader + ".lsb"); reflectionFile) {
298             info.reflectionData = ReadFile(*reflectionFile);
299         }
300         info.info = { stageBits, info.data, { info.reflectionData } };
301     } else {
302         PLUGIN_LOG_E("shader file not found (%s)", shader.data());
303     }
304     return info;
305 }
306 
CreateComputeShader(const ShaderDataLoader & dataLoader,const bool forceReload)307 RenderHandleReference ShaderLoader::CreateComputeShader(const ShaderDataLoader& dataLoader, const bool forceReload)
308 {
309     RenderHandleReference firstShaderVariantRhr;
310     const array_view<const ShaderDataLoader::ShaderVariant> shaderVariants = dataLoader.GetShaderVariants();
311     for (const auto& shaderVariant : shaderVariants) {
312         const string_view computeShader = shaderVariant.computeShader;
313         uint32_t index = INVALID_SM_INDEX;
314         if (!forceReload) {
315             index = shaderMgr_.GetShaderModuleIndex(computeShader);
316         }
317         if (index == INVALID_SM_INDEX) {
318             const auto shaderFile = LoadShaderFile(computeShader, ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT);
319             if (!shaderFile.data.empty()) {
320                 index = shaderMgr_.CreateShaderModule(computeShader, shaderFile.info);
321             } else {
322                 PLUGIN_LOG_E("shader file not found (%s)", computeShader.data());
323             }
324         }
325         if (index != INVALID_SM_INDEX) {
326             const string_view uri = dataLoader.GetUri();
327             const string_view baseShaderPath = dataLoader.GetBaseShader();
328             const string_view baseCategory = dataLoader.GetBaseCategory();
329             const string_view variantName = shaderVariant.variantName;
330             const string_view displayName = shaderVariant.displayName;
331             const string_view pipelineLayout = shaderVariant.pipelineLayout;
332             const string_view renderSlot = shaderVariant.renderSlot;
333             const string_view shaderFileStr = shaderVariant.shaderFileStr;
334             const string_view matMetadataStr = shaderVariant.materialMetadata;
335             const uint32_t rsId = shaderMgr_.CreateRenderSlotId(renderSlot);
336             const uint32_t catId = shaderMgr_.CreateCategoryId(baseCategory);
337             const uint32_t plIndex =
338                 (pipelineLayout.empty())
339                     ? INVALID_SM_INDEX
340                     : RenderHandleUtil::GetIndexPart(shaderMgr_.GetPipelineLayoutHandle(pipelineLayout).GetHandle());
341             // if many variants, the first is shader created without variant name
342             // it will have additional name for searching though
343             RenderHandleReference rhr;
344             if (!firstShaderVariantRhr) {
345                 // NOTE: empty variant name
346                 rhr = shaderMgr_.Create(
347                     ComputeShaderCreateData { uri, rsId, catId, plIndex, index, shaderFileStr, matMetadataStr },
348                     { baseShaderPath, {}, displayName });
349                 firstShaderVariantRhr = rhr;
350                 // add additional fullname with variant for the base shader
351                 if (!variantName.empty()) {
352                     shaderMgr_.AddAdditionalNameForHandle(rhr, uri);
353                 }
354             } else {
355                 rhr = shaderMgr_.Create(
356                     ComputeShaderCreateData { uri, rsId, catId, plIndex, index, shaderFileStr, matMetadataStr },
357                     { baseShaderPath, variantName, displayName });
358             }
359             if (shaderVariant.renderSlotDefaultShader) {
360                 shaderMgr_.SetRenderSlotData(rsId, rhr, {});
361             }
362         } else {
363             PLUGIN_LOG_E("Failed to load shader : %s", computeShader.data());
364         }
365     }
366     return firstShaderVariantRhr;
367 }
368 
CreateGraphicsShader(const ShaderDataLoader & dataLoader,const bool forceReload)369 RenderHandleReference ShaderLoader::CreateGraphicsShader(const ShaderDataLoader& dataLoader, const bool forceReload)
370 {
371     RenderHandleReference firstShaderVariantRhr;
372     const array_view<const ShaderDataLoader::ShaderVariant> shaderVariants = dataLoader.GetShaderVariants();
373     for (const auto& svRef : shaderVariants) {
374         const string_view vertexShader = svRef.vertexShader;
375         const string_view fragmentShader = svRef.fragmentShader;
376         uint32_t vertIndex = (forceReload) ? INVALID_SM_INDEX : shaderMgr_.GetShaderModuleIndex(vertexShader);
377         if (vertIndex == INVALID_SM_INDEX) {
378             const auto shaderFile = LoadShaderFile(vertexShader, ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT);
379             if (!shaderFile.data.empty()) {
380                 vertIndex = shaderMgr_.CreateShaderModule(vertexShader, shaderFile.info);
381             }
382         }
383         uint32_t fragIndex = (forceReload) ? INVALID_SM_INDEX : shaderMgr_.GetShaderModuleIndex(fragmentShader);
384         if (fragIndex == INVALID_SM_INDEX) {
385             const auto shaderFile = LoadShaderFile(fragmentShader, ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT);
386             if (!shaderFile.data.empty()) {
387                 fragIndex = shaderMgr_.CreateShaderModule(fragmentShader, shaderFile.info);
388             }
389         }
390         if ((vertIndex != INVALID_SM_INDEX) && (fragIndex != INVALID_SM_INDEX)) {
391             const string_view uri = dataLoader.GetUri();
392             // creating the default graphics state with full name
393             const string fullName = uri + svRef.variantName;
394             // default graphics state is created beforehand
395             const RenderHandleReference defaultGfxState = shaderMgr_.CreateGraphicsState(
396                 { fullName, svRef.graphicsState }, { svRef.renderSlot, {}, {}, {}, svRef.stateFlags });
397             const uint32_t rsId = shaderMgr_.CreateRenderSlotId(svRef.renderSlot);
398             const uint32_t catId = shaderMgr_.CreateCategoryId(dataLoader.GetBaseCategory());
399             const uint32_t plIndex = svRef.pipelineLayout.empty()
400                                          ? INVALID_SM_INDEX
401                                          : RenderHandleUtil::GetIndexPart(
402                                             shaderMgr_.GetPipelineLayoutHandle(svRef.pipelineLayout).GetHandle());
403             const uint32_t vidIndex =
404                 svRef.vertexInputDeclaration.empty()
405                     ? INVALID_SM_INDEX
406                     : RenderHandleUtil::GetIndexPart(
407                           shaderMgr_.GetVertexInputDeclarationHandle(svRef.vertexInputDeclaration).GetHandle());
408             const uint32_t stateIndex = RenderHandleUtil::GetIndexPart(defaultGfxState.GetHandle());
409             const string_view shaderStr = svRef.shaderFileStr;
410             const string_view matMeta = svRef.materialMetadata;
411             // if many variants, the first is shader created without variant name
412             // it will have additional name for searching though
413             RenderHandleReference rhr;
414             if (!firstShaderVariantRhr) {
415                 // NOTE: empty variant name
416                 rhr = shaderMgr_.Create(
417                     { uri, rsId, catId, vidIndex, plIndex, stateIndex, vertIndex, fragIndex, shaderStr, matMeta },
418                     { dataLoader.GetBaseShader(), {}, svRef.displayName });
419                 firstShaderVariantRhr = rhr;
420                 // add additional fullname with variant for the base shader
421                 if (!svRef.variantName.empty()) {
422                     shaderMgr_.AddAdditionalNameForHandle(firstShaderVariantRhr, fullName);
423                 }
424             } else {
425                 rhr = shaderMgr_.Create(
426                     { uri, rsId, catId, vidIndex, plIndex, stateIndex, vertIndex, fragIndex, shaderStr, matMeta },
427                     { dataLoader.GetBaseShader(), svRef.variantName, svRef.displayName });
428             }
429             if (svRef.renderSlotDefaultShader) {
430                 shaderMgr_.SetRenderSlotData(rsId, rhr, {});
431             }
432         } else {
433             PLUGIN_LOG_E("Failed to load shader : %s %s", vertexShader.data(), fragmentShader.data());
434         }
435     }
436     return firstShaderVariantRhr;
437 }
438 
CreateShader(const ShaderDataLoader & dataLoader,const bool forceReload)439 RenderHandleReference ShaderLoader::CreateShader(const ShaderDataLoader& dataLoader, const bool forceReload)
440 {
441     const array_view<const ShaderDataLoader::ShaderVariant> shaderVariants = dataLoader.GetShaderVariants();
442     if (shaderVariants.empty()) {
443         return {};
444     }
445 
446     const string_view compShader = shaderVariants[0].computeShader;
447     if (!compShader.empty()) {
448         return CreateComputeShader(dataLoader, forceReload);
449     } else {
450         const string_view vertShader = shaderVariants[0].vertexShader;
451         const string_view fragShader = shaderVariants[0].fragmentShader;
452         if (!vertShader.empty() && !fragShader.empty()) {
453             return CreateGraphicsShader(dataLoader, forceReload);
454         }
455     }
456     return {};
457 }
458 
LoadShaderStates(const string_view currentPath,const IDirectory & directory)459 void ShaderLoader::LoadShaderStates(const string_view currentPath, const IDirectory& directory)
460 {
461     for (auto const& entry : directory.GetEntries()) {
462         switch (entry.type) {
463             default:
464             case IDirectory::Entry::Type::UNKNOWN:
465                 break;
466             case IDirectory::Entry::Type::FILE: {
467                 HandleShaderStateFile(currentPath + entry.name, entry);
468                 break;
469             }
470             case IDirectory::Entry::Type::DIRECTORY: {
471                 PLUGIN_LOG_I("recursive vertex input declarations directories not supported");
472                 break;
473             }
474         }
475     }
476 }
477 
CreateShaderStates(const string_view uri,const array_view<const ShaderStateLoaderVariantData> & variantData,const array_view<const GraphicsState> & states)478 void ShaderLoader::CreateShaderStates(const string_view uri,
479     const array_view<const ShaderStateLoaderVariantData>& variantData, const array_view<const GraphicsState>& states)
480 {
481     for (size_t stateIdx = 0; stateIdx < states.size(); ++stateIdx) {
482         const ShaderManager::GraphicsStateCreateInfo createInfo { uri, states[stateIdx] };
483         const auto& variant = variantData[stateIdx];
484         const ShaderManager::GraphicsStateVariantCreateInfo variantCreateInfo { variant.renderSlot, variant.variantName,
485             variant.baseShaderState, variant.baseVariantName, variant.stateFlags };
486         const RenderHandleReference handle = shaderMgr_.CreateGraphicsState(createInfo, variantCreateInfo);
487         if (variant.renderSlotDefaultState && (!variant.renderSlot.empty())) {
488             const uint32_t renderSlotId = shaderMgr_.GetRenderSlotId(variant.renderSlot);
489             shaderMgr_.SetRenderSlotData(renderSlotId, {}, handle);
490         }
491         if (!handle) {
492             PLUGIN_LOG_E(
493                 "error creating graphics state (name: %s, variant: %s)", uri.data(), variant.variantName.data());
494         }
495     }
496 }
497 
LoadVids(const string_view currentPath,const IDirectory & directory)498 void ShaderLoader::LoadVids(const string_view currentPath, const IDirectory& directory)
499 {
500     for (auto const& entry : directory.GetEntries()) {
501         switch (entry.type) {
502             default:
503             case IDirectory::Entry::Type::UNKNOWN:
504                 break;
505             case IDirectory::Entry::Type::FILE: {
506                 HandleVertexInputDeclarationFile(currentPath + entry.name, entry);
507                 break;
508             }
509             case IDirectory::Entry::Type::DIRECTORY: {
510                 PLUGIN_LOG_I("recursive vertex input declarations directories not supported");
511                 break;
512             }
513         }
514     }
515 }
516 
CreateVertexInputDeclaration(const VertexInputDeclarationLoader & loader)517 RenderHandleReference ShaderLoader::CreateVertexInputDeclaration(const VertexInputDeclarationLoader& loader)
518 {
519     const string_view uri = loader.GetUri();
520     VertexInputDeclarationView dataView = loader.GetVertexInputDeclarationView();
521     return shaderMgr_.CreateVertexInputDeclaration({ uri, dataView });
522 }
523 
LoadPipelineLayouts(const string_view currentPath,const IDirectory & directory)524 void ShaderLoader::LoadPipelineLayouts(const string_view currentPath, const IDirectory& directory)
525 {
526     for (auto const& entry : directory.GetEntries()) {
527         switch (entry.type) {
528             default:
529             case IDirectory::Entry::Type::UNKNOWN:
530                 break;
531             case IDirectory::Entry::Type::FILE: {
532                 HandlePipelineLayoutFile(currentPath + entry.name, entry);
533                 break;
534             }
535             case IDirectory::Entry::Type::DIRECTORY: {
536                 PLUGIN_LOG_I("recursive pipeline layout directories not supported");
537                 break;
538             }
539         }
540     }
541 }
542 
CreatePipelineLayout(const PipelineLayoutLoader & loader)543 RenderHandleReference ShaderLoader::CreatePipelineLayout(const PipelineLayoutLoader& loader)
544 {
545     const string_view uri = loader.GetUri();
546     const PipelineLayout& pipelineLayout = loader.GetPipelineLayout();
547     return shaderMgr_.CreatePipelineLayout({ uri, pipelineLayout });
548 }
549 RENDER_END_NAMESPACE()
550