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