common: Miscellaneous cleanups (#7239)
* code: Remove some old msvc workarounds * android: Upgrade to NDK 26 * Allows access to newer libc++ * common/swap: Make use of std::endian Allows removing a bunch of defines in favor of a two liner. * common: Remove misc.cpp * GetLastErrorMsg has been in error.h for a while and also helps removing a depedency from a hot header like common_funcs * common: use SetThreadDescription API for thread names * common: Remove linear disk cache * Has never been used? * bit_set: Make constexpr * ring_buffer: Use feature macro * bit_set: Use <bit> and concepts * gsp_gpu: Restore comment * core: Ignore GCC warning --------- Co-authored-by: Lioncash <mathew1800@gmail.com> Co-authored-by: Liam <byteslice@airmail.cc>
This commit is contained in:
parent
15ea0c6336
commit
2b20082581
15 changed files with 50 additions and 426 deletions
|
@ -128,6 +128,7 @@ else()
|
||||||
# GCC may warn when it ignores attributes like maybe_unused,
|
# GCC may warn when it ignores attributes like maybe_unused,
|
||||||
# which is a problem for older versions (e.g. GCC 11).
|
# which is a problem for older versions (e.g. GCC 11).
|
||||||
add_compile_options("-Wno-attributes")
|
add_compile_options("-Wno-attributes")
|
||||||
|
add_compile_options("-Wno-interference-size")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MINGW)
|
if (MINGW)
|
||||||
|
|
|
@ -29,7 +29,7 @@ android {
|
||||||
namespace = "org.citra.citra_emu"
|
namespace = "org.citra.citra_emu"
|
||||||
|
|
||||||
compileSdkVersion = "android-34"
|
compileSdkVersion = "android-34"
|
||||||
ndkVersion = "25.2.9519653"
|
ndkVersion = "26.1.10909125"
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
|
|
@ -83,14 +83,6 @@ class GMainWindow : public QMainWindow {
|
||||||
/// Max number of recently loaded items to keep track of
|
/// Max number of recently loaded items to keep track of
|
||||||
static const int max_recent_files_item = 10;
|
static const int max_recent_files_item = 10;
|
||||||
|
|
||||||
// TODO: Make use of this!
|
|
||||||
enum {
|
|
||||||
UI_IDLE,
|
|
||||||
UI_EMU_BOOTING,
|
|
||||||
UI_EMU_RUNNING,
|
|
||||||
UI_EMU_STOPPING,
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void filterBarSetChecked(bool state);
|
void filterBarSetChecked(bool state);
|
||||||
void UpdateUITheme();
|
void UpdateUITheme();
|
||||||
|
|
|
@ -90,7 +90,6 @@ add_library(citra_common STATIC
|
||||||
file_util.cpp
|
file_util.cpp
|
||||||
file_util.h
|
file_util.h
|
||||||
hash.h
|
hash.h
|
||||||
linear_disk_cache.h
|
|
||||||
literals.h
|
literals.h
|
||||||
logging/backend.cpp
|
logging/backend.cpp
|
||||||
logging/backend.h
|
logging/backend.h
|
||||||
|
@ -110,7 +109,6 @@ add_library(citra_common STATIC
|
||||||
microprofile.cpp
|
microprofile.cpp
|
||||||
microprofile.h
|
microprofile.h
|
||||||
microprofileui.h
|
microprofileui.h
|
||||||
misc.cpp
|
|
||||||
param_package.cpp
|
param_package.cpp
|
||||||
param_package.h
|
param_package.h
|
||||||
polyfill_thread.h
|
polyfill_thread.h
|
||||||
|
|
|
@ -2,78 +2,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#ifdef _WIN32
|
|
||||||
#include <intrin.h>
|
|
||||||
#endif
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <new>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
// namespace avoids conflict with OS X Carbon; don't use BitSet<T> directly
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
// Helper functions:
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
template <typename T>
|
|
||||||
static inline int CountSetBits(T v) {
|
|
||||||
// from https://graphics.stanford.edu/~seander/bithacks.html
|
|
||||||
// GCC has this built in, but MSVC's intrinsic will only emit the actual
|
|
||||||
// POPCNT instruction, which we're not depending on
|
|
||||||
v = v - ((v >> 1) & (T) ~(T)0 / 3);
|
|
||||||
v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3);
|
|
||||||
v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15;
|
|
||||||
return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8;
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u8 val) {
|
|
||||||
unsigned long index;
|
|
||||||
_BitScanForward(&index, val);
|
|
||||||
return (int)index;
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u16 val) {
|
|
||||||
unsigned long index;
|
|
||||||
_BitScanForward(&index, val);
|
|
||||||
return (int)index;
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u32 val) {
|
|
||||||
unsigned long index;
|
|
||||||
_BitScanForward(&index, val);
|
|
||||||
return (int)index;
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u64 val) {
|
|
||||||
unsigned long index;
|
|
||||||
_BitScanForward64(&index, val);
|
|
||||||
return (int)index;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static inline int CountSetBits(u8 val) {
|
|
||||||
return __builtin_popcount(val);
|
|
||||||
}
|
|
||||||
static inline int CountSetBits(u16 val) {
|
|
||||||
return __builtin_popcount(val);
|
|
||||||
}
|
|
||||||
static inline int CountSetBits(u32 val) {
|
|
||||||
return __builtin_popcount(val);
|
|
||||||
}
|
|
||||||
static inline int CountSetBits(u64 val) {
|
|
||||||
return __builtin_popcountll(val);
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u8 val) {
|
|
||||||
return __builtin_ctz(val);
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u16 val) {
|
|
||||||
return __builtin_ctz(val);
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u32 val) {
|
|
||||||
return __builtin_ctz(val);
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u64 val) {
|
|
||||||
return __builtin_ctzll(val);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Similar to std::bitset, this is a class which encapsulates a bitset, i.e.
|
// Similar to std::bitset, this is a class which encapsulates a bitset, i.e.
|
||||||
// using the set bits of an integer to represent a set of integers. Like that
|
// using the set bits of an integer to represent a set of integers. Like that
|
||||||
// class, it acts like an array of bools:
|
// class, it acts like an array of bools:
|
||||||
|
@ -92,22 +28,19 @@ static inline int LeastSignificantSetBit(u64 val) {
|
||||||
// operation.)
|
// operation.)
|
||||||
// - Counting set bits using .Count() - see comment on that method.
|
// - Counting set bits using .Count() - see comment on that method.
|
||||||
|
|
||||||
// TODO: use constexpr when MSVC gets out of the Dark Ages
|
|
||||||
|
|
||||||
template <typename IntTy>
|
template <typename IntTy>
|
||||||
|
requires std::is_unsigned_v<IntTy>
|
||||||
class BitSet {
|
class BitSet {
|
||||||
static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// A reference to a particular bit, returned from operator[].
|
// A reference to a particular bit, returned from operator[].
|
||||||
class Ref {
|
class Ref {
|
||||||
public:
|
public:
|
||||||
Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
|
constexpr Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
|
||||||
Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
|
constexpr Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
|
||||||
operator bool() const {
|
constexpr operator bool() const {
|
||||||
return (m_bs->m_val & m_mask) != 0;
|
return (m_bs->m_val & m_mask) != 0;
|
||||||
}
|
}
|
||||||
bool operator=(bool set) {
|
constexpr bool operator=(bool set) {
|
||||||
m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
|
m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
@ -120,26 +53,26 @@ public:
|
||||||
// A STL-like iterator is required to be able to use range-based for loops.
|
// A STL-like iterator is required to be able to use range-based for loops.
|
||||||
class Iterator {
|
class Iterator {
|
||||||
public:
|
public:
|
||||||
Iterator(const Iterator& other) : m_val(other.m_val) {}
|
constexpr Iterator(const Iterator& other) : m_val(other.m_val) {}
|
||||||
Iterator(IntTy val) : m_val(val) {}
|
constexpr Iterator(IntTy val) : m_val(val) {}
|
||||||
int operator*() {
|
constexpr int operator*() {
|
||||||
// This will never be called when m_val == 0, because that would be the end() iterator
|
// This will never be called when m_val == 0, because that would be the end() iterator
|
||||||
return LeastSignificantSetBit(m_val);
|
return std::countr_zero(m_val);
|
||||||
}
|
}
|
||||||
Iterator& operator++() {
|
constexpr Iterator& operator++() {
|
||||||
// Unset least significant set bit
|
// Unset least significant set bit
|
||||||
m_val &= m_val - IntTy(1);
|
m_val &= m_val - IntTy(1);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Iterator operator++(int _) {
|
constexpr Iterator operator++(int) {
|
||||||
Iterator other(*this);
|
Iterator other(*this);
|
||||||
++*this;
|
++*this;
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
bool operator==(Iterator other) const {
|
constexpr bool operator==(Iterator other) const {
|
||||||
return m_val == other.m_val;
|
return m_val == other.m_val;
|
||||||
}
|
}
|
||||||
bool operator!=(Iterator other) const {
|
constexpr bool operator!=(Iterator other) const {
|
||||||
return m_val != other.m_val;
|
return m_val != other.m_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,74 +80,69 @@ public:
|
||||||
IntTy m_val;
|
IntTy m_val;
|
||||||
};
|
};
|
||||||
|
|
||||||
BitSet() : m_val(0) {}
|
constexpr BitSet() : m_val(0) {}
|
||||||
explicit BitSet(IntTy val) : m_val(val) {}
|
constexpr explicit BitSet(IntTy val) : m_val(val) {}
|
||||||
BitSet(std::initializer_list<int> init) {
|
constexpr BitSet(std::initializer_list<int> init) {
|
||||||
m_val = 0;
|
m_val = 0;
|
||||||
for (int bit : init)
|
for (int bit : init)
|
||||||
m_val |= (IntTy)1 << bit;
|
m_val |= (IntTy)1 << bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BitSet AllTrue(std::size_t count) {
|
constexpr static BitSet AllTrue(std::size_t count) {
|
||||||
return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
|
return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref operator[](std::size_t bit) {
|
constexpr Ref operator[](std::size_t bit) {
|
||||||
return Ref(this, (IntTy)1 << bit);
|
return Ref(this, (IntTy)1 << bit);
|
||||||
}
|
}
|
||||||
const Ref operator[](std::size_t bit) const {
|
constexpr const Ref operator[](std::size_t bit) const {
|
||||||
return (*const_cast<BitSet*>(this))[bit];
|
return (*const_cast<BitSet*>(this))[bit];
|
||||||
}
|
}
|
||||||
bool operator==(BitSet other) const {
|
constexpr bool operator==(BitSet other) const {
|
||||||
return m_val == other.m_val;
|
return m_val == other.m_val;
|
||||||
}
|
}
|
||||||
bool operator!=(BitSet other) const {
|
constexpr bool operator!=(BitSet other) const {
|
||||||
return m_val != other.m_val;
|
return m_val != other.m_val;
|
||||||
}
|
}
|
||||||
bool operator<(BitSet other) const {
|
constexpr bool operator<(BitSet other) const {
|
||||||
return m_val < other.m_val;
|
return m_val < other.m_val;
|
||||||
}
|
}
|
||||||
bool operator>(BitSet other) const {
|
constexpr bool operator>(BitSet other) const {
|
||||||
return m_val > other.m_val;
|
return m_val > other.m_val;
|
||||||
}
|
}
|
||||||
BitSet operator|(BitSet other) const {
|
constexpr BitSet operator|(BitSet other) const {
|
||||||
return BitSet(m_val | other.m_val);
|
return BitSet(m_val | other.m_val);
|
||||||
}
|
}
|
||||||
BitSet operator&(BitSet other) const {
|
constexpr BitSet operator&(BitSet other) const {
|
||||||
return BitSet(m_val & other.m_val);
|
return BitSet(m_val & other.m_val);
|
||||||
}
|
}
|
||||||
BitSet operator^(BitSet other) const {
|
constexpr BitSet operator^(BitSet other) const {
|
||||||
return BitSet(m_val ^ other.m_val);
|
return BitSet(m_val ^ other.m_val);
|
||||||
}
|
}
|
||||||
BitSet operator~() const {
|
constexpr BitSet operator~() const {
|
||||||
return BitSet(~m_val);
|
return BitSet(~m_val);
|
||||||
}
|
}
|
||||||
BitSet& operator|=(BitSet other) {
|
constexpr BitSet& operator|=(BitSet other) {
|
||||||
return *this = *this | other;
|
return *this = *this | other;
|
||||||
}
|
}
|
||||||
BitSet& operator&=(BitSet other) {
|
constexpr BitSet& operator&=(BitSet other) {
|
||||||
return *this = *this & other;
|
return *this = *this & other;
|
||||||
}
|
}
|
||||||
BitSet& operator^=(BitSet other) {
|
constexpr BitSet& operator^=(BitSet other) {
|
||||||
return *this = *this ^ other;
|
return *this = *this ^ other;
|
||||||
}
|
}
|
||||||
operator u32() = delete;
|
operator u32() = delete;
|
||||||
operator bool() {
|
constexpr operator bool() {
|
||||||
return m_val != 0;
|
return m_val != 0;
|
||||||
}
|
}
|
||||||
|
constexpr u32 Count() const {
|
||||||
// Warning: Even though on modern CPUs this is a single fast instruction,
|
return std::popcount(m_val);
|
||||||
// Dolphin's official builds do not currently assume POPCNT support on x86,
|
|
||||||
// so slower explicit bit twiddling is generated. Still should generally
|
|
||||||
// be faster than a loop.
|
|
||||||
unsigned int Count() const {
|
|
||||||
return CountSetBits(m_val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator begin() const {
|
constexpr Iterator begin() const {
|
||||||
return Iterator(m_val);
|
return Iterator(m_val);
|
||||||
}
|
}
|
||||||
Iterator end() const {
|
constexpr Iterator end() const {
|
||||||
return Iterator(0);
|
return Iterator(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
/// Textually concatenates two tokens. The double-expansion is required by the C preprocessor.
|
/// Textually concatenates two tokens. The double-expansion is required by the C preprocessor.
|
||||||
|
@ -46,14 +45,8 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#if (_MSC_VER < 1900)
|
|
||||||
// Function Cross-Compatibility
|
|
||||||
#define snprintf _snprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Locale Cross-Compatibility
|
// Locale Cross-Compatibility
|
||||||
#define locale_t _locale_t
|
#define locale_t _locale_t
|
||||||
|
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
|
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
|
||||||
|
@ -109,9 +102,3 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||||
using T = std::underlying_type_t<type>; \
|
using T = std::underlying_type_t<type>; \
|
||||||
return static_cast<T>(key) == 0; \
|
return static_cast<T>(key) == 0; \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic function to get last error message.
|
|
||||||
// Call directly after the command or use the error num.
|
|
||||||
// This function might change the error code.
|
|
||||||
// Defined in Misc.cpp.
|
|
||||||
[[nodiscard]] std::string GetLastErrorMsg();
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_paths.h"
|
#include "common/common_paths.h"
|
||||||
|
#include "common/error.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
|
@ -90,6 +91,8 @@
|
||||||
// REMEMBER: strdup considered harmful!
|
// REMEMBER: strdup considered harmful!
|
||||||
namespace FileUtil {
|
namespace FileUtil {
|
||||||
|
|
||||||
|
using Common::GetLastErrorMsg;
|
||||||
|
|
||||||
// Remove any ending forward slashes from directory paths
|
// Remove any ending forward slashes from directory paths
|
||||||
// Modifies argument.
|
// Modifies argument.
|
||||||
static void StripTailDirSlashes(std::string& fname) {
|
static void StripTailDirSlashes(std::string& fname) {
|
||||||
|
|
|
@ -1,168 +0,0 @@
|
||||||
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
// defined in Version.cpp
|
|
||||||
extern const char* scm_rev_git_str;
|
|
||||||
|
|
||||||
// On disk format:
|
|
||||||
// header{
|
|
||||||
// u32 'DCAC';
|
|
||||||
// u32 version; // svn_rev
|
|
||||||
// u16 sizeof(key_type);
|
|
||||||
// u16 sizeof(value_type);
|
|
||||||
//}
|
|
||||||
|
|
||||||
// key_value_pair{
|
|
||||||
// u32 value_size;
|
|
||||||
// key_type key;
|
|
||||||
// value_type[value_size] value;
|
|
||||||
//}
|
|
||||||
|
|
||||||
template <typename K, typename V>
|
|
||||||
class LinearDiskCacheReader {
|
|
||||||
public:
|
|
||||||
virtual void Read(const K& key, const V* value, u32 value_size) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Dead simple unsorted key-value store with append functionality.
|
|
||||||
// No random read functionality, all reading is done in OpenAndRead.
|
|
||||||
// Keys and values can contain any characters, including \0.
|
|
||||||
//
|
|
||||||
// Suitable for caching generated shader bytecode between executions.
|
|
||||||
// Not tuned for extreme performance but should be reasonably fast.
|
|
||||||
// Does not support keys or values larger than 2GB, which should be reasonable.
|
|
||||||
// Keys must have non-zero length; values can have zero length.
|
|
||||||
|
|
||||||
// K and V are some POD type
|
|
||||||
// K : the key type
|
|
||||||
// V : value array type
|
|
||||||
template <typename K, typename V>
|
|
||||||
class LinearDiskCache {
|
|
||||||
public:
|
|
||||||
// return number of read entries
|
|
||||||
u32 OpenAndRead(const char* filename, LinearDiskCacheReader<K, V>& reader) {
|
|
||||||
using std::ios_base;
|
|
||||||
|
|
||||||
// close any currently opened file
|
|
||||||
Close();
|
|
||||||
m_num_entries = 0;
|
|
||||||
|
|
||||||
// try opening for reading/writing
|
|
||||||
OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary);
|
|
||||||
|
|
||||||
m_file.seekg(0, std::ios::end);
|
|
||||||
std::fstream::pos_type end_pos = m_file.tellg();
|
|
||||||
m_file.seekg(0, std::ios::beg);
|
|
||||||
std::fstream::pos_type start_pos = m_file.tellg();
|
|
||||||
std::streamoff file_size = end_pos - start_pos;
|
|
||||||
|
|
||||||
if (m_file.is_open() && ValidateHeader()) {
|
|
||||||
// good header, read some key/value pairs
|
|
||||||
K key;
|
|
||||||
|
|
||||||
std::vector<V> value;
|
|
||||||
u32 value_size;
|
|
||||||
u32 entry_number;
|
|
||||||
|
|
||||||
std::fstream::pos_type last_pos = m_file.tellg();
|
|
||||||
|
|
||||||
while (Read(&value_size)) {
|
|
||||||
std::streamoff next_extent =
|
|
||||||
(last_pos - start_pos) + sizeof(value_size) + value_size;
|
|
||||||
if (next_extent > file_size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
value.clear();
|
|
||||||
value.resize(value_size);
|
|
||||||
|
|
||||||
// read key/value and pass to reader
|
|
||||||
if (Read(&key) && Read(value.data(), value_size) && Read(&entry_number) &&
|
|
||||||
entry_number == m_num_entries + 1) {
|
|
||||||
reader.Read(key, value.data(), value_size);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_num_entries++;
|
|
||||||
last_pos = m_file.tellg();
|
|
||||||
}
|
|
||||||
m_file.seekp(last_pos);
|
|
||||||
m_file.clear();
|
|
||||||
|
|
||||||
value.clear();
|
|
||||||
return m_num_entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
// failed to open file for reading or bad header
|
|
||||||
// close and recreate file
|
|
||||||
Close();
|
|
||||||
m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary);
|
|
||||||
WriteHeader();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sync() {
|
|
||||||
m_file.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close() {
|
|
||||||
if (m_file.is_open())
|
|
||||||
m_file.close();
|
|
||||||
// clear any error flags
|
|
||||||
m_file.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Appends a key-value pair to the store.
|
|
||||||
void Append(const K& key, const V* value, u32 value_size) {
|
|
||||||
// TODO: Should do a check that we don't already have "key"? (I think each caller does that
|
|
||||||
// already.)
|
|
||||||
Write(&value_size);
|
|
||||||
Write(&key);
|
|
||||||
Write(value, value_size);
|
|
||||||
m_num_entries++;
|
|
||||||
Write(&m_num_entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void WriteHeader() {
|
|
||||||
Write(&m_header);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ValidateHeader() {
|
|
||||||
char file_header[sizeof(Header)];
|
|
||||||
|
|
||||||
return (Read(file_header, sizeof(Header)) &&
|
|
||||||
!memcmp((const char*)&m_header, file_header, sizeof(Header)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename D>
|
|
||||||
bool Write(const D* data, u32 count = 1) {
|
|
||||||
return m_file.write((const char*)data, count * sizeof(D)).good();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename D>
|
|
||||||
bool Read(const D* data, u32 count = 1) {
|
|
||||||
return m_file.read((char*)data, count * sizeof(D)).good();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Header {
|
|
||||||
Header() : id(*(u32*)"DCAC"), key_t_size(sizeof(K)), value_t_size(sizeof(V)) {
|
|
||||||
std::memcpy(ver, scm_rev_git_str, 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
const u32 id;
|
|
||||||
const u16 key_t_size, value_t_size;
|
|
||||||
char ver[40];
|
|
||||||
|
|
||||||
} m_header;
|
|
||||||
|
|
||||||
std::fstream m_file;
|
|
||||||
u32 m_num_entries;
|
|
||||||
};
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <cerrno>
|
|
||||||
#include <cstring>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
|
||||||
|
|
||||||
// Generic function to get last error message.
|
|
||||||
// Call directly after the command or use the error num.
|
|
||||||
// This function might change the error code.
|
|
||||||
std::string GetLastErrorMsg() {
|
|
||||||
#ifdef _WIN32
|
|
||||||
LPSTR err_str;
|
|
||||||
|
|
||||||
DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
||||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
||||||
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
||||||
reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
|
|
||||||
if (!res) {
|
|
||||||
return "(FormatMessageA failed to format error)";
|
|
||||||
}
|
|
||||||
std::string ret(err_str);
|
|
||||||
LocalFree(err_str);
|
|
||||||
return ret;
|
|
||||||
#else
|
|
||||||
char err_str[255];
|
|
||||||
#if (defined(__GLIBC__) || __ANDROID_API__ >= 23) && \
|
|
||||||
(_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
|
|
||||||
// Thread safe (GNU-specific)
|
|
||||||
const char* str = strerror_r(errno, err_str, sizeof(err_str));
|
|
||||||
return std::string(str);
|
|
||||||
#else
|
|
||||||
// Thread safe (XSI-compliant)
|
|
||||||
int second_err = strerror_r(errno, err_str, sizeof(err_str));
|
|
||||||
if (second_err != 0) {
|
|
||||||
return "(strerror_r failed to format error)";
|
|
||||||
}
|
|
||||||
return std::string(err_str);
|
|
||||||
#endif // GLIBC etc.
|
|
||||||
#endif // _WIN32
|
|
||||||
}
|
|
|
@ -105,9 +105,7 @@ public:
|
||||||
private:
|
private:
|
||||||
// It is important to separate the below atomics for performance reasons:
|
// It is important to separate the below atomics for performance reasons:
|
||||||
// Having them on the same cache-line would result in false-sharing between them.
|
// Having them on the same cache-line would result in false-sharing between them.
|
||||||
// TODO: Remove this ifdef whenever clang and GCC support
|
#ifdef __cpp_lib_hardware_interference_size
|
||||||
// std::hardware_destructive_interference_size.
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1911
|
|
||||||
static constexpr std::size_t padding_size =
|
static constexpr std::size_t padding_size =
|
||||||
std::hardware_destructive_interference_size - sizeof(std::atomic_size_t);
|
std::hardware_destructive_interference_size - sizeof(std::atomic_size_t);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -17,43 +17,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#endif
|
#endif
|
||||||
|
#include <bit>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <type_traits>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
// GCC
|
|
||||||
#ifdef __GNUC__
|
|
||||||
|
|
||||||
#if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN)
|
|
||||||
#define COMMON_LITTLE_ENDIAN 1
|
|
||||||
#elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && !defined(COMMON_BIG_ENDIAN)
|
|
||||||
#define COMMON_BIG_ENDIAN 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// LLVM/clang
|
|
||||||
#elif defined(__clang__)
|
|
||||||
|
|
||||||
#if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN)
|
|
||||||
#define COMMON_LITTLE_ENDIAN 1
|
|
||||||
#elif __BIG_ENDIAN__ && !defined(COMMON_BIG_ENDIAN)
|
|
||||||
#define COMMON_BIG_ENDIAN 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// MSVC
|
|
||||||
#elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN)
|
|
||||||
|
|
||||||
#define COMMON_LITTLE_ENDIAN 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Worst case, default to little endian.
|
|
||||||
#if !COMMON_BIG_ENDIAN && !COMMON_LITTLE_ENDIAN
|
|
||||||
#define COMMON_LITTLE_ENDIAN 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -675,17 +646,8 @@ struct AddEndian<T, SwapTag> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Alias LETag/BETag as KeepTag/SwapTag depending on the system
|
// Alias LETag/BETag as KeepTag/SwapTag depending on the system
|
||||||
#if COMMON_LITTLE_ENDIAN
|
using LETag = std::conditional_t<std::endian::native == std::endian::little, KeepTag, SwapTag>;
|
||||||
|
using BETag = std::conditional_t<std::endian::native == std::endian::big, KeepTag, SwapTag>;
|
||||||
using LETag = KeepTag;
|
|
||||||
using BETag = SwapTag;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
using BETag = KeepTag;
|
|
||||||
using LETag = SwapTag;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Aliases for LE types
|
// Aliases for LE types
|
||||||
using u16_le = AddEndian<u16, LETag>::type;
|
using u16_le = AddEndian<u16, LETag>::type;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include "common/string_util.h"
|
||||||
#else
|
#else
|
||||||
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
#include <pthread_np.h>
|
#include <pthread_np.h>
|
||||||
|
@ -82,29 +83,8 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
// Sets the debugger-visible name of the current thread.
|
// Sets the debugger-visible name of the current thread.
|
||||||
// Uses trick documented in:
|
|
||||||
// https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code
|
|
||||||
void SetCurrentThreadName(const char* name) {
|
void SetCurrentThreadName(const char* name) {
|
||||||
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
SetThreadDescription(GetCurrentThread(), UTF8ToUTF16W(name).data());
|
||||||
|
|
||||||
#pragma pack(push, 8)
|
|
||||||
struct THREADNAME_INFO {
|
|
||||||
DWORD dwType; // must be 0x1000
|
|
||||||
LPCSTR szName; // pointer to name (in user addr space)
|
|
||||||
DWORD dwThreadID; // thread ID (-1=caller thread)
|
|
||||||
DWORD dwFlags; // reserved for future use, must be zero
|
|
||||||
} info;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
info.dwType = 0x1000;
|
|
||||||
info.szName = name;
|
|
||||||
info.dwThreadID = std::numeric_limits<DWORD>::max();
|
|
||||||
info.dwFlags = 0;
|
|
||||||
|
|
||||||
__try {
|
|
||||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
|
||||||
} __except (EXCEPTION_CONTINUE_EXECUTION) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !MSVC_VER, so must be POSIX threads
|
#else // !MSVC_VER, so must be POSIX threads
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "common/archives.h"
|
#include "common/archives.h"
|
||||||
|
#include "common/error.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
@ -103,7 +104,7 @@ ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFileBase(const Path& pa
|
||||||
|
|
||||||
FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
|
FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
|
||||||
if (!file.IsOpen()) {
|
if (!file.IsOpen()) {
|
||||||
LOG_CRITICAL(Service_FS, "Error opening {}: {}", full_path, GetLastErrorMsg());
|
LOG_CRITICAL(Service_FS, "Error opening {}: {}", full_path, Common::GetLastErrorMsg());
|
||||||
return ERROR_NOT_FOUND;
|
return ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,10 +97,8 @@ struct FrameBufferUpdate {
|
||||||
static_assert(sizeof(FrameBufferUpdate) == 0x40, "Struct has incorrect size");
|
static_assert(sizeof(FrameBufferUpdate) == 0x40, "Struct has incorrect size");
|
||||||
// TODO: Not sure if this padding is correct.
|
// TODO: Not sure if this padding is correct.
|
||||||
// Chances are the second block is stored at offset 0x24 rather than 0x20.
|
// Chances are the second block is stored at offset 0x24 rather than 0x20.
|
||||||
#ifndef _MSC_VER
|
|
||||||
static_assert(offsetof(FrameBufferUpdate, framebuffer_info[1]) == 0x20,
|
static_assert(offsetof(FrameBufferUpdate, framebuffer_info[1]) == 0x20,
|
||||||
"FrameBufferInfo element has incorrect alignment");
|
"FrameBufferInfo element has incorrect alignment");
|
||||||
#endif
|
|
||||||
|
|
||||||
/// GSP command
|
/// GSP command
|
||||||
struct Command {
|
struct Command {
|
||||||
|
|
|
@ -64,22 +64,14 @@ private:
|
||||||
};
|
};
|
||||||
static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
|
static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
|
||||||
|
|
||||||
// TODO: MSVC does not support using offsetof() on non-static data members even though this
|
|
||||||
// is technically allowed since C++11. This macro should be enabled once MSVC adds
|
|
||||||
// support for that.
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
#define ASSERT_REG_POSITION(field_name, position) \
|
#define ASSERT_REG_POSITION(field_name, position) \
|
||||||
static_assert(offsetof(Regs, field_name) == position * 4, \
|
static_assert(offsetof(Regs, field_name) == position * 4, \
|
||||||
"Field " #field_name " has invalid position")
|
"Field " #field_name " has invalid position")
|
||||||
|
|
||||||
ASSERT_REG_POSITION(color_fill_top, 0x81);
|
ASSERT_REG_POSITION(color_fill_top, 0x81);
|
||||||
ASSERT_REG_POSITION(backlight_top, 0x90);
|
ASSERT_REG_POSITION(backlight_top, 0x90);
|
||||||
ASSERT_REG_POSITION(color_fill_bottom, 0x281);
|
ASSERT_REG_POSITION(color_fill_bottom, 0x281);
|
||||||
ASSERT_REG_POSITION(backlight_bottom, 0x290);
|
ASSERT_REG_POSITION(backlight_bottom, 0x290);
|
||||||
|
|
||||||
#undef ASSERT_REG_POSITION
|
|
||||||
#endif // !defined(_MSC_VER)
|
|
||||||
|
|
||||||
extern Regs g_regs;
|
extern Regs g_regs;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
Loading…
Reference in a new issue