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