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 "shader_data_loader.h"
17 
18 #include <charconv>
19 
20 #include <base/containers/string.h>
21 #include <base/util/uid_util.h>
22 #include <core/io/intf_file_manager.h>
23 #include <core/namespace.h>
24 
25 #include "json_util.h"
26 #include "shader_state_loader_util.h"
27 #include "util/log.h"
28 
29 using namespace BASE_NS;
30 using namespace CORE_NS;
31 
32 RENDER_BEGIN_NAMESPACE()
33 namespace {
34 constexpr size_t VERSION_SIZE { 5u };
35 constexpr uint32_t VERSION_MAJOR { 22u };
36 
LoadState(const json::value & jsonData,GraphicsState & graphicsState,GraphicsStateFlags & stateFlags,ShaderDataLoader::LoadResult & result)37 void LoadState(const json::value& jsonData, GraphicsState& graphicsState, GraphicsStateFlags& stateFlags,
38     ShaderDataLoader::LoadResult& result)
39 {
40     {
41         ShaderStateLoaderUtil::ShaderStateResult ssr;
42         ShaderStateLoaderUtil::ParseSingleState(jsonData, ssr);
43         ShaderStateLoaderUtil::ParseStateFlags(jsonData, stateFlags, ssr);
44         if (ssr.res.success && (ssr.states.states.size() == 1u)) {
45             graphicsState = move(ssr.states.states[0u]);
46         } else {
47             result.error += ssr.res.error;
48         }
49     }
50 }
51 
LoadSingleShaderVariant(const json::value & jsonData,ShaderDataLoader::ShaderVariant & data,ShaderDataLoader::LoadResult & result)52 void LoadSingleShaderVariant(
53     const json::value& jsonData, ShaderDataLoader::ShaderVariant& data, ShaderDataLoader::LoadResult& result)
54 {
55     SafeGetJsonValue(jsonData, "renderSlotDefaultShader", result.error, data.renderSlotDefaultShader);
56     SafeGetJsonValue(jsonData, "variantName", result.error, data.variantName);
57     SafeGetJsonValue(jsonData, "displayName", result.error, data.displayName);
58     SafeGetJsonValue(jsonData, "vert", result.error, data.vertexShader);
59     SafeGetJsonValue(jsonData, "frag", result.error, data.fragmentShader);
60     SafeGetJsonValue(jsonData, "compute", result.error, data.computeShader);
61     if (data.computeShader.empty()) {
62         SafeGetJsonValue(jsonData, "comp", result.error, data.computeShader);
63     }
64     {
65         SafeGetJsonValue(jsonData, "slot", result.error, data.renderSlot);
66         SafeGetJsonValue(jsonData, "renderSlot", result.error, data.renderSlot);
67     }
68     SafeGetJsonValue(jsonData, "vertexInputDeclaration", result.error, data.vertexInputDeclaration);
69     SafeGetJsonValue(jsonData, "pipelineLayout", result.error, data.pipelineLayout);
70 
71     if (result.success) {
72         data.shaderFileStr = json::to_string(jsonData);
73         if (const json::value* iter = jsonData.find("state"); iter) {
74             LoadState(*iter, data.graphicsState, data.stateFlags, result);
75         }
76         if (const json::value* iter = jsonData.find("materialMetadata"); iter) {
77             data.materialMetadata = json::to_string(*iter);
78         }
79     }
80 }
81 
LoadFunc(const json::value & jsonData,string & baseShader,string & baseCategory,vector<ShaderDataLoader::ShaderVariant> & shaderVariants)82 ShaderDataLoader::LoadResult LoadFunc(const json::value& jsonData, string& baseShader, string& baseCategory,
83     vector<ShaderDataLoader::ShaderVariant>& shaderVariants)
84 {
85     ShaderDataLoader::LoadResult result;
86     // compatibility check with early out
87     {
88         string ver;
89         string type;
90         uint32_t verMajor { ~0u };
91         uint32_t verMinor { ~0u };
92         if (const json::value* iter = jsonData.find("compatibility_info"); iter) {
93             SafeGetJsonValue(*iter, "type", result.error, type);
94             SafeGetJsonValue(*iter, "version", result.error, ver);
95             if (ver.size() == VERSION_SIZE) {
96                 if (const auto delim = ver.find('.'); delim != string::npos) {
97                     std::from_chars(ver.data(), ver.data() + delim, verMajor);
98                     std::from_chars(ver.data() + delim + 1, ver.data() + ver.size(), verMinor);
99                 }
100             }
101         }
102         if ((type != "shader") || (verMajor != VERSION_MAJOR)) {
103             result.error += "invalid shader type (" + type + ") and/or version (" + ver + ").";
104             result.success = false;
105             return result;
106         }
107     }
108 
109 #if (RENDER_VALIDATION_ENABLED == 1)
110     {
111         string name;
112         SafeGetJsonValue(jsonData, "name", result.error, name);
113         if (!name.empty()) {
114             PLUGIN_LOG_W("RENDER_VALIDATION: name (%s) not supported in shader json", name.c_str());
115         }
116     }
117 #endif
118     // base shader
119     SafeGetJsonValue(jsonData, "baseShader", result.error, baseShader);
120     // category
121     SafeGetJsonValue(jsonData, "category", result.error, baseCategory);
122 
123     // check all variants or use (older) single variant style
124     if (const json::value* iter = jsonData.find("shaders"); iter) {
125         if (iter->is_array()) {
126             for (const auto& variantRef : iter->array_) {
127                 ShaderDataLoader::ShaderVariant sv;
128                 LoadSingleShaderVariant(variantRef, sv, result);
129                 if (result.error.empty()) {
130                     shaderVariants.push_back(move(sv));
131                 }
132             }
133         }
134     } else {
135         ShaderDataLoader::ShaderVariant sv;
136         LoadSingleShaderVariant(jsonData, sv, result);
137         if (result.error.empty()) {
138             shaderVariants.push_back(move(sv));
139         }
140     }
141 
142     result.success = result.error.empty();
143     return result;
144 }
145 } // namespace
146 
GetUri() const147 string_view ShaderDataLoader::GetUri() const
148 {
149     return uri_;
150 }
151 
GetBaseShader() const152 string_view ShaderDataLoader::GetBaseShader() const
153 {
154     return baseShader_;
155 }
156 
GetBaseCategory() const157 BASE_NS::string_view ShaderDataLoader::GetBaseCategory() const
158 {
159     return baseCategory_;
160 }
161 
GetShaderVariants() const162 array_view<const ShaderDataLoader::ShaderVariant> ShaderDataLoader::GetShaderVariants() const
163 {
164     return shaderVariants_;
165 }
166 
Load(IFileManager & fileManager,const string_view uri)167 ShaderDataLoader::LoadResult ShaderDataLoader::Load(IFileManager& fileManager, const string_view uri)
168 {
169     uri_ = uri;
170     IFile::Ptr file = fileManager.OpenFile(uri);
171     if (!file) {
172         PLUGIN_LOG_D("Error loading '%s'", string(uri).c_str());
173         return LoadResult("Failed to open file.");
174     }
175 
176     const uint64_t byteLength = file->GetLength();
177 
178     string raw;
179     raw.resize(static_cast<size_t>(byteLength));
180 
181     if (file->Read(raw.data(), byteLength) != byteLength) {
182         PLUGIN_LOG_D("Error loading '%s'", string(uri).c_str());
183         return LoadResult("Failed to read file.");
184     }
185 
186     return Load(move(raw));
187 }
188 
Load(string && jsonData)189 ShaderDataLoader::LoadResult ShaderDataLoader::Load(string&& jsonData)
190 {
191     LoadResult result;
192     const auto json = json::parse(jsonData.data());
193     if (json) {
194         result = RENDER_NS::LoadFunc(json, baseShader_, baseCategory_, shaderVariants_);
195     } else {
196         result.success = false;
197         result.error = "Invalid json file.";
198     }
199 
200     return result;
201 }
202 RENDER_END_NAMESPACE()
203