| // |
| // Copyright 2019 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // system_utils: Defines common utility functions |
| |
| #include "util/test_utils.h" |
| |
| #include <EGL/egl.h> |
| #include <EGL/eglext.h> |
| |
| #include <cstring> |
| #include <fstream> |
| #include <iostream> |
| |
| namespace angle |
| { |
| |
| namespace |
| { |
| void DeleteArg(int *argc, char **argv, int argIndex) |
| { |
| // Shift the remainder of the argv list left by one. Note that argv has (*argc + 1) elements, |
| // the last one always being NULL. The following loop moves the trailing NULL element as well. |
| for (int index = argIndex; index < *argc; ++index) |
| { |
| argv[index] = argv[index + 1]; |
| } |
| (*argc)--; |
| } |
| |
| const char *GetSingleArg(const char *flag, |
| int *argc, |
| char **argv, |
| int argIndex, |
| ArgHandling handling) |
| { |
| if (strstr(argv[argIndex], flag) == argv[argIndex]) |
| { |
| const char *ptr = argv[argIndex] + strlen(flag); |
| |
| if (*ptr == '=') |
| { |
| if (handling == ArgHandling::Delete) |
| { |
| DeleteArg(argc, argv, argIndex); |
| } |
| return ptr + 1; |
| } |
| |
| if (*ptr == '\0' && argIndex < *argc - 1) |
| { |
| ptr = argv[argIndex + 1]; |
| if (handling == ArgHandling::Delete) |
| { |
| DeleteArg(argc, argv, argIndex); |
| DeleteArg(argc, argv, argIndex); |
| } |
| return ptr; |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| using DisplayTypeInfo = std::pair<const char *, EGLint>; |
| |
| const DisplayTypeInfo kDisplayTypes[] = { |
| {"d3d9", EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE}, |
| {"d3d11", EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE}, |
| {"gl", EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE}, |
| {"gles", EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE}, |
| {"metal", EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE}, |
| {"null", EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE}, |
| {"swiftshader", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE}, |
| {"vulkan", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE}, |
| {"vulkan-null", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE}, |
| }; |
| } // anonymous namespace |
| |
| bool GetFileSize(const char *filePath, uint32_t *sizeOut) |
| { |
| std::ifstream stream(filePath); |
| if (!stream) |
| { |
| return false; |
| } |
| |
| stream.seekg(0, std::ios::end); |
| *sizeOut = static_cast<uint32_t>(stream.tellg()); |
| return true; |
| } |
| |
| bool ReadEntireFileToString(const char *filePath, std::string *contentsOut) |
| { |
| std::ifstream stream(filePath); |
| if (!stream) |
| { |
| return false; |
| } |
| |
| stream.seekg(0, std::ios::end); |
| contentsOut->reserve(static_cast<unsigned int>(stream.tellg())); |
| stream.seekg(0, std::ios::beg); |
| |
| contentsOut->assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>()); |
| |
| return true; |
| } |
| |
| // static |
| Process::~Process() = default; |
| |
| ProcessHandle::ProcessHandle() : mProcess(nullptr) {} |
| |
| ProcessHandle::ProcessHandle(Process *process) : mProcess(process) {} |
| |
| ProcessHandle::ProcessHandle(const std::vector<const char *> &args, |
| ProcessOutputCapture captureOutput) |
| : mProcess(LaunchProcess(args, captureOutput)) |
| {} |
| |
| ProcessHandle::~ProcessHandle() |
| { |
| reset(); |
| } |
| |
| ProcessHandle::ProcessHandle(ProcessHandle &&other) : mProcess(other.mProcess) |
| { |
| other.mProcess = nullptr; |
| } |
| |
| ProcessHandle &ProcessHandle::operator=(ProcessHandle &&rhs) |
| { |
| std::swap(mProcess, rhs.mProcess); |
| return *this; |
| } |
| |
| void ProcessHandle::reset() |
| { |
| if (mProcess) |
| { |
| delete mProcess; |
| mProcess = nullptr; |
| } |
| } |
| |
| bool ParseIntArgWithHandling(const char *flag, |
| int *argc, |
| char **argv, |
| int argIndex, |
| int *valueOut, |
| ArgHandling handling) |
| { |
| const char *value = GetSingleArg(flag, argc, argv, argIndex, handling); |
| if (!value) |
| { |
| return false; |
| } |
| |
| char *end = nullptr; |
| const long longValue = strtol(value, &end, 10); |
| |
| if (*end != '\0') |
| { |
| printf("Error parsing integer flag value.\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (longValue == LONG_MAX || longValue == LONG_MIN || static_cast<int>(longValue) != longValue) |
| { |
| printf("Overflow when parsing integer flag value.\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| *valueOut = static_cast<int>(longValue); |
| // Note: return value is always false with ArgHandling::Preserve handling |
| return handling == ArgHandling::Delete; |
| } |
| |
| bool ParseIntArg(const char *flag, int *argc, char **argv, int argIndex, int *valueOut) |
| { |
| return ParseIntArgWithHandling(flag, argc, argv, argIndex, valueOut, ArgHandling::Delete); |
| } |
| |
| bool ParseFlag(const char *flag, int *argc, char **argv, int argIndex, bool *flagOut) |
| { |
| if (strcmp(flag, argv[argIndex]) == 0) |
| { |
| *flagOut = true; |
| DeleteArg(argc, argv, argIndex); |
| return true; |
| } |
| return false; |
| } |
| |
| bool ParseStringArg(const char *flag, int *argc, char **argv, int argIndex, std::string *valueOut) |
| { |
| const char *value = GetSingleArg(flag, argc, argv, argIndex, ArgHandling::Delete); |
| if (!value) |
| { |
| return false; |
| } |
| |
| *valueOut = value; |
| return true; |
| } |
| |
| bool ParseCStringArgWithHandling(const char *flag, |
| int *argc, |
| char **argv, |
| int argIndex, |
| const char **valueOut, |
| ArgHandling handling) |
| { |
| const char *value = GetSingleArg(flag, argc, argv, argIndex, handling); |
| if (!value) |
| { |
| return false; |
| } |
| |
| *valueOut = value; |
| // Note: return value is always false with ArgHandling::Preserve handling |
| return handling == ArgHandling::Delete; |
| } |
| |
| bool ParseCStringArg(const char *flag, int *argc, char **argv, int argIndex, const char **valueOut) |
| { |
| return ParseCStringArgWithHandling(flag, argc, argv, argIndex, valueOut, ArgHandling::Delete); |
| } |
| |
| void AddArg(int *argc, char **argv, const char *arg) |
| { |
| // This unsafe const_cast is necessary to work around gtest limitations. |
| argv[*argc] = const_cast<char *>(arg); |
| argv[*argc + 1] = nullptr; |
| (*argc)++; |
| } |
| |
| uint32_t GetPlatformANGLETypeFromArg(const char *useANGLEArg, uint32_t defaultPlatformType) |
| { |
| if (!useANGLEArg) |
| { |
| return defaultPlatformType; |
| } |
| |
| for (const DisplayTypeInfo &displayTypeInfo : kDisplayTypes) |
| { |
| if (strcmp(displayTypeInfo.first, useANGLEArg) == 0) |
| { |
| std::cout << "Using ANGLE back-end API: " << displayTypeInfo.first << std::endl; |
| return displayTypeInfo.second; |
| } |
| } |
| |
| std::cout << "Unknown ANGLE back-end API: " << useANGLEArg << std::endl; |
| exit(EXIT_FAILURE); |
| } |
| |
| uint32_t GetANGLEDeviceTypeFromArg(const char *useANGLEArg, uint32_t defaultDeviceType) |
| { |
| if (useANGLEArg) |
| { |
| if (strcmp(useANGLEArg, "swiftshader") == 0) |
| { |
| return EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE; |
| } |
| if (strstr(useANGLEArg, "null") != 0) |
| { |
| return EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE; |
| } |
| } |
| return defaultDeviceType; |
| } |
| } // namespace angle |