18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "loader/shader_loader.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <cstring>
198bf80f4bSopenharmony_ci#include <set>
208bf80f4bSopenharmony_ci
218bf80f4bSopenharmony_ci#include <base/containers/array_view.h>
228bf80f4bSopenharmony_ci#include <base/containers/vector.h>
238bf80f4bSopenharmony_ci#include <core/io/intf_file_manager.h>
248bf80f4bSopenharmony_ci#include <render/device/gpu_resource_desc.h>
258bf80f4bSopenharmony_ci#include <render/device/pipeline_layout_desc.h>
268bf80f4bSopenharmony_ci#include <render/namespace.h>
278bf80f4bSopenharmony_ci
288bf80f4bSopenharmony_ci#include "device/shader_manager.h"
298bf80f4bSopenharmony_ci#include "loader/json_util.h"
308bf80f4bSopenharmony_ci#include "loader/pipeline_layout_loader.h"
318bf80f4bSopenharmony_ci#include "loader/shader_data_loader.h"
328bf80f4bSopenharmony_ci#include "loader/shader_state_loader.h"
338bf80f4bSopenharmony_ci#include "loader/vertex_input_declaration_loader.h"
348bf80f4bSopenharmony_ci#include "util/log.h"
358bf80f4bSopenharmony_ci
368bf80f4bSopenharmony_ciusing namespace BASE_NS;
378bf80f4bSopenharmony_ciusing namespace CORE_NS;
388bf80f4bSopenharmony_ci
398bf80f4bSopenharmony_ciRENDER_BEGIN_NAMESPACE()
408bf80f4bSopenharmony_cinamespace {
418bf80f4bSopenharmony_cienum ShaderDataFileType : uint32_t {
428bf80f4bSopenharmony_ci    UNDEFINED = 0,
438bf80f4bSopenharmony_ci    SHADER = 1,
448bf80f4bSopenharmony_ci    SHADER_STATE = 2,
458bf80f4bSopenharmony_ci    VERTEX_INPUT_DECLARATION = 3,
468bf80f4bSopenharmony_ci    PIPELINE_LAYOUT = 4,
478bf80f4bSopenharmony_ci};
488bf80f4bSopenharmony_ci
498bf80f4bSopenharmony_ciconstexpr string_view ShaderDataFileExtensions[] {
508bf80f4bSopenharmony_ci    "",
518bf80f4bSopenharmony_ci    ".shader",
528bf80f4bSopenharmony_ci    ".shadergs",
538bf80f4bSopenharmony_ci    ".shadervid",
548bf80f4bSopenharmony_ci    ".shaderpl",
558bf80f4bSopenharmony_ci};
568bf80f4bSopenharmony_ci
578bf80f4bSopenharmony_cibool HasExtension(const char* ext, const string_view fileUri)
588bf80f4bSopenharmony_ci{
598bf80f4bSopenharmony_ci    if (auto const pos = fileUri.rfind(ext); pos != string_view::npos) {
608bf80f4bSopenharmony_ci        return std::strlen(ext) == (fileUri.length() - pos);
618bf80f4bSopenharmony_ci    }
628bf80f4bSopenharmony_ci    return false;
638bf80f4bSopenharmony_ci}
648bf80f4bSopenharmony_ci
658bf80f4bSopenharmony_ciShaderDataFileType GetShaderDataFileType(IFileManager& fileMgr, const string_view fullFilename)
668bf80f4bSopenharmony_ci{
678bf80f4bSopenharmony_ci    if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::SHADER].data(), fullFilename)) {
688bf80f4bSopenharmony_ci        return ShaderDataFileType::SHADER;
698bf80f4bSopenharmony_ci    } else if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::SHADER_STATE].data(), fullFilename)) {
708bf80f4bSopenharmony_ci        return ShaderDataFileType::SHADER_STATE;
718bf80f4bSopenharmony_ci    } else if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::PIPELINE_LAYOUT].data(), fullFilename)) {
728bf80f4bSopenharmony_ci        return ShaderDataFileType::PIPELINE_LAYOUT;
738bf80f4bSopenharmony_ci    } else if (HasExtension(
748bf80f4bSopenharmony_ci                   ShaderDataFileExtensions[ShaderDataFileType::VERTEX_INPUT_DECLARATION].data(), fullFilename)) {
758bf80f4bSopenharmony_ci        return ShaderDataFileType::VERTEX_INPUT_DECLARATION;
768bf80f4bSopenharmony_ci    }
778bf80f4bSopenharmony_ci    return ShaderDataFileType::UNDEFINED;
788bf80f4bSopenharmony_ci}
798bf80f4bSopenharmony_ci
808bf80f4bSopenharmony_civector<uint8_t> ReadFile(IFile& file)
818bf80f4bSopenharmony_ci{
828bf80f4bSopenharmony_ci    auto fileData = vector<uint8_t>(static_cast<std::size_t>(file.GetLength()));
838bf80f4bSopenharmony_ci    file.Read(fileData.data(), fileData.size());
848bf80f4bSopenharmony_ci    return fileData;
858bf80f4bSopenharmony_ci}
868bf80f4bSopenharmony_ci} // namespace
878bf80f4bSopenharmony_ci
888bf80f4bSopenharmony_ciShaderLoader::ShaderLoader(IFileManager& fileManager, ShaderManager& shaderManager, const DeviceBackendType type)
898bf80f4bSopenharmony_ci    : fileManager_(fileManager), shaderMgr_(shaderManager), type_(type)
908bf80f4bSopenharmony_ci{}
918bf80f4bSopenharmony_ci
928bf80f4bSopenharmony_civoid ShaderLoader::Load(const ShaderManager::ShaderFilePathDesc& desc)
938bf80f4bSopenharmony_ci{
948bf80f4bSopenharmony_ci    if (!desc.shaderStatePath.empty()) {
958bf80f4bSopenharmony_ci        auto const shaderStatesPath = fileManager_.OpenDirectory(desc.shaderStatePath);
968bf80f4bSopenharmony_ci        if (shaderStatesPath) {
978bf80f4bSopenharmony_ci            LoadShaderStates(desc.shaderStatePath, *shaderStatesPath);
988bf80f4bSopenharmony_ci        } else {
998bf80f4bSopenharmony_ci            PLUGIN_LOG_W("graphics state path (%s) not found.", desc.shaderStatePath.data());
1008bf80f4bSopenharmony_ci        }
1018bf80f4bSopenharmony_ci    }
1028bf80f4bSopenharmony_ci    if (!desc.vertexInputDeclarationPath.empty()) {
1038bf80f4bSopenharmony_ci        auto const vidsPath = fileManager_.OpenDirectory(desc.vertexInputDeclarationPath);
1048bf80f4bSopenharmony_ci        if (vidsPath) {
1058bf80f4bSopenharmony_ci            LoadVids(desc.vertexInputDeclarationPath, *vidsPath);
1068bf80f4bSopenharmony_ci        } else {
1078bf80f4bSopenharmony_ci            PLUGIN_LOG_W("vertex input declaration path (%s) not found.", desc.vertexInputDeclarationPath.data());
1088bf80f4bSopenharmony_ci        }
1098bf80f4bSopenharmony_ci    }
1108bf80f4bSopenharmony_ci    if (!desc.pipelineLayoutPath.empty()) {
1118bf80f4bSopenharmony_ci        auto const pipelineLayoutsPath = fileManager_.OpenDirectory(desc.pipelineLayoutPath);
1128bf80f4bSopenharmony_ci        if (pipelineLayoutsPath) {
1138bf80f4bSopenharmony_ci            LoadPipelineLayouts(desc.pipelineLayoutPath, *pipelineLayoutsPath);
1148bf80f4bSopenharmony_ci        } else {
1158bf80f4bSopenharmony_ci            PLUGIN_LOG_W("pipeline layout path (%s) not found.", desc.pipelineLayoutPath.data());
1168bf80f4bSopenharmony_ci        }
1178bf80f4bSopenharmony_ci    }
1188bf80f4bSopenharmony_ci    if (!desc.shaderPath.empty()) {
1198bf80f4bSopenharmony_ci        auto const shadersPath = fileManager_.OpenDirectory(desc.shaderPath);
1208bf80f4bSopenharmony_ci        if (shadersPath) {
1218bf80f4bSopenharmony_ci            RecurseDirectory(desc.shaderPath, *shadersPath);
1228bf80f4bSopenharmony_ci        } else {
1238bf80f4bSopenharmony_ci            PLUGIN_LOG_W("shader path (%s) not found.", desc.shaderPath.data());
1248bf80f4bSopenharmony_ci        }
1258bf80f4bSopenharmony_ci    }
1268bf80f4bSopenharmony_ci}
1278bf80f4bSopenharmony_ci
1288bf80f4bSopenharmony_civoid ShaderLoader::LoadFile(const string_view uri, const bool forceReload)
1298bf80f4bSopenharmony_ci{
1308bf80f4bSopenharmony_ci    const IDirectory::Entry entry = fileManager_.GetEntry(uri);
1318bf80f4bSopenharmony_ci    if (entry.type == IDirectory::Entry::FILE) {
1328bf80f4bSopenharmony_ci        // NOTE: currently there's no info within the shader json files
1338bf80f4bSopenharmony_ci        // we do type evaluation based on some key names in the json
1348bf80f4bSopenharmony_ci        const ShaderDataFileType shaderDataFileType = GetShaderDataFileType(fileManager_, uri);
1358bf80f4bSopenharmony_ci        switch (shaderDataFileType) {
1368bf80f4bSopenharmony_ci            case ShaderDataFileType::SHADER: {
1378bf80f4bSopenharmony_ci                // Force re-loads the shader module creation
1388bf80f4bSopenharmony_ci                HandleShaderFile(uri, entry, forceReload);
1398bf80f4bSopenharmony_ci                break;
1408bf80f4bSopenharmony_ci            }
1418bf80f4bSopenharmony_ci            case ShaderDataFileType::SHADER_STATE: {
1428bf80f4bSopenharmony_ci                HandleShaderStateFile(uri, entry);
1438bf80f4bSopenharmony_ci                break;
1448bf80f4bSopenharmony_ci            }
1458bf80f4bSopenharmony_ci            case ShaderDataFileType::PIPELINE_LAYOUT: {
1468bf80f4bSopenharmony_ci                HandlePipelineLayoutFile(uri, entry);
1478bf80f4bSopenharmony_ci                break;
1488bf80f4bSopenharmony_ci            }
1498bf80f4bSopenharmony_ci            case ShaderDataFileType::VERTEX_INPUT_DECLARATION: {
1508bf80f4bSopenharmony_ci                HandleVertexInputDeclarationFile(uri, entry);
1518bf80f4bSopenharmony_ci                break;
1528bf80f4bSopenharmony_ci            }
1538bf80f4bSopenharmony_ci            default: {
1548bf80f4bSopenharmony_ci                break;
1558bf80f4bSopenharmony_ci            }
1568bf80f4bSopenharmony_ci        }
1578bf80f4bSopenharmony_ci    }
1588bf80f4bSopenharmony_ci}
1598bf80f4bSopenharmony_ci
1608bf80f4bSopenharmony_civoid ShaderLoader::HandleShaderFile(
1618bf80f4bSopenharmony_ci    const string_view fullFileName, const IDirectory::Entry& entry, const bool forceReload)
1628bf80f4bSopenharmony_ci{
1638bf80f4bSopenharmony_ci    if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::SHADER].data(), entry.name)) {
1648bf80f4bSopenharmony_ci        ShaderDataLoader loader;
1658bf80f4bSopenharmony_ci        const auto result = loader.Load(fileManager_, fullFileName);
1668bf80f4bSopenharmony_ci        if (result.success) {
1678bf80f4bSopenharmony_ci            auto const handle = CreateShader(loader, forceReload);
1688bf80f4bSopenharmony_ci#if (RENDER_DEV_ENABLED == 1)
1698bf80f4bSopenharmony_ci            const auto shaderVariants = loader.GetShaderVariants();
1708bf80f4bSopenharmony_ci            for (const auto& shaderVariant : shaderVariants) {
1718bf80f4bSopenharmony_ci                // Dev related book-keeping for reloading of spv files
1728bf80f4bSopenharmony_ci                auto const handleType = handle.GetHandleType();
1738bf80f4bSopenharmony_ci                if (handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
1748bf80f4bSopenharmony_ci                    string compShader = shaderVariant.computeShader;
1758bf80f4bSopenharmony_ci                    PLUGIN_ASSERT(!compShader.empty());
1768bf80f4bSopenharmony_ci
1778bf80f4bSopenharmony_ci                    auto& ref = fileToShaderNames_[move(compShader)];
1788bf80f4bSopenharmony_ci                    ref.shaderStageFlags = ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT;
1798bf80f4bSopenharmony_ci                    ref.shaderNames.emplace_back(fullFileName);
1808bf80f4bSopenharmony_ci                } else if (handleType == RenderHandleType::SHADER_STATE_OBJECT) {
1818bf80f4bSopenharmony_ci                    string vertShader = shaderVariant.vertexShader;
1828bf80f4bSopenharmony_ci                    string fragShader = shaderVariant.fragmentShader;
1838bf80f4bSopenharmony_ci                    PLUGIN_ASSERT_MSG(
1848bf80f4bSopenharmony_ci                        (!vertShader.empty()) && (!fragShader.empty()), "shader name: %s", fullFileName.data());
1858bf80f4bSopenharmony_ci
1868bf80f4bSopenharmony_ci                    auto& refVert = fileToShaderNames_[move(vertShader)];
1878bf80f4bSopenharmony_ci                    refVert.shaderStageFlags = ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT;
1888bf80f4bSopenharmony_ci                    refVert.shaderNames.emplace_back(fullFileName);
1898bf80f4bSopenharmony_ci                    auto& refFrag = fileToShaderNames_[move(fragShader)];
1908bf80f4bSopenharmony_ci                    refFrag.shaderStageFlags = ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT;
1918bf80f4bSopenharmony_ci                    refFrag.shaderNames.emplace_back(fullFileName);
1928bf80f4bSopenharmony_ci                }
1938bf80f4bSopenharmony_ci            }
1948bf80f4bSopenharmony_ci#endif
1958bf80f4bSopenharmony_ci        } else {
1968bf80f4bSopenharmony_ci            PLUGIN_LOG_E("unable to load shader json %s : %s", fullFileName.data(), result.error.c_str());
1978bf80f4bSopenharmony_ci        }
1988bf80f4bSopenharmony_ci    }
1998bf80f4bSopenharmony_ci}
2008bf80f4bSopenharmony_ci
2018bf80f4bSopenharmony_civoid ShaderLoader::HandleShaderStateFile(const string_view fullFileName, const IDirectory::Entry& entry)
2028bf80f4bSopenharmony_ci{
2038bf80f4bSopenharmony_ci    if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::SHADER_STATE].data(), entry.name)) {
2048bf80f4bSopenharmony_ci        ShaderStateLoader loader;
2058bf80f4bSopenharmony_ci        const auto result = loader.Load(fileManager_, fullFileName);
2068bf80f4bSopenharmony_ci        if (result.success) {
2078bf80f4bSopenharmony_ci            CreateShaderStates(loader.GetUri(), loader.GetGraphicsStateVariantData(), loader.GetGraphicsStates());
2088bf80f4bSopenharmony_ci        } else {
2098bf80f4bSopenharmony_ci            PLUGIN_LOG_E("unable to load shader state json %s : %s", fullFileName.data(), result.error.c_str());
2108bf80f4bSopenharmony_ci        }
2118bf80f4bSopenharmony_ci    }
2128bf80f4bSopenharmony_ci}
2138bf80f4bSopenharmony_ci
2148bf80f4bSopenharmony_civoid ShaderLoader::HandlePipelineLayoutFile(const string_view fullFileName, const IDirectory::Entry& entry)
2158bf80f4bSopenharmony_ci{
2168bf80f4bSopenharmony_ci    if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::PIPELINE_LAYOUT].data(), entry.name)) {
2178bf80f4bSopenharmony_ci        PipelineLayoutLoader loader;
2188bf80f4bSopenharmony_ci        const auto result = loader.Load(fileManager_, fullFileName);
2198bf80f4bSopenharmony_ci        if (result.success) {
2208bf80f4bSopenharmony_ci            auto const handle = CreatePipelineLayout(loader);
2218bf80f4bSopenharmony_ci            if (!handle) {
2228bf80f4bSopenharmony_ci                PLUGIN_LOG_E(
2238bf80f4bSopenharmony_ci                    "pipeline layout could not be created (%s) (%s)", fullFileName.data(), loader.GetUri().data());
2248bf80f4bSopenharmony_ci            }
2258bf80f4bSopenharmony_ci        } else {
2268bf80f4bSopenharmony_ci            PLUGIN_LOG_E("unable to load pipeline layout json %s : %s", fullFileName.data(), result.error.c_str());
2278bf80f4bSopenharmony_ci        }
2288bf80f4bSopenharmony_ci    }
2298bf80f4bSopenharmony_ci}
2308bf80f4bSopenharmony_ci
2318bf80f4bSopenharmony_civoid ShaderLoader::HandleVertexInputDeclarationFile(const string_view fullFileName, const IDirectory::Entry& entry)
2328bf80f4bSopenharmony_ci{
2338bf80f4bSopenharmony_ci    if (HasExtension(ShaderDataFileExtensions[ShaderDataFileType::VERTEX_INPUT_DECLARATION].data(), entry.name)) {
2348bf80f4bSopenharmony_ci        VertexInputDeclarationLoader loader;
2358bf80f4bSopenharmony_ci        const auto result = loader.Load(fileManager_, fullFileName);
2368bf80f4bSopenharmony_ci        if (result.success) {
2378bf80f4bSopenharmony_ci            auto const vidName = loader.GetUri();
2388bf80f4bSopenharmony_ci            auto const handle = CreateVertexInputDeclaration(loader);
2398bf80f4bSopenharmony_ci            if (!handle) {
2408bf80f4bSopenharmony_ci                PLUGIN_LOG_E(
2418bf80f4bSopenharmony_ci                    "vertex input declaration could not be created (%s) (%s)", fullFileName.data(), vidName.data());
2428bf80f4bSopenharmony_ci            }
2438bf80f4bSopenharmony_ci        } else {
2448bf80f4bSopenharmony_ci            PLUGIN_LOG_E(
2458bf80f4bSopenharmony_ci                "unable to load vertex input declaration json %s : %s", fullFileName.data(), result.error.c_str());
2468bf80f4bSopenharmony_ci        }
2478bf80f4bSopenharmony_ci    }
2488bf80f4bSopenharmony_ci}
2498bf80f4bSopenharmony_ci
2508bf80f4bSopenharmony_civoid ShaderLoader::RecurseDirectory(const string_view currentPath, const IDirectory& directory)
2518bf80f4bSopenharmony_ci{
2528bf80f4bSopenharmony_ci    for (auto const& entry : directory.GetEntries()) {
2538bf80f4bSopenharmony_ci        switch (entry.type) {
2548bf80f4bSopenharmony_ci            default:
2558bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::UNKNOWN:
2568bf80f4bSopenharmony_ci                break;
2578bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::FILE: {
2588bf80f4bSopenharmony_ci                // does not force the shader module re-creations
2598bf80f4bSopenharmony_ci                HandleShaderFile(currentPath + entry.name, entry, false);
2608bf80f4bSopenharmony_ci                break;
2618bf80f4bSopenharmony_ci            }
2628bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::DIRECTORY: {
2638bf80f4bSopenharmony_ci                if (entry.name == "." || entry.name == "..") {
2648bf80f4bSopenharmony_ci                    continue;
2658bf80f4bSopenharmony_ci                }
2668bf80f4bSopenharmony_ci                auto nextDirectory = currentPath + entry.name + '/';
2678bf80f4bSopenharmony_ci                auto dir = fileManager_.OpenDirectory(nextDirectory);
2688bf80f4bSopenharmony_ci                if (dir) {
2698bf80f4bSopenharmony_ci                    RecurseDirectory(nextDirectory, *dir);
2708bf80f4bSopenharmony_ci                }
2718bf80f4bSopenharmony_ci                break;
2728bf80f4bSopenharmony_ci            }
2738bf80f4bSopenharmony_ci        }
2748bf80f4bSopenharmony_ci    }
2758bf80f4bSopenharmony_ci}
2768bf80f4bSopenharmony_ci
2778bf80f4bSopenharmony_ciShaderLoader::ShaderFile ShaderLoader::LoadShaderFile(const string_view shader, const ShaderStageFlags stageBits)
2788bf80f4bSopenharmony_ci{
2798bf80f4bSopenharmony_ci    ShaderLoader::ShaderFile info;
2808bf80f4bSopenharmony_ci    IFile::Ptr shaderFile;
2818bf80f4bSopenharmony_ci    switch (type_) {
2828bf80f4bSopenharmony_ci        case DeviceBackendType::VULKAN:
2838bf80f4bSopenharmony_ci            shaderFile = fileManager_.OpenFile(shader);
2848bf80f4bSopenharmony_ci            break;
2858bf80f4bSopenharmony_ci        case DeviceBackendType::OPENGLES:
2868bf80f4bSopenharmony_ci            shaderFile = fileManager_.OpenFile(shader + ".gles");
2878bf80f4bSopenharmony_ci            break;
2888bf80f4bSopenharmony_ci        case DeviceBackendType::OPENGL:
2898bf80f4bSopenharmony_ci            shaderFile = fileManager_.OpenFile(shader + ".gl");
2908bf80f4bSopenharmony_ci            break;
2918bf80f4bSopenharmony_ci        default:
2928bf80f4bSopenharmony_ci            break;
2938bf80f4bSopenharmony_ci    }
2948bf80f4bSopenharmony_ci    if (shaderFile) {
2958bf80f4bSopenharmony_ci        info.data = ReadFile(*shaderFile);
2968bf80f4bSopenharmony_ci
2978bf80f4bSopenharmony_ci        if (IFile::Ptr reflectionFile = fileManager_.OpenFile(shader + ".lsb"); reflectionFile) {
2988bf80f4bSopenharmony_ci            info.reflectionData = ReadFile(*reflectionFile);
2998bf80f4bSopenharmony_ci        }
3008bf80f4bSopenharmony_ci        info.info = { stageBits, info.data, { info.reflectionData } };
3018bf80f4bSopenharmony_ci    } else {
3028bf80f4bSopenharmony_ci        PLUGIN_LOG_E("shader file not found (%s)", shader.data());
3038bf80f4bSopenharmony_ci    }
3048bf80f4bSopenharmony_ci    return info;
3058bf80f4bSopenharmony_ci}
3068bf80f4bSopenharmony_ci
3078bf80f4bSopenharmony_ciRenderHandleReference ShaderLoader::CreateComputeShader(const ShaderDataLoader& dataLoader, const bool forceReload)
3088bf80f4bSopenharmony_ci{
3098bf80f4bSopenharmony_ci    RenderHandleReference firstShaderVariantRhr;
3108bf80f4bSopenharmony_ci    const array_view<const ShaderDataLoader::ShaderVariant> shaderVariants = dataLoader.GetShaderVariants();
3118bf80f4bSopenharmony_ci    for (const auto& shaderVariant : shaderVariants) {
3128bf80f4bSopenharmony_ci        const string_view computeShader = shaderVariant.computeShader;
3138bf80f4bSopenharmony_ci        uint32_t index = INVALID_SM_INDEX;
3148bf80f4bSopenharmony_ci        if (!forceReload) {
3158bf80f4bSopenharmony_ci            index = shaderMgr_.GetShaderModuleIndex(computeShader);
3168bf80f4bSopenharmony_ci        }
3178bf80f4bSopenharmony_ci        if (index == INVALID_SM_INDEX) {
3188bf80f4bSopenharmony_ci            const auto shaderFile = LoadShaderFile(computeShader, ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT);
3198bf80f4bSopenharmony_ci            if (!shaderFile.data.empty()) {
3208bf80f4bSopenharmony_ci                index = shaderMgr_.CreateShaderModule(computeShader, shaderFile.info);
3218bf80f4bSopenharmony_ci            } else {
3228bf80f4bSopenharmony_ci                PLUGIN_LOG_E("shader file not found (%s)", computeShader.data());
3238bf80f4bSopenharmony_ci            }
3248bf80f4bSopenharmony_ci        }
3258bf80f4bSopenharmony_ci        if (index != INVALID_SM_INDEX) {
3268bf80f4bSopenharmony_ci            const string_view uri = dataLoader.GetUri();
3278bf80f4bSopenharmony_ci            const string_view baseShaderPath = dataLoader.GetBaseShader();
3288bf80f4bSopenharmony_ci            const string_view baseCategory = dataLoader.GetBaseCategory();
3298bf80f4bSopenharmony_ci            const string_view variantName = shaderVariant.variantName;
3308bf80f4bSopenharmony_ci            const string_view displayName = shaderVariant.displayName;
3318bf80f4bSopenharmony_ci            const string_view pipelineLayout = shaderVariant.pipelineLayout;
3328bf80f4bSopenharmony_ci            const string_view renderSlot = shaderVariant.renderSlot;
3338bf80f4bSopenharmony_ci            const string_view shaderFileStr = shaderVariant.shaderFileStr;
3348bf80f4bSopenharmony_ci            const string_view matMetadataStr = shaderVariant.materialMetadata;
3358bf80f4bSopenharmony_ci            const uint32_t rsId = shaderMgr_.CreateRenderSlotId(renderSlot);
3368bf80f4bSopenharmony_ci            const uint32_t catId = shaderMgr_.CreateCategoryId(baseCategory);
3378bf80f4bSopenharmony_ci            const uint32_t plIndex =
3388bf80f4bSopenharmony_ci                (pipelineLayout.empty())
3398bf80f4bSopenharmony_ci                    ? INVALID_SM_INDEX
3408bf80f4bSopenharmony_ci                    : RenderHandleUtil::GetIndexPart(shaderMgr_.GetPipelineLayoutHandle(pipelineLayout).GetHandle());
3418bf80f4bSopenharmony_ci            // if many variants, the first is shader created without variant name
3428bf80f4bSopenharmony_ci            // it will have additional name for searching though
3438bf80f4bSopenharmony_ci            RenderHandleReference rhr;
3448bf80f4bSopenharmony_ci            if (!firstShaderVariantRhr) {
3458bf80f4bSopenharmony_ci                // NOTE: empty variant name
3468bf80f4bSopenharmony_ci                rhr = shaderMgr_.Create(
3478bf80f4bSopenharmony_ci                    ComputeShaderCreateData { uri, rsId, catId, plIndex, index, shaderFileStr, matMetadataStr },
3488bf80f4bSopenharmony_ci                    { baseShaderPath, {}, displayName });
3498bf80f4bSopenharmony_ci                firstShaderVariantRhr = rhr;
3508bf80f4bSopenharmony_ci                // add additional fullname with variant for the base shader
3518bf80f4bSopenharmony_ci                if (!variantName.empty()) {
3528bf80f4bSopenharmony_ci                    shaderMgr_.AddAdditionalNameForHandle(rhr, uri);
3538bf80f4bSopenharmony_ci                }
3548bf80f4bSopenharmony_ci            } else {
3558bf80f4bSopenharmony_ci                rhr = shaderMgr_.Create(
3568bf80f4bSopenharmony_ci                    ComputeShaderCreateData { uri, rsId, catId, plIndex, index, shaderFileStr, matMetadataStr },
3578bf80f4bSopenharmony_ci                    { baseShaderPath, variantName, displayName });
3588bf80f4bSopenharmony_ci            }
3598bf80f4bSopenharmony_ci            if (shaderVariant.renderSlotDefaultShader) {
3608bf80f4bSopenharmony_ci                shaderMgr_.SetRenderSlotData(rsId, rhr, {});
3618bf80f4bSopenharmony_ci            }
3628bf80f4bSopenharmony_ci        } else {
3638bf80f4bSopenharmony_ci            PLUGIN_LOG_E("Failed to load shader : %s", computeShader.data());
3648bf80f4bSopenharmony_ci        }
3658bf80f4bSopenharmony_ci    }
3668bf80f4bSopenharmony_ci    return firstShaderVariantRhr;
3678bf80f4bSopenharmony_ci}
3688bf80f4bSopenharmony_ci
3698bf80f4bSopenharmony_ciRenderHandleReference ShaderLoader::CreateGraphicsShader(const ShaderDataLoader& dataLoader, const bool forceReload)
3708bf80f4bSopenharmony_ci{
3718bf80f4bSopenharmony_ci    RenderHandleReference firstShaderVariantRhr;
3728bf80f4bSopenharmony_ci    const array_view<const ShaderDataLoader::ShaderVariant> shaderVariants = dataLoader.GetShaderVariants();
3738bf80f4bSopenharmony_ci    for (const auto& svRef : shaderVariants) {
3748bf80f4bSopenharmony_ci        const string_view vertexShader = svRef.vertexShader;
3758bf80f4bSopenharmony_ci        const string_view fragmentShader = svRef.fragmentShader;
3768bf80f4bSopenharmony_ci        uint32_t vertIndex = (forceReload) ? INVALID_SM_INDEX : shaderMgr_.GetShaderModuleIndex(vertexShader);
3778bf80f4bSopenharmony_ci        if (vertIndex == INVALID_SM_INDEX) {
3788bf80f4bSopenharmony_ci            const auto shaderFile = LoadShaderFile(vertexShader, ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT);
3798bf80f4bSopenharmony_ci            if (!shaderFile.data.empty()) {
3808bf80f4bSopenharmony_ci                vertIndex = shaderMgr_.CreateShaderModule(vertexShader, shaderFile.info);
3818bf80f4bSopenharmony_ci            }
3828bf80f4bSopenharmony_ci        }
3838bf80f4bSopenharmony_ci        uint32_t fragIndex = (forceReload) ? INVALID_SM_INDEX : shaderMgr_.GetShaderModuleIndex(fragmentShader);
3848bf80f4bSopenharmony_ci        if (fragIndex == INVALID_SM_INDEX) {
3858bf80f4bSopenharmony_ci            const auto shaderFile = LoadShaderFile(fragmentShader, ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT);
3868bf80f4bSopenharmony_ci            if (!shaderFile.data.empty()) {
3878bf80f4bSopenharmony_ci                fragIndex = shaderMgr_.CreateShaderModule(fragmentShader, shaderFile.info);
3888bf80f4bSopenharmony_ci            }
3898bf80f4bSopenharmony_ci        }
3908bf80f4bSopenharmony_ci        if ((vertIndex != INVALID_SM_INDEX) && (fragIndex != INVALID_SM_INDEX)) {
3918bf80f4bSopenharmony_ci            const string_view uri = dataLoader.GetUri();
3928bf80f4bSopenharmony_ci            // creating the default graphics state with full name
3938bf80f4bSopenharmony_ci            const string fullName = uri + svRef.variantName;
3948bf80f4bSopenharmony_ci            // default graphics state is created beforehand
3958bf80f4bSopenharmony_ci            const RenderHandleReference defaultGfxState = shaderMgr_.CreateGraphicsState(
3968bf80f4bSopenharmony_ci                { fullName, svRef.graphicsState }, { svRef.renderSlot, {}, {}, {}, svRef.stateFlags });
3978bf80f4bSopenharmony_ci            const uint32_t rsId = shaderMgr_.CreateRenderSlotId(svRef.renderSlot);
3988bf80f4bSopenharmony_ci            const uint32_t catId = shaderMgr_.CreateCategoryId(dataLoader.GetBaseCategory());
3998bf80f4bSopenharmony_ci            const uint32_t plIndex = svRef.pipelineLayout.empty()
4008bf80f4bSopenharmony_ci                                         ? INVALID_SM_INDEX
4018bf80f4bSopenharmony_ci                                         : RenderHandleUtil::GetIndexPart(
4028bf80f4bSopenharmony_ci                                            shaderMgr_.GetPipelineLayoutHandle(svRef.pipelineLayout).GetHandle());
4038bf80f4bSopenharmony_ci            const uint32_t vidIndex =
4048bf80f4bSopenharmony_ci                svRef.vertexInputDeclaration.empty()
4058bf80f4bSopenharmony_ci                    ? INVALID_SM_INDEX
4068bf80f4bSopenharmony_ci                    : RenderHandleUtil::GetIndexPart(
4078bf80f4bSopenharmony_ci                          shaderMgr_.GetVertexInputDeclarationHandle(svRef.vertexInputDeclaration).GetHandle());
4088bf80f4bSopenharmony_ci            const uint32_t stateIndex = RenderHandleUtil::GetIndexPart(defaultGfxState.GetHandle());
4098bf80f4bSopenharmony_ci            const string_view shaderStr = svRef.shaderFileStr;
4108bf80f4bSopenharmony_ci            const string_view matMeta = svRef.materialMetadata;
4118bf80f4bSopenharmony_ci            // if many variants, the first is shader created without variant name
4128bf80f4bSopenharmony_ci            // it will have additional name for searching though
4138bf80f4bSopenharmony_ci            RenderHandleReference rhr;
4148bf80f4bSopenharmony_ci            if (!firstShaderVariantRhr) {
4158bf80f4bSopenharmony_ci                // NOTE: empty variant name
4168bf80f4bSopenharmony_ci                rhr = shaderMgr_.Create(
4178bf80f4bSopenharmony_ci                    { uri, rsId, catId, vidIndex, plIndex, stateIndex, vertIndex, fragIndex, shaderStr, matMeta },
4188bf80f4bSopenharmony_ci                    { dataLoader.GetBaseShader(), {}, svRef.displayName });
4198bf80f4bSopenharmony_ci                firstShaderVariantRhr = rhr;
4208bf80f4bSopenharmony_ci                // add additional fullname with variant for the base shader
4218bf80f4bSopenharmony_ci                if (!svRef.variantName.empty()) {
4228bf80f4bSopenharmony_ci                    shaderMgr_.AddAdditionalNameForHandle(firstShaderVariantRhr, fullName);
4238bf80f4bSopenharmony_ci                }
4248bf80f4bSopenharmony_ci            } else {
4258bf80f4bSopenharmony_ci                rhr = shaderMgr_.Create(
4268bf80f4bSopenharmony_ci                    { uri, rsId, catId, vidIndex, plIndex, stateIndex, vertIndex, fragIndex, shaderStr, matMeta },
4278bf80f4bSopenharmony_ci                    { dataLoader.GetBaseShader(), svRef.variantName, svRef.displayName });
4288bf80f4bSopenharmony_ci            }
4298bf80f4bSopenharmony_ci            if (svRef.renderSlotDefaultShader) {
4308bf80f4bSopenharmony_ci                shaderMgr_.SetRenderSlotData(rsId, rhr, {});
4318bf80f4bSopenharmony_ci            }
4328bf80f4bSopenharmony_ci        } else {
4338bf80f4bSopenharmony_ci            PLUGIN_LOG_E("Failed to load shader : %s %s", vertexShader.data(), fragmentShader.data());
4348bf80f4bSopenharmony_ci        }
4358bf80f4bSopenharmony_ci    }
4368bf80f4bSopenharmony_ci    return firstShaderVariantRhr;
4378bf80f4bSopenharmony_ci}
4388bf80f4bSopenharmony_ci
4398bf80f4bSopenharmony_ciRenderHandleReference ShaderLoader::CreateShader(const ShaderDataLoader& dataLoader, const bool forceReload)
4408bf80f4bSopenharmony_ci{
4418bf80f4bSopenharmony_ci    const array_view<const ShaderDataLoader::ShaderVariant> shaderVariants = dataLoader.GetShaderVariants();
4428bf80f4bSopenharmony_ci    if (shaderVariants.empty()) {
4438bf80f4bSopenharmony_ci        return {};
4448bf80f4bSopenharmony_ci    }
4458bf80f4bSopenharmony_ci
4468bf80f4bSopenharmony_ci    const string_view compShader = shaderVariants[0].computeShader;
4478bf80f4bSopenharmony_ci    if (!compShader.empty()) {
4488bf80f4bSopenharmony_ci        return CreateComputeShader(dataLoader, forceReload);
4498bf80f4bSopenharmony_ci    } else {
4508bf80f4bSopenharmony_ci        const string_view vertShader = shaderVariants[0].vertexShader;
4518bf80f4bSopenharmony_ci        const string_view fragShader = shaderVariants[0].fragmentShader;
4528bf80f4bSopenharmony_ci        if (!vertShader.empty() && !fragShader.empty()) {
4538bf80f4bSopenharmony_ci            return CreateGraphicsShader(dataLoader, forceReload);
4548bf80f4bSopenharmony_ci        }
4558bf80f4bSopenharmony_ci    }
4568bf80f4bSopenharmony_ci    return {};
4578bf80f4bSopenharmony_ci}
4588bf80f4bSopenharmony_ci
4598bf80f4bSopenharmony_civoid ShaderLoader::LoadShaderStates(const string_view currentPath, const IDirectory& directory)
4608bf80f4bSopenharmony_ci{
4618bf80f4bSopenharmony_ci    for (auto const& entry : directory.GetEntries()) {
4628bf80f4bSopenharmony_ci        switch (entry.type) {
4638bf80f4bSopenharmony_ci            default:
4648bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::UNKNOWN:
4658bf80f4bSopenharmony_ci                break;
4668bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::FILE: {
4678bf80f4bSopenharmony_ci                HandleShaderStateFile(currentPath + entry.name, entry);
4688bf80f4bSopenharmony_ci                break;
4698bf80f4bSopenharmony_ci            }
4708bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::DIRECTORY: {
4718bf80f4bSopenharmony_ci                PLUGIN_LOG_I("recursive vertex input declarations directories not supported");
4728bf80f4bSopenharmony_ci                break;
4738bf80f4bSopenharmony_ci            }
4748bf80f4bSopenharmony_ci        }
4758bf80f4bSopenharmony_ci    }
4768bf80f4bSopenharmony_ci}
4778bf80f4bSopenharmony_ci
4788bf80f4bSopenharmony_civoid ShaderLoader::CreateShaderStates(const string_view uri,
4798bf80f4bSopenharmony_ci    const array_view<const ShaderStateLoaderVariantData>& variantData, const array_view<const GraphicsState>& states)
4808bf80f4bSopenharmony_ci{
4818bf80f4bSopenharmony_ci    for (size_t stateIdx = 0; stateIdx < states.size(); ++stateIdx) {
4828bf80f4bSopenharmony_ci        const ShaderManager::GraphicsStateCreateInfo createInfo { uri, states[stateIdx] };
4838bf80f4bSopenharmony_ci        const auto& variant = variantData[stateIdx];
4848bf80f4bSopenharmony_ci        const ShaderManager::GraphicsStateVariantCreateInfo variantCreateInfo { variant.renderSlot, variant.variantName,
4858bf80f4bSopenharmony_ci            variant.baseShaderState, variant.baseVariantName, variant.stateFlags };
4868bf80f4bSopenharmony_ci        const RenderHandleReference handle = shaderMgr_.CreateGraphicsState(createInfo, variantCreateInfo);
4878bf80f4bSopenharmony_ci        if (variant.renderSlotDefaultState && (!variant.renderSlot.empty())) {
4888bf80f4bSopenharmony_ci            const uint32_t renderSlotId = shaderMgr_.GetRenderSlotId(variant.renderSlot);
4898bf80f4bSopenharmony_ci            shaderMgr_.SetRenderSlotData(renderSlotId, {}, handle);
4908bf80f4bSopenharmony_ci        }
4918bf80f4bSopenharmony_ci        if (!handle) {
4928bf80f4bSopenharmony_ci            PLUGIN_LOG_E(
4938bf80f4bSopenharmony_ci                "error creating graphics state (name: %s, variant: %s)", uri.data(), variant.variantName.data());
4948bf80f4bSopenharmony_ci        }
4958bf80f4bSopenharmony_ci    }
4968bf80f4bSopenharmony_ci}
4978bf80f4bSopenharmony_ci
4988bf80f4bSopenharmony_civoid ShaderLoader::LoadVids(const string_view currentPath, const IDirectory& directory)
4998bf80f4bSopenharmony_ci{
5008bf80f4bSopenharmony_ci    for (auto const& entry : directory.GetEntries()) {
5018bf80f4bSopenharmony_ci        switch (entry.type) {
5028bf80f4bSopenharmony_ci            default:
5038bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::UNKNOWN:
5048bf80f4bSopenharmony_ci                break;
5058bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::FILE: {
5068bf80f4bSopenharmony_ci                HandleVertexInputDeclarationFile(currentPath + entry.name, entry);
5078bf80f4bSopenharmony_ci                break;
5088bf80f4bSopenharmony_ci            }
5098bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::DIRECTORY: {
5108bf80f4bSopenharmony_ci                PLUGIN_LOG_I("recursive vertex input declarations directories not supported");
5118bf80f4bSopenharmony_ci                break;
5128bf80f4bSopenharmony_ci            }
5138bf80f4bSopenharmony_ci        }
5148bf80f4bSopenharmony_ci    }
5158bf80f4bSopenharmony_ci}
5168bf80f4bSopenharmony_ci
5178bf80f4bSopenharmony_ciRenderHandleReference ShaderLoader::CreateVertexInputDeclaration(const VertexInputDeclarationLoader& loader)
5188bf80f4bSopenharmony_ci{
5198bf80f4bSopenharmony_ci    const string_view uri = loader.GetUri();
5208bf80f4bSopenharmony_ci    VertexInputDeclarationView dataView = loader.GetVertexInputDeclarationView();
5218bf80f4bSopenharmony_ci    return shaderMgr_.CreateVertexInputDeclaration({ uri, dataView });
5228bf80f4bSopenharmony_ci}
5238bf80f4bSopenharmony_ci
5248bf80f4bSopenharmony_civoid ShaderLoader::LoadPipelineLayouts(const string_view currentPath, const IDirectory& directory)
5258bf80f4bSopenharmony_ci{
5268bf80f4bSopenharmony_ci    for (auto const& entry : directory.GetEntries()) {
5278bf80f4bSopenharmony_ci        switch (entry.type) {
5288bf80f4bSopenharmony_ci            default:
5298bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::UNKNOWN:
5308bf80f4bSopenharmony_ci                break;
5318bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::FILE: {
5328bf80f4bSopenharmony_ci                HandlePipelineLayoutFile(currentPath + entry.name, entry);
5338bf80f4bSopenharmony_ci                break;
5348bf80f4bSopenharmony_ci            }
5358bf80f4bSopenharmony_ci            case IDirectory::Entry::Type::DIRECTORY: {
5368bf80f4bSopenharmony_ci                PLUGIN_LOG_I("recursive pipeline layout directories not supported");
5378bf80f4bSopenharmony_ci                break;
5388bf80f4bSopenharmony_ci            }
5398bf80f4bSopenharmony_ci        }
5408bf80f4bSopenharmony_ci    }
5418bf80f4bSopenharmony_ci}
5428bf80f4bSopenharmony_ci
5438bf80f4bSopenharmony_ciRenderHandleReference ShaderLoader::CreatePipelineLayout(const PipelineLayoutLoader& loader)
5448bf80f4bSopenharmony_ci{
5458bf80f4bSopenharmony_ci    const string_view uri = loader.GetUri();
5468bf80f4bSopenharmony_ci    const PipelineLayout& pipelineLayout = loader.GetPipelineLayout();
5478bf80f4bSopenharmony_ci    return shaderMgr_.CreatePipelineLayout({ uri, pipelineLayout });
5488bf80f4bSopenharmony_ci}
5498bf80f4bSopenharmony_ciRENDER_END_NAMESPACE()
550