1e5c31af7Sopenharmony_ci// Copyright 2018 The Amber Authors. 2e5c31af7Sopenharmony_ci// 3e5c31af7Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4e5c31af7Sopenharmony_ci// you may not use this file except in compliance with the License. 5e5c31af7Sopenharmony_ci// You may obtain a copy of the License at 6e5c31af7Sopenharmony_ci// 7e5c31af7Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8e5c31af7Sopenharmony_ci// 9e5c31af7Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10e5c31af7Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11e5c31af7Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12e5c31af7Sopenharmony_ci// See the License for the specific language governing permissions and 13e5c31af7Sopenharmony_ci// limitations under the License. 14e5c31af7Sopenharmony_ci 15e5c31af7Sopenharmony_ci#include "amber/amber.h" 16e5c31af7Sopenharmony_ci 17e5c31af7Sopenharmony_ci#include <stdio.h> 18e5c31af7Sopenharmony_ci 19e5c31af7Sopenharmony_ci#include <algorithm> 20e5c31af7Sopenharmony_ci#include <cassert> 21e5c31af7Sopenharmony_ci#include <cstdio> 22e5c31af7Sopenharmony_ci#include <cstdlib> 23e5c31af7Sopenharmony_ci#include <fstream> 24e5c31af7Sopenharmony_ci#include <iomanip> 25e5c31af7Sopenharmony_ci#include <iostream> 26e5c31af7Sopenharmony_ci#include <set> 27e5c31af7Sopenharmony_ci#include <string> 28e5c31af7Sopenharmony_ci#include <utility> 29e5c31af7Sopenharmony_ci#include <vector> 30e5c31af7Sopenharmony_ci 31e5c31af7Sopenharmony_ci#include "amber/recipe.h" 32e5c31af7Sopenharmony_ci#include "samples/config_helper.h" 33e5c31af7Sopenharmony_ci#include "samples/ppm.h" 34e5c31af7Sopenharmony_ci#include "samples/timestamp.h" 35e5c31af7Sopenharmony_ci#include "src/build-versions.h" 36e5c31af7Sopenharmony_ci#include "src/make_unique.h" 37e5c31af7Sopenharmony_ci 38e5c31af7Sopenharmony_ci#if AMBER_ENABLE_SPIRV_TOOLS 39e5c31af7Sopenharmony_ci#include "spirv-tools/libspirv.hpp" 40e5c31af7Sopenharmony_ci#endif 41e5c31af7Sopenharmony_ci 42e5c31af7Sopenharmony_ci#if AMBER_ENABLE_LODEPNG 43e5c31af7Sopenharmony_ci#include "samples/png.h" 44e5c31af7Sopenharmony_ci#endif // AMBER_ENABLE_LODEPNG 45e5c31af7Sopenharmony_ci 46e5c31af7Sopenharmony_cinamespace { 47e5c31af7Sopenharmony_ci 48e5c31af7Sopenharmony_ciconst char* kGeneratedColorBuffer = "framebuffer"; 49e5c31af7Sopenharmony_ci 50e5c31af7Sopenharmony_cistruct Options { 51e5c31af7Sopenharmony_ci std::vector<std::string> input_filenames; 52e5c31af7Sopenharmony_ci 53e5c31af7Sopenharmony_ci std::vector<std::string> image_filenames; 54e5c31af7Sopenharmony_ci std::string buffer_filename; 55e5c31af7Sopenharmony_ci std::vector<std::string> fb_names; 56e5c31af7Sopenharmony_ci std::vector<amber::BufferInfo> buffer_to_dump; 57e5c31af7Sopenharmony_ci uint32_t engine_major = 1; 58e5c31af7Sopenharmony_ci uint32_t engine_minor = 0; 59e5c31af7Sopenharmony_ci int32_t fence_timeout = -1; 60e5c31af7Sopenharmony_ci int32_t selected_device = -1; 61e5c31af7Sopenharmony_ci bool parse_only = false; 62e5c31af7Sopenharmony_ci bool pipeline_create_only = false; 63e5c31af7Sopenharmony_ci bool disable_validation_layer = false; 64e5c31af7Sopenharmony_ci bool quiet = false; 65e5c31af7Sopenharmony_ci bool show_help = false; 66e5c31af7Sopenharmony_ci bool show_version_info = false; 67e5c31af7Sopenharmony_ci bool log_graphics_calls = false; 68e5c31af7Sopenharmony_ci bool log_graphics_calls_time = false; 69e5c31af7Sopenharmony_ci bool log_execute_calls = false; 70e5c31af7Sopenharmony_ci bool disable_spirv_validation = false; 71e5c31af7Sopenharmony_ci std::string shader_filename; 72e5c31af7Sopenharmony_ci amber::EngineType engine = amber::kEngineTypeVulkan; 73e5c31af7Sopenharmony_ci std::string spv_env; 74e5c31af7Sopenharmony_ci}; 75e5c31af7Sopenharmony_ci 76e5c31af7Sopenharmony_ciconst char kUsage[] = R"(Usage: amber [options] SCRIPT [SCRIPTS...] 77e5c31af7Sopenharmony_ci 78e5c31af7Sopenharmony_ci options: 79e5c31af7Sopenharmony_ci -p -- Parse input files only; Don't execute. 80e5c31af7Sopenharmony_ci -ps -- Parse input files, create pipelines; Don't execute. 81e5c31af7Sopenharmony_ci -q -- Disable summary output. 82e5c31af7Sopenharmony_ci -d -- Disable validation layers. 83e5c31af7Sopenharmony_ci -D <ID> -- ID of device to run with (Vulkan only). 84e5c31af7Sopenharmony_ci -f <value> -- Sets the fence timeout value to |value| 85e5c31af7Sopenharmony_ci -t <spirv_env> -- The target SPIR-V environment e.g., spv1.3, vulkan1.1, vulkan1.2. 86e5c31af7Sopenharmony_ci If a SPIR-V environment, assume the lowest version of Vulkan that 87e5c31af7Sopenharmony_ci requires support of that version of SPIR-V. 88e5c31af7Sopenharmony_ci If a Vulkan environment, use the highest version of SPIR-V required 89e5c31af7Sopenharmony_ci to be supported by that version of Vulkan. 90e5c31af7Sopenharmony_ci Use vulkan1.1spv1.4 for SPIR-V 1.4 with Vulkan 1.1. 91e5c31af7Sopenharmony_ci Defaults to spv1.0. 92e5c31af7Sopenharmony_ci -i <filename> -- Write rendering to <filename> as a PNG image if it ends with '.png', 93e5c31af7Sopenharmony_ci or as a PPM image otherwise. 94e5c31af7Sopenharmony_ci -I <buffername> -- Name of framebuffer to dump. Defaults to 'framebuffer'. 95e5c31af7Sopenharmony_ci -b <filename> -- Write contents of a UBO or SSBO to <filename>. 96e5c31af7Sopenharmony_ci -B [<pipeline name>:][<desc set>:]<binding> -- Identifier of buffer to write. 97e5c31af7Sopenharmony_ci Default is [first pipeline:][0:]0. 98e5c31af7Sopenharmony_ci -w <filename> -- Write shader assembly to |filename| 99e5c31af7Sopenharmony_ci -e <engine> -- Specify graphics engine: vulkan, dawn. Default is vulkan. 100e5c31af7Sopenharmony_ci -v <engine version> -- Engine version (eg, 1.1 for Vulkan). Default 1.0. 101e5c31af7Sopenharmony_ci -V, --version -- Output version information for Amber and libraries. 102e5c31af7Sopenharmony_ci --log-graphics-calls -- Log graphics API calls (only for Vulkan so far). 103e5c31af7Sopenharmony_ci --log-graphics-calls-time -- Log timing of graphics API calls timing (Vulkan only). 104e5c31af7Sopenharmony_ci --log-execute-calls -- Log each execute call before run. 105e5c31af7Sopenharmony_ci --disable-spirv-val -- Disable SPIR-V validation. 106e5c31af7Sopenharmony_ci -h -- This help text. 107e5c31af7Sopenharmony_ci)"; 108e5c31af7Sopenharmony_ci 109e5c31af7Sopenharmony_ci// Parses a decimal integer from the given string, and writes it to |retval|. 110e5c31af7Sopenharmony_ci// Returns true if parsing succeeded and consumed the whole string. 111e5c31af7Sopenharmony_cistatic bool ParseOneInt(const char* str, int* retval) { 112e5c31af7Sopenharmony_ci char trailing = 0; 113e5c31af7Sopenharmony_ci#if defined(_MSC_VER) 114e5c31af7Sopenharmony_ci return sscanf_s(str, "%d%c", retval, &trailing, 1) == 1; 115e5c31af7Sopenharmony_ci#else 116e5c31af7Sopenharmony_ci return std::sscanf(str, "%d%c", retval, &trailing) == 1; 117e5c31af7Sopenharmony_ci#endif 118e5c31af7Sopenharmony_ci} 119e5c31af7Sopenharmony_ci 120e5c31af7Sopenharmony_ci// Parses a decimal integer, then a period (.), then a decimal integer from the 121e5c31af7Sopenharmony_ci// given string, and writes it to |retval|. Returns true if parsing succeeded 122e5c31af7Sopenharmony_ci// and consumed the whole string. 123e5c31af7Sopenharmony_cistatic int ParseIntDotInt(const char* str, int* retval0, int* retval1) { 124e5c31af7Sopenharmony_ci char trailing = 0; 125e5c31af7Sopenharmony_ci#if defined(_MSC_VER) 126e5c31af7Sopenharmony_ci return sscanf_s(str, "%d.%d%c", retval0, retval1, &trailing, 1) == 2; 127e5c31af7Sopenharmony_ci#else 128e5c31af7Sopenharmony_ci return std::sscanf(str, "%d.%d%c", retval0, retval1, &trailing) == 2; 129e5c31af7Sopenharmony_ci#endif 130e5c31af7Sopenharmony_ci} 131e5c31af7Sopenharmony_ci 132e5c31af7Sopenharmony_cibool ParseArgs(const std::vector<std::string>& args, Options* opts) { 133e5c31af7Sopenharmony_ci for (size_t i = 1; i < args.size(); ++i) { 134e5c31af7Sopenharmony_ci const std::string& arg = args[i]; 135e5c31af7Sopenharmony_ci if (arg == "-i") { 136e5c31af7Sopenharmony_ci ++i; 137e5c31af7Sopenharmony_ci if (i >= args.size()) { 138e5c31af7Sopenharmony_ci std::cerr << "Missing value for -i argument." << std::endl; 139e5c31af7Sopenharmony_ci return false; 140e5c31af7Sopenharmony_ci } 141e5c31af7Sopenharmony_ci opts->image_filenames.push_back(args[i]); 142e5c31af7Sopenharmony_ci 143e5c31af7Sopenharmony_ci } else if (arg == "-I") { 144e5c31af7Sopenharmony_ci ++i; 145e5c31af7Sopenharmony_ci if (i >= args.size()) { 146e5c31af7Sopenharmony_ci std::cerr << "Missing value for -I argument." << std::endl; 147e5c31af7Sopenharmony_ci return false; 148e5c31af7Sopenharmony_ci } 149e5c31af7Sopenharmony_ci opts->fb_names.push_back(args[i]); 150e5c31af7Sopenharmony_ci 151e5c31af7Sopenharmony_ci } else if (arg == "-b") { 152e5c31af7Sopenharmony_ci ++i; 153e5c31af7Sopenharmony_ci if (i >= args.size()) { 154e5c31af7Sopenharmony_ci std::cerr << "Missing value for -b argument." << std::endl; 155e5c31af7Sopenharmony_ci return false; 156e5c31af7Sopenharmony_ci } 157e5c31af7Sopenharmony_ci opts->buffer_filename = args[i]; 158e5c31af7Sopenharmony_ci 159e5c31af7Sopenharmony_ci } else if (arg == "-B") { 160e5c31af7Sopenharmony_ci ++i; 161e5c31af7Sopenharmony_ci if (i >= args.size()) { 162e5c31af7Sopenharmony_ci std::cerr << "Missing value for -B argument." << std::endl; 163e5c31af7Sopenharmony_ci return false; 164e5c31af7Sopenharmony_ci } 165e5c31af7Sopenharmony_ci opts->buffer_to_dump.emplace_back(); 166e5c31af7Sopenharmony_ci opts->buffer_to_dump.back().buffer_name = args[i]; 167e5c31af7Sopenharmony_ci } else if (arg == "-w") { 168e5c31af7Sopenharmony_ci ++i; 169e5c31af7Sopenharmony_ci if (i >= args.size()) { 170e5c31af7Sopenharmony_ci std::cerr << "Missing value for -w argument." << std::endl; 171e5c31af7Sopenharmony_ci return false; 172e5c31af7Sopenharmony_ci } 173e5c31af7Sopenharmony_ci opts->shader_filename = args[i]; 174e5c31af7Sopenharmony_ci } else if (arg == "-e") { 175e5c31af7Sopenharmony_ci ++i; 176e5c31af7Sopenharmony_ci if (i >= args.size()) { 177e5c31af7Sopenharmony_ci std::cerr << "Missing value for -e argument." << std::endl; 178e5c31af7Sopenharmony_ci return false; 179e5c31af7Sopenharmony_ci } 180e5c31af7Sopenharmony_ci const std::string& engine = args[i]; 181e5c31af7Sopenharmony_ci if (engine == "vulkan") { 182e5c31af7Sopenharmony_ci opts->engine = amber::kEngineTypeVulkan; 183e5c31af7Sopenharmony_ci } else if (engine == "dawn") { 184e5c31af7Sopenharmony_ci opts->engine = amber::kEngineTypeDawn; 185e5c31af7Sopenharmony_ci } else { 186e5c31af7Sopenharmony_ci std::cerr 187e5c31af7Sopenharmony_ci << "Invalid value for -e argument. Must be one of: vulkan dawn" 188e5c31af7Sopenharmony_ci << std::endl; 189e5c31af7Sopenharmony_ci return false; 190e5c31af7Sopenharmony_ci } 191e5c31af7Sopenharmony_ci } else if (arg == "-D") { 192e5c31af7Sopenharmony_ci ++i; 193e5c31af7Sopenharmony_ci if (i >= args.size()) { 194e5c31af7Sopenharmony_ci std::cerr << "Missing ID for -D argument." << std::endl; 195e5c31af7Sopenharmony_ci return false; 196e5c31af7Sopenharmony_ci } 197e5c31af7Sopenharmony_ci 198e5c31af7Sopenharmony_ci int32_t val = 0; 199e5c31af7Sopenharmony_ci if (!ParseOneInt(args[i].c_str(), &val)) { 200e5c31af7Sopenharmony_ci std::cerr << "Invalid device ID: " << args[i] << std::endl; 201e5c31af7Sopenharmony_ci return false; 202e5c31af7Sopenharmony_ci } 203e5c31af7Sopenharmony_ci if (val < 0) { 204e5c31af7Sopenharmony_ci std::cerr << "Device ID must be non-negative" << std::endl; 205e5c31af7Sopenharmony_ci return false; 206e5c31af7Sopenharmony_ci } 207e5c31af7Sopenharmony_ci opts->selected_device = val; 208e5c31af7Sopenharmony_ci 209e5c31af7Sopenharmony_ci } else if (arg == "-f") { 210e5c31af7Sopenharmony_ci ++i; 211e5c31af7Sopenharmony_ci if (i >= args.size()) { 212e5c31af7Sopenharmony_ci std::cerr << "Missing value for -f argument." << std::endl; 213e5c31af7Sopenharmony_ci return false; 214e5c31af7Sopenharmony_ci } 215e5c31af7Sopenharmony_ci 216e5c31af7Sopenharmony_ci int32_t val = 0; 217e5c31af7Sopenharmony_ci if (!ParseOneInt(args[i].c_str(), &val)) { 218e5c31af7Sopenharmony_ci std::cerr << "Invalid fence timeout: " << args[i] << std::endl; 219e5c31af7Sopenharmony_ci return false; 220e5c31af7Sopenharmony_ci } 221e5c31af7Sopenharmony_ci if (val < 0) { 222e5c31af7Sopenharmony_ci std::cerr << "Fence timeout must be non-negative" << std::endl; 223e5c31af7Sopenharmony_ci return false; 224e5c31af7Sopenharmony_ci } 225e5c31af7Sopenharmony_ci opts->fence_timeout = val; 226e5c31af7Sopenharmony_ci 227e5c31af7Sopenharmony_ci } else if (arg == "-t") { 228e5c31af7Sopenharmony_ci ++i; 229e5c31af7Sopenharmony_ci if (i >= args.size()) { 230e5c31af7Sopenharmony_ci std::cerr << "Missing value for -t argument." << std::endl; 231e5c31af7Sopenharmony_ci return false; 232e5c31af7Sopenharmony_ci } 233e5c31af7Sopenharmony_ci opts->spv_env = args[i]; 234e5c31af7Sopenharmony_ci } else if (arg == "-h" || arg == "--help") { 235e5c31af7Sopenharmony_ci opts->show_help = true; 236e5c31af7Sopenharmony_ci } else if (arg == "-v") { 237e5c31af7Sopenharmony_ci ++i; 238e5c31af7Sopenharmony_ci if (i >= args.size()) { 239e5c31af7Sopenharmony_ci std::cerr << "Missing value for -v argument." << std::endl; 240e5c31af7Sopenharmony_ci return false; 241e5c31af7Sopenharmony_ci } 242e5c31af7Sopenharmony_ci const std::string& ver = std::string(args[i]); 243e5c31af7Sopenharmony_ci 244e5c31af7Sopenharmony_ci int32_t major = 0; 245e5c31af7Sopenharmony_ci int32_t minor = 0; 246e5c31af7Sopenharmony_ci if (ParseIntDotInt(ver.c_str(), &major, &minor) || 247e5c31af7Sopenharmony_ci ParseOneInt(ver.c_str(), &major)) { 248e5c31af7Sopenharmony_ci if (major < 0) { 249e5c31af7Sopenharmony_ci std::cerr << "Version major must be non-negative" << std::endl; 250e5c31af7Sopenharmony_ci return false; 251e5c31af7Sopenharmony_ci } 252e5c31af7Sopenharmony_ci if (minor < 0) { 253e5c31af7Sopenharmony_ci std::cerr << "Version minor must be non-negative" << std::endl; 254e5c31af7Sopenharmony_ci return false; 255e5c31af7Sopenharmony_ci } 256e5c31af7Sopenharmony_ci opts->engine_major = static_cast<uint32_t>(major); 257e5c31af7Sopenharmony_ci opts->engine_minor = static_cast<uint32_t>(minor); 258e5c31af7Sopenharmony_ci } else { 259e5c31af7Sopenharmony_ci std::cerr << "Invalid engine version number: " << ver << std::endl; 260e5c31af7Sopenharmony_ci return false; 261e5c31af7Sopenharmony_ci } 262e5c31af7Sopenharmony_ci } else if (arg == "-V" || arg == "--version") { 263e5c31af7Sopenharmony_ci opts->show_version_info = true; 264e5c31af7Sopenharmony_ci } else if (arg == "-p") { 265e5c31af7Sopenharmony_ci opts->parse_only = true; 266e5c31af7Sopenharmony_ci } else if (arg == "-ps") { 267e5c31af7Sopenharmony_ci opts->pipeline_create_only = true; 268e5c31af7Sopenharmony_ci } else if (arg == "-d") { 269e5c31af7Sopenharmony_ci opts->disable_validation_layer = true; 270e5c31af7Sopenharmony_ci } else if (arg == "-s") { 271e5c31af7Sopenharmony_ci // -s is deprecated but still recognized, it inverts the quiet flag. 272e5c31af7Sopenharmony_ci opts->quiet = false; 273e5c31af7Sopenharmony_ci } else if (arg == "-q") { 274e5c31af7Sopenharmony_ci opts->quiet = true; 275e5c31af7Sopenharmony_ci } else if (arg == "--log-graphics-calls") { 276e5c31af7Sopenharmony_ci opts->log_graphics_calls = true; 277e5c31af7Sopenharmony_ci } else if (arg == "--log-graphics-calls-time") { 278e5c31af7Sopenharmony_ci opts->log_graphics_calls_time = true; 279e5c31af7Sopenharmony_ci } else if (arg == "--log-execute-calls") { 280e5c31af7Sopenharmony_ci opts->log_execute_calls = true; 281e5c31af7Sopenharmony_ci } else if (arg == "--disable-spirv-val") { 282e5c31af7Sopenharmony_ci opts->disable_spirv_validation = true; 283e5c31af7Sopenharmony_ci } else if (arg.size() > 0 && arg[0] == '-') { 284e5c31af7Sopenharmony_ci std::cerr << "Unrecognized option " << arg << std::endl; 285e5c31af7Sopenharmony_ci return false; 286e5c31af7Sopenharmony_ci } else if (!arg.empty()) { 287e5c31af7Sopenharmony_ci opts->input_filenames.push_back(arg); 288e5c31af7Sopenharmony_ci } 289e5c31af7Sopenharmony_ci } 290e5c31af7Sopenharmony_ci 291e5c31af7Sopenharmony_ci return true; 292e5c31af7Sopenharmony_ci} 293e5c31af7Sopenharmony_ci 294e5c31af7Sopenharmony_cistd::vector<char> ReadFile(const std::string& input_file) { 295e5c31af7Sopenharmony_ci FILE* file = nullptr; 296e5c31af7Sopenharmony_ci#if defined(_MSC_VER) 297e5c31af7Sopenharmony_ci fopen_s(&file, input_file.c_str(), "rb"); 298e5c31af7Sopenharmony_ci#else 299e5c31af7Sopenharmony_ci file = fopen(input_file.c_str(), "rb"); 300e5c31af7Sopenharmony_ci#endif 301e5c31af7Sopenharmony_ci if (!file) { 302e5c31af7Sopenharmony_ci std::cerr << "Failed to open " << input_file << std::endl; 303e5c31af7Sopenharmony_ci return {}; 304e5c31af7Sopenharmony_ci } 305e5c31af7Sopenharmony_ci 306e5c31af7Sopenharmony_ci fseek(file, 0, SEEK_END); 307e5c31af7Sopenharmony_ci uint64_t tell_file_size = static_cast<uint64_t>(ftell(file)); 308e5c31af7Sopenharmony_ci if (tell_file_size <= 0) { 309e5c31af7Sopenharmony_ci std::cerr << "Input file of incorrect size: " << input_file << std::endl; 310e5c31af7Sopenharmony_ci fclose(file); 311e5c31af7Sopenharmony_ci return {}; 312e5c31af7Sopenharmony_ci } 313e5c31af7Sopenharmony_ci fseek(file, 0, SEEK_SET); 314e5c31af7Sopenharmony_ci 315e5c31af7Sopenharmony_ci size_t file_size = static_cast<size_t>(tell_file_size); 316e5c31af7Sopenharmony_ci 317e5c31af7Sopenharmony_ci std::vector<char> data; 318e5c31af7Sopenharmony_ci data.resize(file_size); 319e5c31af7Sopenharmony_ci 320e5c31af7Sopenharmony_ci size_t bytes_read = fread(data.data(), sizeof(char), file_size, file); 321e5c31af7Sopenharmony_ci fclose(file); 322e5c31af7Sopenharmony_ci if (bytes_read != file_size) { 323e5c31af7Sopenharmony_ci std::cerr << "Failed to read " << input_file << std::endl; 324e5c31af7Sopenharmony_ci return {}; 325e5c31af7Sopenharmony_ci } 326e5c31af7Sopenharmony_ci 327e5c31af7Sopenharmony_ci return data; 328e5c31af7Sopenharmony_ci} 329e5c31af7Sopenharmony_ci 330e5c31af7Sopenharmony_ciclass SampleDelegate : public amber::Delegate { 331e5c31af7Sopenharmony_ci public: 332e5c31af7Sopenharmony_ci SampleDelegate() = default; 333e5c31af7Sopenharmony_ci ~SampleDelegate() override = default; 334e5c31af7Sopenharmony_ci 335e5c31af7Sopenharmony_ci void Log(const std::string& message) override { 336e5c31af7Sopenharmony_ci std::cout << message << std::endl; 337e5c31af7Sopenharmony_ci } 338e5c31af7Sopenharmony_ci 339e5c31af7Sopenharmony_ci bool LogGraphicsCalls() const override { return log_graphics_calls_; } 340e5c31af7Sopenharmony_ci void SetLogGraphicsCalls(bool log_graphics_calls) { 341e5c31af7Sopenharmony_ci log_graphics_calls_ = log_graphics_calls; 342e5c31af7Sopenharmony_ci } 343e5c31af7Sopenharmony_ci 344e5c31af7Sopenharmony_ci bool LogExecuteCalls() const override { return log_execute_calls_; } 345e5c31af7Sopenharmony_ci void SetLogExecuteCalls(bool log_execute_calls) { 346e5c31af7Sopenharmony_ci log_execute_calls_ = log_execute_calls; 347e5c31af7Sopenharmony_ci } 348e5c31af7Sopenharmony_ci 349e5c31af7Sopenharmony_ci bool LogGraphicsCallsTime() const override { 350e5c31af7Sopenharmony_ci return log_graphics_calls_time_; 351e5c31af7Sopenharmony_ci } 352e5c31af7Sopenharmony_ci void SetLogGraphicsCallsTime(bool log_graphics_calls_time) { 353e5c31af7Sopenharmony_ci log_graphics_calls_time_ = log_graphics_calls_time; 354e5c31af7Sopenharmony_ci if (log_graphics_calls_time) { 355e5c31af7Sopenharmony_ci // Make sure regular logging is also enabled 356e5c31af7Sopenharmony_ci log_graphics_calls_ = true; 357e5c31af7Sopenharmony_ci } 358e5c31af7Sopenharmony_ci } 359e5c31af7Sopenharmony_ci 360e5c31af7Sopenharmony_ci uint64_t GetTimestampNs() const override { 361e5c31af7Sopenharmony_ci return timestamp::SampleGetTimestampNs(); 362e5c31af7Sopenharmony_ci } 363e5c31af7Sopenharmony_ci 364e5c31af7Sopenharmony_ci void SetScriptPath(std::string path) { path_ = path; } 365e5c31af7Sopenharmony_ci 366e5c31af7Sopenharmony_ci amber::Result LoadBufferData(const std::string file_name, 367e5c31af7Sopenharmony_ci amber::BufferDataFileType file_type, 368e5c31af7Sopenharmony_ci amber::BufferInfo* buffer) const override { 369e5c31af7Sopenharmony_ci if (file_type == amber::BufferDataFileType::kPng) { 370e5c31af7Sopenharmony_ci#if AMBER_ENABLE_LODEPNG 371e5c31af7Sopenharmony_ci return png::LoadPNG(path_ + file_name, &buffer->width, &buffer->height, 372e5c31af7Sopenharmony_ci &buffer->values); 373e5c31af7Sopenharmony_ci#else 374e5c31af7Sopenharmony_ci return amber::Result("PNG support is not enabled in compile options."); 375e5c31af7Sopenharmony_ci#endif // AMBER_ENABLE_LODEPNG 376e5c31af7Sopenharmony_ci } else { 377e5c31af7Sopenharmony_ci auto data = ReadFile(path_ + file_name); 378e5c31af7Sopenharmony_ci if (data.empty()) 379e5c31af7Sopenharmony_ci return amber::Result("Failed to load buffer data " + file_name); 380e5c31af7Sopenharmony_ci 381e5c31af7Sopenharmony_ci for (auto d : data) { 382e5c31af7Sopenharmony_ci amber::Value v; 383e5c31af7Sopenharmony_ci v.SetIntValue(static_cast<uint64_t>(d)); 384e5c31af7Sopenharmony_ci buffer->values.push_back(v); 385e5c31af7Sopenharmony_ci } 386e5c31af7Sopenharmony_ci 387e5c31af7Sopenharmony_ci buffer->width = 1; 388e5c31af7Sopenharmony_ci buffer->height = 1; 389e5c31af7Sopenharmony_ci } 390e5c31af7Sopenharmony_ci 391e5c31af7Sopenharmony_ci return {}; 392e5c31af7Sopenharmony_ci } 393e5c31af7Sopenharmony_ci 394e5c31af7Sopenharmony_ci private: 395e5c31af7Sopenharmony_ci bool log_graphics_calls_ = false; 396e5c31af7Sopenharmony_ci bool log_graphics_calls_time_ = false; 397e5c31af7Sopenharmony_ci bool log_execute_calls_ = false; 398e5c31af7Sopenharmony_ci std::string path_ = ""; 399e5c31af7Sopenharmony_ci}; 400e5c31af7Sopenharmony_ci 401e5c31af7Sopenharmony_cistd::string disassemble(const std::string& env, 402e5c31af7Sopenharmony_ci const std::vector<uint32_t>& data) { 403e5c31af7Sopenharmony_ci#if AMBER_ENABLE_SPIRV_TOOLS 404e5c31af7Sopenharmony_ci std::string spv_errors; 405e5c31af7Sopenharmony_ci 406e5c31af7Sopenharmony_ci spv_target_env target_env = SPV_ENV_UNIVERSAL_1_0; 407e5c31af7Sopenharmony_ci if (!env.empty()) { 408e5c31af7Sopenharmony_ci if (!spvParseTargetEnv(env.c_str(), &target_env)) 409e5c31af7Sopenharmony_ci return ""; 410e5c31af7Sopenharmony_ci } 411e5c31af7Sopenharmony_ci 412e5c31af7Sopenharmony_ci auto msg_consumer = [&spv_errors](spv_message_level_t level, const char*, 413e5c31af7Sopenharmony_ci const spv_position_t& position, 414e5c31af7Sopenharmony_ci const char* message) { 415e5c31af7Sopenharmony_ci switch (level) { 416e5c31af7Sopenharmony_ci case SPV_MSG_FATAL: 417e5c31af7Sopenharmony_ci case SPV_MSG_INTERNAL_ERROR: 418e5c31af7Sopenharmony_ci case SPV_MSG_ERROR: 419e5c31af7Sopenharmony_ci spv_errors += "error: line " + std::to_string(position.index) + ": " + 420e5c31af7Sopenharmony_ci message + "\n"; 421e5c31af7Sopenharmony_ci break; 422e5c31af7Sopenharmony_ci case SPV_MSG_WARNING: 423e5c31af7Sopenharmony_ci spv_errors += "warning: line " + std::to_string(position.index) + ": " + 424e5c31af7Sopenharmony_ci message + "\n"; 425e5c31af7Sopenharmony_ci break; 426e5c31af7Sopenharmony_ci case SPV_MSG_INFO: 427e5c31af7Sopenharmony_ci spv_errors += "info: line " + std::to_string(position.index) + ": " + 428e5c31af7Sopenharmony_ci message + "\n"; 429e5c31af7Sopenharmony_ci break; 430e5c31af7Sopenharmony_ci case SPV_MSG_DEBUG: 431e5c31af7Sopenharmony_ci break; 432e5c31af7Sopenharmony_ci } 433e5c31af7Sopenharmony_ci }; 434e5c31af7Sopenharmony_ci 435e5c31af7Sopenharmony_ci spvtools::SpirvTools tools(target_env); 436e5c31af7Sopenharmony_ci tools.SetMessageConsumer(msg_consumer); 437e5c31af7Sopenharmony_ci 438e5c31af7Sopenharmony_ci std::string result; 439e5c31af7Sopenharmony_ci tools.Disassemble(data, &result, 440e5c31af7Sopenharmony_ci SPV_BINARY_TO_TEXT_OPTION_INDENT | 441e5c31af7Sopenharmony_ci SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 442e5c31af7Sopenharmony_ci return result; 443e5c31af7Sopenharmony_ci#else 444e5c31af7Sopenharmony_ci return ""; 445e5c31af7Sopenharmony_ci#endif // AMBER_ENABLE_SPIRV_TOOLS 446e5c31af7Sopenharmony_ci} 447e5c31af7Sopenharmony_ci 448e5c31af7Sopenharmony_ci} // namespace 449e5c31af7Sopenharmony_ci 450e5c31af7Sopenharmony_ci#ifdef AMBER_ANDROID_MAIN 451e5c31af7Sopenharmony_ci#pragma clang diagnostic push 452e5c31af7Sopenharmony_ci#pragma clang diagnostic ignored "-Wmissing-prototypes" 453e5c31af7Sopenharmony_ci#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection" 454e5c31af7Sopenharmony_ciint android_main(int argc, const char** argv) { 455e5c31af7Sopenharmony_ci#pragma clang diagnostic pop 456e5c31af7Sopenharmony_ci#else 457e5c31af7Sopenharmony_ciint main(int argc, const char** argv) { 458e5c31af7Sopenharmony_ci#endif 459e5c31af7Sopenharmony_ci std::vector<std::string> args(argv, argv + argc); 460e5c31af7Sopenharmony_ci Options options; 461e5c31af7Sopenharmony_ci SampleDelegate delegate; 462e5c31af7Sopenharmony_ci 463e5c31af7Sopenharmony_ci if (!ParseArgs(args, &options)) { 464e5c31af7Sopenharmony_ci std::cerr << "Failed to parse arguments." << std::endl; 465e5c31af7Sopenharmony_ci return 1; 466e5c31af7Sopenharmony_ci } 467e5c31af7Sopenharmony_ci 468e5c31af7Sopenharmony_ci if (options.show_version_info) { 469e5c31af7Sopenharmony_ci std::cout << "Amber : " << AMBER_VERSION << std::endl; 470e5c31af7Sopenharmony_ci#if AMBER_ENABLE_SPIRV_TOOLS 471e5c31af7Sopenharmony_ci std::cout << "SPIRV-Tools : " << SPIRV_TOOLS_VERSION << std::endl; 472e5c31af7Sopenharmony_ci std::cout << "SPIRV-Headers: " << SPIRV_HEADERS_VERSION << std::endl; 473e5c31af7Sopenharmony_ci#endif // AMBER_ENABLE_SPIRV_TOOLS 474e5c31af7Sopenharmony_ci#if AMBER_ENABLE_SHADERC 475e5c31af7Sopenharmony_ci std::cout << "GLSLang : " << GLSLANG_VERSION << std::endl; 476e5c31af7Sopenharmony_ci std::cout << "Shaderc : " << SHADERC_VERSION << std::endl; 477e5c31af7Sopenharmony_ci#endif // AMBER_ENABLE_SHADERC 478e5c31af7Sopenharmony_ci } 479e5c31af7Sopenharmony_ci 480e5c31af7Sopenharmony_ci if (options.show_help) { 481e5c31af7Sopenharmony_ci std::cout << kUsage << std::endl; 482e5c31af7Sopenharmony_ci return 0; 483e5c31af7Sopenharmony_ci } 484e5c31af7Sopenharmony_ci 485e5c31af7Sopenharmony_ci amber::Result result; 486e5c31af7Sopenharmony_ci std::vector<std::string> failures; 487e5c31af7Sopenharmony_ci struct RecipeData { 488e5c31af7Sopenharmony_ci std::string file; 489e5c31af7Sopenharmony_ci std::unique_ptr<amber::Recipe> recipe; 490e5c31af7Sopenharmony_ci }; 491e5c31af7Sopenharmony_ci std::vector<RecipeData> recipe_data; 492e5c31af7Sopenharmony_ci for (const auto& file : options.input_filenames) { 493e5c31af7Sopenharmony_ci auto char_data = ReadFile(file); 494e5c31af7Sopenharmony_ci auto data = std::string(char_data.begin(), char_data.end()); 495e5c31af7Sopenharmony_ci if (data.empty()) { 496e5c31af7Sopenharmony_ci std::cerr << file << " is empty." << std::endl; 497e5c31af7Sopenharmony_ci failures.push_back(file); 498e5c31af7Sopenharmony_ci continue; 499e5c31af7Sopenharmony_ci } 500e5c31af7Sopenharmony_ci 501e5c31af7Sopenharmony_ci // Parse file path and set it for delegate to use when loading buffer data. 502e5c31af7Sopenharmony_ci delegate.SetScriptPath(file.substr(0, file.find_last_of("/\\") + 1)); 503e5c31af7Sopenharmony_ci 504e5c31af7Sopenharmony_ci amber::Amber am(&delegate); 505e5c31af7Sopenharmony_ci std::unique_ptr<amber::Recipe> recipe = amber::MakeUnique<amber::Recipe>(); 506e5c31af7Sopenharmony_ci 507e5c31af7Sopenharmony_ci result = am.Parse(data, recipe.get()); 508e5c31af7Sopenharmony_ci if (!result.IsSuccess()) { 509e5c31af7Sopenharmony_ci std::cerr << file << ": " << result.Error() << std::endl; 510e5c31af7Sopenharmony_ci failures.push_back(file); 511e5c31af7Sopenharmony_ci continue; 512e5c31af7Sopenharmony_ci } 513e5c31af7Sopenharmony_ci 514e5c31af7Sopenharmony_ci if (options.fence_timeout > -1) 515e5c31af7Sopenharmony_ci recipe->SetFenceTimeout(static_cast<uint32_t>(options.fence_timeout)); 516e5c31af7Sopenharmony_ci 517e5c31af7Sopenharmony_ci recipe_data.emplace_back(); 518e5c31af7Sopenharmony_ci recipe_data.back().file = file; 519e5c31af7Sopenharmony_ci recipe_data.back().recipe = std::move(recipe); 520e5c31af7Sopenharmony_ci } 521e5c31af7Sopenharmony_ci 522e5c31af7Sopenharmony_ci if (options.parse_only) 523e5c31af7Sopenharmony_ci return 0; 524e5c31af7Sopenharmony_ci 525e5c31af7Sopenharmony_ci if (options.log_graphics_calls) 526e5c31af7Sopenharmony_ci delegate.SetLogGraphicsCalls(true); 527e5c31af7Sopenharmony_ci if (options.log_graphics_calls_time) 528e5c31af7Sopenharmony_ci delegate.SetLogGraphicsCallsTime(true); 529e5c31af7Sopenharmony_ci if (options.log_execute_calls) 530e5c31af7Sopenharmony_ci delegate.SetLogExecuteCalls(true); 531e5c31af7Sopenharmony_ci 532e5c31af7Sopenharmony_ci amber::Options amber_options; 533e5c31af7Sopenharmony_ci amber_options.engine = options.engine; 534e5c31af7Sopenharmony_ci amber_options.spv_env = options.spv_env; 535e5c31af7Sopenharmony_ci amber_options.execution_type = options.pipeline_create_only 536e5c31af7Sopenharmony_ci ? amber::ExecutionType::kPipelineCreateOnly 537e5c31af7Sopenharmony_ci : amber::ExecutionType::kExecute; 538e5c31af7Sopenharmony_ci amber_options.disable_spirv_validation = options.disable_spirv_validation; 539e5c31af7Sopenharmony_ci 540e5c31af7Sopenharmony_ci std::set<std::string> required_features; 541e5c31af7Sopenharmony_ci std::set<std::string> required_device_extensions; 542e5c31af7Sopenharmony_ci std::set<std::string> required_instance_extensions; 543e5c31af7Sopenharmony_ci for (const auto& recipe_data_elem : recipe_data) { 544e5c31af7Sopenharmony_ci const auto features = recipe_data_elem.recipe->GetRequiredFeatures(); 545e5c31af7Sopenharmony_ci required_features.insert(features.begin(), features.end()); 546e5c31af7Sopenharmony_ci 547e5c31af7Sopenharmony_ci const auto device_extensions = 548e5c31af7Sopenharmony_ci recipe_data_elem.recipe->GetRequiredDeviceExtensions(); 549e5c31af7Sopenharmony_ci required_device_extensions.insert(device_extensions.begin(), 550e5c31af7Sopenharmony_ci device_extensions.end()); 551e5c31af7Sopenharmony_ci 552e5c31af7Sopenharmony_ci const auto inst_extensions = 553e5c31af7Sopenharmony_ci recipe_data_elem.recipe->GetRequiredInstanceExtensions(); 554e5c31af7Sopenharmony_ci required_instance_extensions.insert(inst_extensions.begin(), 555e5c31af7Sopenharmony_ci inst_extensions.end()); 556e5c31af7Sopenharmony_ci } 557e5c31af7Sopenharmony_ci 558e5c31af7Sopenharmony_ci sample::ConfigHelper config_helper; 559e5c31af7Sopenharmony_ci std::unique_ptr<amber::EngineConfig> config; 560e5c31af7Sopenharmony_ci 561e5c31af7Sopenharmony_ci amber::Result r = config_helper.CreateConfig( 562e5c31af7Sopenharmony_ci amber_options.engine, options.engine_major, options.engine_minor, 563e5c31af7Sopenharmony_ci options.selected_device, 564e5c31af7Sopenharmony_ci std::vector<std::string>(required_features.begin(), 565e5c31af7Sopenharmony_ci required_features.end()), 566e5c31af7Sopenharmony_ci std::vector<std::string>(required_instance_extensions.begin(), 567e5c31af7Sopenharmony_ci required_instance_extensions.end()), 568e5c31af7Sopenharmony_ci std::vector<std::string>(required_device_extensions.begin(), 569e5c31af7Sopenharmony_ci required_device_extensions.end()), 570e5c31af7Sopenharmony_ci options.disable_validation_layer, options.show_version_info, &config); 571e5c31af7Sopenharmony_ci 572e5c31af7Sopenharmony_ci if (!r.IsSuccess()) { 573e5c31af7Sopenharmony_ci std::cout << r.Error() << std::endl; 574e5c31af7Sopenharmony_ci return 1; 575e5c31af7Sopenharmony_ci } 576e5c31af7Sopenharmony_ci 577e5c31af7Sopenharmony_ci amber_options.config = config.get(); 578e5c31af7Sopenharmony_ci 579e5c31af7Sopenharmony_ci if (!options.buffer_filename.empty()) { 580e5c31af7Sopenharmony_ci // Have a filename to dump, but no explicit buffer, set the default of 0:0. 581e5c31af7Sopenharmony_ci if (options.buffer_to_dump.empty()) { 582e5c31af7Sopenharmony_ci options.buffer_to_dump.emplace_back(); 583e5c31af7Sopenharmony_ci options.buffer_to_dump.back().buffer_name = "0:0"; 584e5c31af7Sopenharmony_ci } 585e5c31af7Sopenharmony_ci 586e5c31af7Sopenharmony_ci amber_options.extractions.insert(amber_options.extractions.end(), 587e5c31af7Sopenharmony_ci options.buffer_to_dump.begin(), 588e5c31af7Sopenharmony_ci options.buffer_to_dump.end()); 589e5c31af7Sopenharmony_ci } 590e5c31af7Sopenharmony_ci 591e5c31af7Sopenharmony_ci if (options.image_filenames.size() - options.fb_names.size() > 1) { 592e5c31af7Sopenharmony_ci std::cerr << "Need to specify framebuffer names using -I for each output " 593e5c31af7Sopenharmony_ci "image specified by -i." 594e5c31af7Sopenharmony_ci << std::endl; 595e5c31af7Sopenharmony_ci return 1; 596e5c31af7Sopenharmony_ci } 597e5c31af7Sopenharmony_ci 598e5c31af7Sopenharmony_ci // Use default frame buffer name when not specified. 599e5c31af7Sopenharmony_ci while (options.image_filenames.size() > options.fb_names.size()) 600e5c31af7Sopenharmony_ci options.fb_names.push_back(kGeneratedColorBuffer); 601e5c31af7Sopenharmony_ci 602e5c31af7Sopenharmony_ci for (const auto& fb_name : options.fb_names) { 603e5c31af7Sopenharmony_ci amber::BufferInfo buffer_info; 604e5c31af7Sopenharmony_ci buffer_info.buffer_name = fb_name; 605e5c31af7Sopenharmony_ci buffer_info.is_image_buffer = true; 606e5c31af7Sopenharmony_ci amber_options.extractions.push_back(buffer_info); 607e5c31af7Sopenharmony_ci } 608e5c31af7Sopenharmony_ci 609e5c31af7Sopenharmony_ci for (const auto& recipe_data_elem : recipe_data) { 610e5c31af7Sopenharmony_ci const auto* recipe = recipe_data_elem.recipe.get(); 611e5c31af7Sopenharmony_ci const auto& file = recipe_data_elem.file; 612e5c31af7Sopenharmony_ci 613e5c31af7Sopenharmony_ci amber::Amber am(&delegate); 614e5c31af7Sopenharmony_ci result = am.Execute(recipe, &amber_options); 615e5c31af7Sopenharmony_ci if (!result.IsSuccess()) { 616e5c31af7Sopenharmony_ci std::cerr << file << ": " << result.Error() << std::endl; 617e5c31af7Sopenharmony_ci failures.push_back(file); 618e5c31af7Sopenharmony_ci // Note, we continue after failure to allow dumping the buffers which may 619e5c31af7Sopenharmony_ci // give clues as to the failure. 620e5c31af7Sopenharmony_ci } 621e5c31af7Sopenharmony_ci 622e5c31af7Sopenharmony_ci // Dump the shader assembly 623e5c31af7Sopenharmony_ci if (!options.shader_filename.empty()) { 624e5c31af7Sopenharmony_ci#if AMBER_ENABLE_SPIRV_TOOLS 625e5c31af7Sopenharmony_ci std::ofstream shader_file; 626e5c31af7Sopenharmony_ci shader_file.open(options.shader_filename, std::ios::out); 627e5c31af7Sopenharmony_ci if (!shader_file.is_open()) { 628e5c31af7Sopenharmony_ci std::cerr << "Cannot open file for shader dump: "; 629e5c31af7Sopenharmony_ci std::cerr << options.shader_filename << std::endl; 630e5c31af7Sopenharmony_ci } else { 631e5c31af7Sopenharmony_ci auto info = recipe->GetShaderInfo(); 632e5c31af7Sopenharmony_ci for (const auto& sh : info) { 633e5c31af7Sopenharmony_ci shader_file << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" 634e5c31af7Sopenharmony_ci << std::endl; 635e5c31af7Sopenharmony_ci shader_file << "; " << sh.shader_name << std::endl 636e5c31af7Sopenharmony_ci << ";" << std::endl; 637e5c31af7Sopenharmony_ci shader_file << disassemble(options.spv_env, sh.shader_data) 638e5c31af7Sopenharmony_ci << std::endl; 639e5c31af7Sopenharmony_ci } 640e5c31af7Sopenharmony_ci shader_file.close(); 641e5c31af7Sopenharmony_ci } 642e5c31af7Sopenharmony_ci#endif // AMBER_ENABLE_SPIRV_TOOLS 643e5c31af7Sopenharmony_ci } 644e5c31af7Sopenharmony_ci 645e5c31af7Sopenharmony_ci for (size_t i = 0; i < options.image_filenames.size(); ++i) { 646e5c31af7Sopenharmony_ci std::vector<uint8_t> out_buf; 647e5c31af7Sopenharmony_ci auto image_filename = options.image_filenames[i]; 648e5c31af7Sopenharmony_ci auto pos = image_filename.find_last_of('.'); 649e5c31af7Sopenharmony_ci bool usePNG = 650e5c31af7Sopenharmony_ci pos != std::string::npos && image_filename.substr(pos + 1) == "png"; 651e5c31af7Sopenharmony_ci for (const amber::BufferInfo& buffer_info : amber_options.extractions) { 652e5c31af7Sopenharmony_ci if (buffer_info.buffer_name == options.fb_names[i]) { 653e5c31af7Sopenharmony_ci if (buffer_info.values.size() != 654e5c31af7Sopenharmony_ci (buffer_info.width * buffer_info.height)) { 655e5c31af7Sopenharmony_ci result = amber::Result( 656e5c31af7Sopenharmony_ci "Framebuffer (" + buffer_info.buffer_name + ") size (" + 657e5c31af7Sopenharmony_ci std::to_string(buffer_info.values.size()) + 658e5c31af7Sopenharmony_ci ") != " + "width * height (" + 659e5c31af7Sopenharmony_ci std::to_string(buffer_info.width * buffer_info.height) + ")"); 660e5c31af7Sopenharmony_ci break; 661e5c31af7Sopenharmony_ci } 662e5c31af7Sopenharmony_ci 663e5c31af7Sopenharmony_ci if (buffer_info.values.empty()) { 664e5c31af7Sopenharmony_ci result = amber::Result("Framebuffer (" + buffer_info.buffer_name + 665e5c31af7Sopenharmony_ci ") empty or non-existent."); 666e5c31af7Sopenharmony_ci break; 667e5c31af7Sopenharmony_ci } 668e5c31af7Sopenharmony_ci 669e5c31af7Sopenharmony_ci if (usePNG) { 670e5c31af7Sopenharmony_ci#if AMBER_ENABLE_LODEPNG 671e5c31af7Sopenharmony_ci result = png::ConvertToPNG(buffer_info.width, buffer_info.height, 672e5c31af7Sopenharmony_ci buffer_info.values, &out_buf); 673e5c31af7Sopenharmony_ci#else // AMBER_ENABLE_LODEPNG 674e5c31af7Sopenharmony_ci result = amber::Result("PNG support not enabled"); 675e5c31af7Sopenharmony_ci#endif // AMBER_ENABLE_LODEPNG 676e5c31af7Sopenharmony_ci } else { 677e5c31af7Sopenharmony_ci ppm::ConvertToPPM(buffer_info.width, buffer_info.height, 678e5c31af7Sopenharmony_ci buffer_info.values, &out_buf); 679e5c31af7Sopenharmony_ci result = {}; 680e5c31af7Sopenharmony_ci } 681e5c31af7Sopenharmony_ci break; 682e5c31af7Sopenharmony_ci } 683e5c31af7Sopenharmony_ci } 684e5c31af7Sopenharmony_ci if (result.IsSuccess()) { 685e5c31af7Sopenharmony_ci std::ofstream image_file; 686e5c31af7Sopenharmony_ci image_file.open(image_filename, std::ios::out | std::ios::binary); 687e5c31af7Sopenharmony_ci if (!image_file.is_open()) { 688e5c31af7Sopenharmony_ci std::cerr << "Cannot open file for image dump: "; 689e5c31af7Sopenharmony_ci std::cerr << image_filename << std::endl; 690e5c31af7Sopenharmony_ci continue; 691e5c31af7Sopenharmony_ci } 692e5c31af7Sopenharmony_ci image_file << std::string(out_buf.begin(), out_buf.end()); 693e5c31af7Sopenharmony_ci image_file.close(); 694e5c31af7Sopenharmony_ci } else { 695e5c31af7Sopenharmony_ci std::cerr << result.Error() << std::endl; 696e5c31af7Sopenharmony_ci } 697e5c31af7Sopenharmony_ci } 698e5c31af7Sopenharmony_ci 699e5c31af7Sopenharmony_ci if (!options.buffer_filename.empty()) { 700e5c31af7Sopenharmony_ci std::ofstream buffer_file; 701e5c31af7Sopenharmony_ci buffer_file.open(options.buffer_filename, std::ios::out); 702e5c31af7Sopenharmony_ci if (!buffer_file.is_open()) { 703e5c31af7Sopenharmony_ci std::cerr << "Cannot open file for buffer dump: "; 704e5c31af7Sopenharmony_ci std::cerr << options.buffer_filename << std::endl; 705e5c31af7Sopenharmony_ci } else { 706e5c31af7Sopenharmony_ci for (const amber::BufferInfo& buffer_info : amber_options.extractions) { 707e5c31af7Sopenharmony_ci // Skip frame buffers. 708e5c31af7Sopenharmony_ci if (std::any_of(options.fb_names.begin(), options.fb_names.end(), 709e5c31af7Sopenharmony_ci [&](std::string s) { 710e5c31af7Sopenharmony_ci return s == buffer_info.buffer_name; 711e5c31af7Sopenharmony_ci }) || 712e5c31af7Sopenharmony_ci buffer_info.buffer_name == kGeneratedColorBuffer) { 713e5c31af7Sopenharmony_ci continue; 714e5c31af7Sopenharmony_ci } 715e5c31af7Sopenharmony_ci 716e5c31af7Sopenharmony_ci buffer_file << buffer_info.buffer_name << std::endl; 717e5c31af7Sopenharmony_ci const auto& values = buffer_info.values; 718e5c31af7Sopenharmony_ci for (size_t i = 0; i < values.size(); ++i) { 719e5c31af7Sopenharmony_ci buffer_file << " " << std::setfill('0') << std::setw(2) << std::hex 720e5c31af7Sopenharmony_ci << values[i].AsUint32(); 721e5c31af7Sopenharmony_ci if (i % 16 == 15) 722e5c31af7Sopenharmony_ci buffer_file << std::endl; 723e5c31af7Sopenharmony_ci } 724e5c31af7Sopenharmony_ci buffer_file << std::endl; 725e5c31af7Sopenharmony_ci } 726e5c31af7Sopenharmony_ci buffer_file.close(); 727e5c31af7Sopenharmony_ci } 728e5c31af7Sopenharmony_ci } 729e5c31af7Sopenharmony_ci } 730e5c31af7Sopenharmony_ci 731e5c31af7Sopenharmony_ci if (!options.quiet) { 732e5c31af7Sopenharmony_ci if (!failures.empty()) { 733e5c31af7Sopenharmony_ci std::cout << "\nSummary of Failures:" << std::endl; 734e5c31af7Sopenharmony_ci 735e5c31af7Sopenharmony_ci for (const auto& failure : failures) 736e5c31af7Sopenharmony_ci std::cout << " " << failure << std::endl; 737e5c31af7Sopenharmony_ci } 738e5c31af7Sopenharmony_ci 739e5c31af7Sopenharmony_ci std::cout << "\nSummary: " 740e5c31af7Sopenharmony_ci << (options.input_filenames.size() - failures.size()) << " pass, " 741e5c31af7Sopenharmony_ci << failures.size() << " fail" << std::endl; 742e5c31af7Sopenharmony_ci } 743e5c31af7Sopenharmony_ci 744e5c31af7Sopenharmony_ci return !failures.empty(); 745e5c31af7Sopenharmony_ci} 746