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