| // | |
| // 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 |