// // 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 #include #include #include #include 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 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}, {"webgpu", EGL_PLATFORM_ANGLE_TYPE_WEBGPU_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(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(stream.tellg())); stream.seekg(0, std::ios::beg); contentsOut->assign((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); return true; } // static Process::~Process() = default; ProcessHandle::ProcessHandle() : mProcess(nullptr) {} ProcessHandle::ProcessHandle(Process *process) : mProcess(process) {} ProcessHandle::ProcessHandle(const std::vector &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(longValue) != longValue) { printf("Overflow when parsing integer flag value.\n"); exit(EXIT_FAILURE); } *valueOut = static_cast(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(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