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