| // Copyright 2019 The Amber Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "amber_script.h" |
| |
| #include "src/make_unique.h" |
| |
| namespace amber { |
| namespace android { |
| namespace { |
| |
| const char kAmberDir[] = "amber/"; |
| const char kAmberScriptExtension[] = ".amber"; |
| const char kShaderNameSignature[] = ".vk_shader_"; |
| const char kShaderExtension[] = ".spv"; |
| |
| bool IsEndedWith(const std::string& path, const std::string& end) { |
| const size_t path_size = path.size(); |
| const size_t end_size = end.size(); |
| if (path_size < end_size) |
| return false; |
| |
| return path.compare(path_size - end_size, end_size, end) == 0; |
| } |
| |
| bool IsStartedWith(const std::string& path, const std::string& start) { |
| const size_t path_size = path.size(); |
| const size_t start_size = start.size(); |
| if (path_size < start_size) |
| return false; |
| |
| return path.compare(0, start_size, start) == 0; |
| } |
| |
| std::string GetShaderID(const std::string& shader_name) { |
| size_t spv_extension_pos = shader_name.find_last_of('.'); |
| if (spv_extension_pos == std::string::npos) |
| return std::string(); |
| |
| size_t shader_id_pos = |
| shader_name.find_last_of('.', spv_extension_pos - 1UL) + 1UL; |
| if (shader_id_pos == std::string::npos) |
| return std::string(); |
| |
| if (shader_id_pos >= spv_extension_pos || shader_name.size() <= shader_id_pos) |
| return std::string(); |
| |
| return shader_name.substr(shader_id_pos, spv_extension_pos - shader_id_pos); |
| } |
| |
| } // namespace |
| |
| AmberScriptLoader::AmberScriptLoader(android_app* app) : app_context_(app) {} |
| |
| AmberScriptLoader::~AmberScriptLoader() = default; |
| |
| Result AmberScriptLoader::LoadAllScriptsFromAsset() { |
| auto shader_names = FindAllScriptsAndReturnShaderNames(); |
| if (script_info_.empty()) |
| return Result("No Amber script found"); |
| |
| for (auto& info : script_info_) { |
| info.script_content = ReadScript(info.asset_name); |
| if (info.script_content.empty()) |
| return Result(info.asset_name + ":\n\tEmpty Amber script"); |
| } |
| |
| for (auto& info : script_info_) { |
| for (const auto& shader : shader_names) { |
| if (!IsStartedWith(shader, info.asset_name + kShaderNameSignature)) |
| continue; |
| |
| auto shader_content = ReadSpvShader(shader); |
| if (shader_content.empty()) |
| return Result(shader + ":\n\tEmpty shader"); |
| |
| auto id = GetShaderID(shader); |
| if (id.empty()) |
| return Result(shader + ":\n\tFail to get shader ID"); |
| |
| info.shader_map[id] = shader_content; |
| } |
| } |
| |
| return {}; |
| } |
| |
| std::vector<std::string> |
| AmberScriptLoader::FindAllScriptsAndReturnShaderNames() { |
| std::vector<std::string> shaders; |
| |
| AAssetDir* asset = |
| AAssetManager_openDir(app_context_->activity->assetManager, kAmberDir); |
| for (const char* file_name = AAssetDir_getNextFileName(asset); file_name; |
| file_name = AAssetDir_getNextFileName(asset)) { |
| std::string file_name_in_string(file_name); |
| if (IsEndedWith(file_name_in_string, kAmberScriptExtension)) { |
| script_info_.emplace_back(); |
| script_info_.back().asset_name = file_name_in_string; |
| } |
| |
| if (IsEndedWith(file_name_in_string, kShaderExtension)) |
| shaders.push_back(file_name_in_string); |
| } |
| AAssetDir_close(asset); |
| |
| return shaders; |
| } |
| |
| std::vector<uint8_t> AmberScriptLoader::ReadContent( |
| const std::string& asset_name) { |
| auto asset_path = kAmberDir + asset_name; |
| AAsset* asset = AAssetManager_open(app_context_->activity->assetManager, |
| asset_path.c_str(), AASSET_MODE_BUFFER); |
| if (!asset) |
| return std::vector<uint8_t>(); |
| |
| size_t size_in_bytes = AAsset_getLength(asset); |
| |
| // Allocate a memory chunk whose size in bytes is |size_in_bytes|. |
| std::vector<uint8_t> content(size_in_bytes); |
| |
| AAsset_read(asset, content.data(), size_in_bytes); |
| AAsset_close(asset); |
| |
| return content; |
| } |
| |
| std::string AmberScriptLoader::ReadScript(const std::string& script_name) { |
| auto content = ReadContent(script_name); |
| return std::string(reinterpret_cast<char*>(content.data())); |
| } |
| |
| std::vector<uint32_t> AmberScriptLoader::ReadSpvShader( |
| const std::string& shader_name) { |
| auto content = ReadContent(shader_name); |
| if (content.size() % sizeof(uint32_t) != 0) |
| return std::vector<uint32_t>(); |
| |
| return std::vector<uint32_t>( |
| reinterpret_cast<uint32_t*>(content.data()), |
| reinterpret_cast<uint32_t*>(content.data() + content.size())); |
| } |
| |
| } // namespace android |
| } // namespace amber |