mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-27 08:05:41 +00:00
4a70164dac
Needed for running on Asahi Linux.
227 lines
9.3 KiB
C++
227 lines
9.3 KiB
C++
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
|
|
|
#pragma once
|
|
#include <bit>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <type_traits>
|
|
|
|
// Force inline helper
|
|
#ifndef ALWAYS_INLINE
|
|
#if defined(_MSC_VER)
|
|
#define ALWAYS_INLINE __forceinline
|
|
#elif defined(__GNUC__) || defined(__clang__)
|
|
#define ALWAYS_INLINE __attribute__((always_inline)) inline
|
|
#else
|
|
#define ALWAYS_INLINE inline
|
|
#endif
|
|
#endif
|
|
|
|
// Force inline in non-debug helper
|
|
#ifdef _DEBUG
|
|
#define ALWAYS_INLINE_RELEASE inline
|
|
#else
|
|
#define ALWAYS_INLINE_RELEASE ALWAYS_INLINE
|
|
#endif
|
|
|
|
// unreferenced parameter macro
|
|
#ifndef UNREFERENCED_VARIABLE
|
|
#if defined(__GNUC__) || defined(__clang__) || defined(__EMSCRIPTEN__)
|
|
#define UNREFERENCED_VARIABLE(P) (void)(P)
|
|
#else
|
|
#define UNREFERENCED_VARIABLE(P) (P)
|
|
#endif
|
|
#endif
|
|
|
|
// countof macro
|
|
#ifndef countof
|
|
#ifdef _countof
|
|
#define countof _countof
|
|
#else
|
|
template<typename T, size_t N>
|
|
char (&__countof_ArraySizeHelper(T (&array)[N]))[N];
|
|
#define countof(array) (sizeof(__countof_ArraySizeHelper(array)))
|
|
#endif
|
|
#endif
|
|
|
|
// offsetof macro
|
|
#ifndef offsetof
|
|
#define offsetof(st, m) ((size_t)((char*)&((st*)(0))->m - (char*)0))
|
|
#endif
|
|
|
|
#ifdef __GNUC__
|
|
#define printflike(n, m) __attribute__((format(printf, n, m)))
|
|
#else
|
|
#define printflike(n, m)
|
|
#endif
|
|
|
|
// [[noreturn]] which can be used on function pointers.
|
|
#ifdef _MSC_VER
|
|
// __declspec(noreturn) produces error C3829.
|
|
#define NORETURN_FUNCTION_POINTER
|
|
#else
|
|
#define NORETURN_FUNCTION_POINTER __attribute__((noreturn))
|
|
#endif
|
|
|
|
// __assume, potentially enables optimization.
|
|
#ifdef _MSC_VER
|
|
#define ASSUME(x) __assume(x)
|
|
#else
|
|
#define ASSUME(x) \
|
|
do \
|
|
{ \
|
|
if (!(x)) \
|
|
__builtin_unreachable(); \
|
|
} while (0)
|
|
#endif
|
|
|
|
// disable warnings that show up at warning level 4
|
|
// TODO: Move to build system instead
|
|
#ifdef _MSC_VER
|
|
#pragma warning(disable : 4201) // warning C4201: nonstandard extension used : nameless struct/union
|
|
#pragma warning(disable : 4100) // warning C4100: 'Platform' : unreferenced formal parameter
|
|
#pragma warning(disable : 4355) // warning C4355: 'this' : used in base member initializer list
|
|
#endif
|
|
|
|
using s8 = int8_t;
|
|
using u8 = uint8_t;
|
|
using s16 = int16_t;
|
|
using u16 = uint16_t;
|
|
using s32 = int32_t;
|
|
using u32 = uint32_t;
|
|
using s64 = int64_t;
|
|
using u64 = uint64_t;
|
|
|
|
// Enable use of static_assert in constexpr if
|
|
template<class T>
|
|
struct dependent_false : std::false_type
|
|
{
|
|
};
|
|
template<int T>
|
|
struct dependent_int_false : std::false_type
|
|
{
|
|
};
|
|
|
|
// Architecture detection.
|
|
#if defined(_MSC_VER)
|
|
|
|
#if defined(_M_X64)
|
|
#define CPU_ARCH_X64 1
|
|
#elif defined(_M_IX86)
|
|
#define CPU_ARCH_X86 1
|
|
#elif defined(_M_ARM64)
|
|
#define CPU_ARCH_ARM64 1
|
|
#elif defined(_M_ARM)
|
|
#define CPU_ARCH_ARM32 1
|
|
#else
|
|
#error Unknown architecture.
|
|
#endif
|
|
|
|
#elif defined(__GNUC__) || defined(__clang__)
|
|
|
|
#if defined(__x86_64__)
|
|
#define CPU_ARCH_X64 1
|
|
#elif defined(__i386__)
|
|
#define CPU_ARCH_X86 1
|
|
#elif defined(__aarch64__)
|
|
#define CPU_ARCH_ARM64 1
|
|
#elif defined(__arm__)
|
|
#define CPU_ARCH_ARM32 1
|
|
#elif defined(__riscv) && __riscv_xlen == 64
|
|
#define CPU_ARCH_RISCV64 1
|
|
#else
|
|
#error Unknown architecture.
|
|
#endif
|
|
|
|
#else
|
|
|
|
#error Unknown compiler.
|
|
|
|
#endif
|
|
|
|
#if defined(CPU_ARCH_X64)
|
|
#define CPU_ARCH_STR "x64"
|
|
#elif defined(CPU_ARCH_X86)
|
|
#define CPU_ARCH_STR "x86"
|
|
#elif defined(CPU_ARCH_ARM32)
|
|
#define CPU_ARCH_STR "arm32"
|
|
#elif defined(CPU_ARCH_ARM64)
|
|
#define CPU_ARCH_STR "arm64"
|
|
#elif defined(CPU_ARCH_RISCV64)
|
|
#define CPU_ARCH_STR "riscv64"
|
|
#else
|
|
#define CPU_ARCH_STR "Unknown"
|
|
#endif
|
|
|
|
// OS detection.
|
|
#if defined(_WIN32)
|
|
#define TARGET_OS_STR "Windows"
|
|
#elif defined(__ANDROID__)
|
|
#define TARGET_OS_STR "Android"
|
|
#elif defined(__linux__)
|
|
#define TARGET_OS_STR "Linux"
|
|
#elif defined(__FreeBSD__)
|
|
#define TARGET_OS_STR "FreeBSD"
|
|
#elif defined(__APPLE__)
|
|
#define TARGET_OS_STR "macOS"
|
|
#else
|
|
#define TARGET_OS_STR "Unknown"
|
|
#endif
|
|
|
|
// Host page sizes.
|
|
#if defined(OVERRIDE_HOST_PAGE_SIZE)
|
|
static constexpr u32 HOST_PAGE_SIZE = OVERRIDE_HOST_PAGE_SIZE;
|
|
static constexpr u32 HOST_PAGE_MASK = HOST_PAGE_SIZE - 1;
|
|
static constexpr u32 HOST_PAGE_SHIFT = std::bit_width(HOST_PAGE_MASK);
|
|
#elif defined(__APPLE__) && defined(__aarch64__)
|
|
static constexpr u32 HOST_PAGE_SIZE = 0x4000;
|
|
static constexpr u32 HOST_PAGE_MASK = HOST_PAGE_SIZE - 1;
|
|
static constexpr u32 HOST_PAGE_SHIFT = 14;
|
|
#else
|
|
static constexpr u32 HOST_PAGE_SIZE = 0x1000;
|
|
static constexpr u32 HOST_PAGE_MASK = HOST_PAGE_SIZE - 1;
|
|
static constexpr u32 HOST_PAGE_SHIFT = 12;
|
|
#endif
|
|
|
|
// Enum class bitwise operators
|
|
#define IMPLEMENT_ENUM_CLASS_BITWISE_OPERATORS(type_) \
|
|
ALWAYS_INLINE constexpr type_ operator&(type_ lhs, type_ rhs) \
|
|
{ \
|
|
return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) & \
|
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
|
} \
|
|
ALWAYS_INLINE constexpr type_ operator|(type_ lhs, type_ rhs) \
|
|
{ \
|
|
return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) | \
|
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
|
} \
|
|
ALWAYS_INLINE constexpr type_ operator^(type_ lhs, type_ rhs) \
|
|
{ \
|
|
return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) ^ \
|
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
|
} \
|
|
ALWAYS_INLINE constexpr type_ operator~(type_ val) \
|
|
{ \
|
|
return static_cast<type_>(~static_cast<std::underlying_type<type_>::type>(val)); \
|
|
} \
|
|
ALWAYS_INLINE constexpr type_& operator&=(type_& lhs, type_ rhs) \
|
|
{ \
|
|
lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) & \
|
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
|
return lhs; \
|
|
} \
|
|
ALWAYS_INLINE constexpr type_& operator|=(type_& lhs, type_ rhs) \
|
|
{ \
|
|
lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) | \
|
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
|
return lhs; \
|
|
} \
|
|
ALWAYS_INLINE constexpr type_& operator^=(type_& lhs, type_ rhs) \
|
|
{ \
|
|
lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) ^ \
|
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
|
return lhs; \
|
|
}
|