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