• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Amber Authors.
2 //
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 #include "amber_script.h"
16 
17 #include "src/make_unique.h"
18 
19 namespace amber {
20 namespace android {
21 namespace {
22 
23 const char kAmberDir[] = "amber/";
24 const char kAmberScriptExtension[] = ".amber";
25 const char kShaderNameSignature[] = ".vk_shader_";
26 const char kShaderExtension[] = ".spv";
27 
IsEndedWith(const std::string & path,const std::string & end)28 bool IsEndedWith(const std::string& path, const std::string& end) {
29   const size_t path_size = path.size();
30   const size_t end_size = end.size();
31   if (path_size < end_size)
32     return false;
33 
34   return path.compare(path_size - end_size, end_size, end) == 0;
35 }
36 
IsStartedWith(const std::string & path,const std::string & start)37 bool IsStartedWith(const std::string& path, const std::string& start) {
38   const size_t path_size = path.size();
39   const size_t start_size = start.size();
40   if (path_size < start_size)
41     return false;
42 
43   return path.compare(0, start_size, start) == 0;
44 }
45 
GetShaderID(const std::string & shader_name)46 std::string GetShaderID(const std::string& shader_name) {
47   size_t spv_extension_pos = shader_name.find_last_of('.');
48   if (spv_extension_pos == std::string::npos)
49     return std::string();
50 
51   size_t shader_id_pos =
52       shader_name.find_last_of('.', spv_extension_pos - 1UL) + 1UL;
53   if (shader_id_pos == std::string::npos)
54     return std::string();
55 
56   if (shader_id_pos >= spv_extension_pos || shader_name.size() <= shader_id_pos)
57     return std::string();
58 
59   return shader_name.substr(shader_id_pos, spv_extension_pos - shader_id_pos);
60 }
61 
62 }  // namespace
63 
AmberScriptLoader(android_app * app)64 AmberScriptLoader::AmberScriptLoader(android_app* app) : app_context_(app) {}
65 
66 AmberScriptLoader::~AmberScriptLoader() = default;
67 
LoadAllScriptsFromAsset()68 Result AmberScriptLoader::LoadAllScriptsFromAsset() {
69   auto shader_names = FindAllScriptsAndReturnShaderNames();
70   if (script_info_.empty())
71     return Result("No Amber script found");
72 
73   for (auto& info : script_info_) {
74     info.script_content = ReadScript(info.asset_name);
75     if (info.script_content.empty())
76       return Result(info.asset_name + ":\n\tEmpty Amber script");
77   }
78 
79   for (auto& info : script_info_) {
80     for (const auto& shader : shader_names) {
81       if (!IsStartedWith(shader, info.asset_name + kShaderNameSignature))
82         continue;
83 
84       auto shader_content = ReadSpvShader(shader);
85       if (shader_content.empty())
86         return Result(shader + ":\n\tEmpty shader");
87 
88       auto id = GetShaderID(shader);
89       if (id.empty())
90         return Result(shader + ":\n\tFail to get shader ID");
91 
92       info.shader_map[id] = shader_content;
93     }
94   }
95 
96   return {};
97 }
98 
99 std::vector<std::string>
FindAllScriptsAndReturnShaderNames()100 AmberScriptLoader::FindAllScriptsAndReturnShaderNames() {
101   std::vector<std::string> shaders;
102 
103   AAssetDir* asset =
104       AAssetManager_openDir(app_context_->activity->assetManager, kAmberDir);
105   for (const char* file_name = AAssetDir_getNextFileName(asset); file_name;
106        file_name = AAssetDir_getNextFileName(asset)) {
107     std::string file_name_in_string(file_name);
108     if (IsEndedWith(file_name_in_string, kAmberScriptExtension)) {
109       script_info_.emplace_back();
110       script_info_.back().asset_name = file_name_in_string;
111     }
112 
113     if (IsEndedWith(file_name_in_string, kShaderExtension))
114       shaders.push_back(file_name_in_string);
115   }
116   AAssetDir_close(asset);
117 
118   return shaders;
119 }
120 
ReadContent(const std::string & asset_name)121 std::vector<uint8_t> AmberScriptLoader::ReadContent(
122     const std::string& asset_name) {
123   auto asset_path = kAmberDir + asset_name;
124   AAsset* asset = AAssetManager_open(app_context_->activity->assetManager,
125                                      asset_path.c_str(), AASSET_MODE_BUFFER);
126   if (!asset)
127     return std::vector<uint8_t>();
128 
129   size_t size_in_bytes = AAsset_getLength(asset);
130 
131   // Allocate a memory chunk whose size in bytes is |size_in_bytes|.
132   std::vector<uint8_t> content(size_in_bytes);
133 
134   AAsset_read(asset, content.data(), size_in_bytes);
135   AAsset_close(asset);
136 
137   return content;
138 }
139 
ReadScript(const std::string & script_name)140 std::string AmberScriptLoader::ReadScript(const std::string& script_name) {
141   auto content = ReadContent(script_name);
142   return std::string(reinterpret_cast<char*>(content.data()));
143 }
144 
ReadSpvShader(const std::string & shader_name)145 std::vector<uint32_t> AmberScriptLoader::ReadSpvShader(
146     const std::string& shader_name) {
147   auto content = ReadContent(shader_name);
148   if (content.size() % sizeof(uint32_t) != 0)
149     return std::vector<uint32_t>();
150 
151   return std::vector<uint32_t>(
152       reinterpret_cast<uint32_t*>(content.data()),
153       reinterpret_cast<uint32_t*>(content.data() + content.size()));
154 }
155 
156 }  // namespace android
157 }  // namespace amber
158