Compare commits
	
		
			11 Commits
		
	
	
		
			gs-uniform
			...
			msvc-clean
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2e963dee02 | ||
| 
						 | 
					b62278d16e | ||
| 
						 | 
					3f55c6b813 | ||
| 
						 | 
					6c55ebac77 | ||
| 
						 | 
					5c2a0c4e37 | ||
| 
						 | 
					0afaa31df5 | ||
| 
						 | 
					bd1ffc34ef | ||
| 
						 | 
					d487afd43c | ||
| 
						 | 
					d4c26a6d95 | ||
| 
						 | 
					2db9328087 | ||
| 
						 | 
					6b4ff943da | 
@@ -128,6 +128,7 @@ else()
 | 
			
		||||
        # GCC may warn when it ignores attributes like maybe_unused,
 | 
			
		||||
        # which is a problem for older versions (e.g. GCC 11).
 | 
			
		||||
        add_compile_options("-Wno-attributes")
 | 
			
		||||
        add_compile_options("-Wno-interference-size")
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
    if (MINGW)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ android {
 | 
			
		||||
    namespace = "org.citra.citra_emu"
 | 
			
		||||
 | 
			
		||||
    compileSdkVersion = "android-34"
 | 
			
		||||
    ndkVersion = "25.2.9519653"
 | 
			
		||||
    ndkVersion = "26.1.10909125"
 | 
			
		||||
 | 
			
		||||
    compileOptions {
 | 
			
		||||
        sourceCompatibility = JavaVersion.VERSION_17
 | 
			
		||||
 
 | 
			
		||||
@@ -83,14 +83,6 @@ class GMainWindow : public QMainWindow {
 | 
			
		||||
    /// Max number of recently loaded items to keep track of
 | 
			
		||||
    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:
 | 
			
		||||
    void filterBarSetChecked(bool state);
 | 
			
		||||
    void UpdateUITheme();
 | 
			
		||||
 
 | 
			
		||||
@@ -90,7 +90,6 @@ add_library(citra_common STATIC
 | 
			
		||||
    file_util.cpp
 | 
			
		||||
    file_util.h
 | 
			
		||||
    hash.h
 | 
			
		||||
    linear_disk_cache.h
 | 
			
		||||
    literals.h
 | 
			
		||||
    logging/backend.cpp
 | 
			
		||||
    logging/backend.h
 | 
			
		||||
@@ -110,7 +109,6 @@ add_library(citra_common STATIC
 | 
			
		||||
    microprofile.cpp
 | 
			
		||||
    microprofile.h
 | 
			
		||||
    microprofileui.h
 | 
			
		||||
    misc.cpp
 | 
			
		||||
    param_package.cpp
 | 
			
		||||
    param_package.h
 | 
			
		||||
    polyfill_thread.h
 | 
			
		||||
 
 | 
			
		||||
@@ -2,78 +2,14 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <bit>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#include <intrin.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <new>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
// namespace avoids conflict with OS X Carbon; don't use BitSet<T> directly
 | 
			
		||||
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.
 | 
			
		||||
// using the set bits of an integer to represent a set of integers.  Like that
 | 
			
		||||
// class, it acts like an array of bools:
 | 
			
		||||
@@ -92,22 +28,19 @@ static inline int LeastSignificantSetBit(u64 val) {
 | 
			
		||||
//   operation.)
 | 
			
		||||
// - Counting set bits using .Count() - see comment on that method.
 | 
			
		||||
 | 
			
		||||
// TODO: use constexpr when MSVC gets out of the Dark Ages
 | 
			
		||||
 | 
			
		||||
template <typename IntTy>
 | 
			
		||||
    requires std::is_unsigned_v<IntTy>
 | 
			
		||||
class BitSet {
 | 
			
		||||
    static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    // A reference to a particular bit, returned from operator[].
 | 
			
		||||
    class Ref {
 | 
			
		||||
    public:
 | 
			
		||||
        Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
 | 
			
		||||
        Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
 | 
			
		||||
        operator bool() const {
 | 
			
		||||
        constexpr Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
 | 
			
		||||
        constexpr Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
 | 
			
		||||
        constexpr operator bool() const {
 | 
			
		||||
            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);
 | 
			
		||||
            return set;
 | 
			
		||||
        }
 | 
			
		||||
@@ -120,26 +53,26 @@ public:
 | 
			
		||||
    // A STL-like iterator is required to be able to use range-based for loops.
 | 
			
		||||
    class Iterator {
 | 
			
		||||
    public:
 | 
			
		||||
        Iterator(const Iterator& other) : m_val(other.m_val) {}
 | 
			
		||||
        Iterator(IntTy val) : m_val(val) {}
 | 
			
		||||
        int operator*() {
 | 
			
		||||
        constexpr Iterator(const Iterator& other) : m_val(other.m_val) {}
 | 
			
		||||
        constexpr Iterator(IntTy val) : m_val(val) {}
 | 
			
		||||
        constexpr int operator*() {
 | 
			
		||||
            // 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
 | 
			
		||||
            m_val &= m_val - IntTy(1);
 | 
			
		||||
            return *this;
 | 
			
		||||
        }
 | 
			
		||||
        Iterator operator++(int _) {
 | 
			
		||||
        constexpr Iterator operator++(int) {
 | 
			
		||||
            Iterator other(*this);
 | 
			
		||||
            ++*this;
 | 
			
		||||
            return other;
 | 
			
		||||
        }
 | 
			
		||||
        bool operator==(Iterator other) const {
 | 
			
		||||
        constexpr bool operator==(Iterator other) const {
 | 
			
		||||
            return m_val == other.m_val;
 | 
			
		||||
        }
 | 
			
		||||
        bool operator!=(Iterator other) const {
 | 
			
		||||
        constexpr bool operator!=(Iterator other) const {
 | 
			
		||||
            return m_val != other.m_val;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -147,74 +80,69 @@ public:
 | 
			
		||||
        IntTy m_val;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    BitSet() : m_val(0) {}
 | 
			
		||||
    explicit BitSet(IntTy val) : m_val(val) {}
 | 
			
		||||
    BitSet(std::initializer_list<int> init) {
 | 
			
		||||
    constexpr BitSet() : m_val(0) {}
 | 
			
		||||
    constexpr explicit BitSet(IntTy val) : m_val(val) {}
 | 
			
		||||
    constexpr BitSet(std::initializer_list<int> init) {
 | 
			
		||||
        m_val = 0;
 | 
			
		||||
        for (int bit : init)
 | 
			
		||||
            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));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ref operator[](std::size_t bit) {
 | 
			
		||||
    constexpr Ref operator[](std::size_t 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];
 | 
			
		||||
    }
 | 
			
		||||
    bool operator==(BitSet other) const {
 | 
			
		||||
    constexpr bool operator==(BitSet other) const {
 | 
			
		||||
        return m_val == other.m_val;
 | 
			
		||||
    }
 | 
			
		||||
    bool operator!=(BitSet other) const {
 | 
			
		||||
    constexpr bool operator!=(BitSet other) const {
 | 
			
		||||
        return m_val != other.m_val;
 | 
			
		||||
    }
 | 
			
		||||
    bool operator<(BitSet other) const {
 | 
			
		||||
    constexpr bool operator<(BitSet other) const {
 | 
			
		||||
        return m_val < other.m_val;
 | 
			
		||||
    }
 | 
			
		||||
    bool operator>(BitSet other) const {
 | 
			
		||||
    constexpr bool operator>(BitSet other) const {
 | 
			
		||||
        return m_val > other.m_val;
 | 
			
		||||
    }
 | 
			
		||||
    BitSet operator|(BitSet other) const {
 | 
			
		||||
    constexpr BitSet operator|(BitSet other) const {
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
    BitSet operator^(BitSet other) const {
 | 
			
		||||
    constexpr BitSet operator^(BitSet other) const {
 | 
			
		||||
        return BitSet(m_val ^ other.m_val);
 | 
			
		||||
    }
 | 
			
		||||
    BitSet operator~() const {
 | 
			
		||||
    constexpr BitSet operator~() const {
 | 
			
		||||
        return BitSet(~m_val);
 | 
			
		||||
    }
 | 
			
		||||
    BitSet& operator|=(BitSet other) {
 | 
			
		||||
    constexpr BitSet& operator|=(BitSet other) {
 | 
			
		||||
        return *this = *this | other;
 | 
			
		||||
    }
 | 
			
		||||
    BitSet& operator&=(BitSet other) {
 | 
			
		||||
    constexpr BitSet& operator&=(BitSet other) {
 | 
			
		||||
        return *this = *this & other;
 | 
			
		||||
    }
 | 
			
		||||
    BitSet& operator^=(BitSet other) {
 | 
			
		||||
    constexpr BitSet& operator^=(BitSet other) {
 | 
			
		||||
        return *this = *this ^ other;
 | 
			
		||||
    }
 | 
			
		||||
    operator u32() = delete;
 | 
			
		||||
    operator bool() {
 | 
			
		||||
    constexpr operator bool() {
 | 
			
		||||
        return m_val != 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Warning: Even though on modern CPUs this is a single fast instruction,
 | 
			
		||||
    // 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);
 | 
			
		||||
    constexpr u32 Count() const {
 | 
			
		||||
        return std::popcount(m_val);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Iterator begin() const {
 | 
			
		||||
    constexpr Iterator begin() const {
 | 
			
		||||
        return Iterator(m_val);
 | 
			
		||||
    }
 | 
			
		||||
    Iterator end() const {
 | 
			
		||||
    constexpr Iterator end() const {
 | 
			
		||||
        return Iterator(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
/// Textually concatenates two tokens. The double-expansion is required by the C preprocessor.
 | 
			
		||||
@@ -46,14 +45,8 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
#if (_MSC_VER < 1900)
 | 
			
		||||
// Function Cross-Compatibility
 | 
			
		||||
#define snprintf _snprintf
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Locale Cross-Compatibility
 | 
			
		||||
#define locale_t _locale_t
 | 
			
		||||
 | 
			
		||||
#endif // _MSC_VER
 | 
			
		||||
 | 
			
		||||
#define DECLARE_ENUM_FLAG_OPERATORS(type)                                                          \
 | 
			
		||||
@@ -109,9 +102,3 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
 | 
			
		||||
        using T = std::underlying_type_t<type>;                                                    \
 | 
			
		||||
        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/common_funcs.h"
 | 
			
		||||
#include "common/common_paths.h"
 | 
			
		||||
#include "common/error.h"
 | 
			
		||||
#include "common/file_util.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/scope_exit.h"
 | 
			
		||||
@@ -90,6 +91,8 @@
 | 
			
		||||
// REMEMBER: strdup considered harmful!
 | 
			
		||||
namespace FileUtil {
 | 
			
		||||
 | 
			
		||||
using Common::GetLastErrorMsg;
 | 
			
		||||
 | 
			
		||||
// Remove any ending forward slashes from directory paths
 | 
			
		||||
// Modifies argument.
 | 
			
		||||
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:
 | 
			
		||||
    // 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.
 | 
			
		||||
    // TODO: Remove this ifdef whenever clang and GCC support
 | 
			
		||||
    //       std::hardware_destructive_interference_size.
 | 
			
		||||
#if defined(_MSC_VER) && _MSC_VER >= 1911
 | 
			
		||||
#ifdef __cpp_lib_hardware_interference_size
 | 
			
		||||
    static constexpr std::size_t padding_size =
 | 
			
		||||
        std::hardware_destructive_interference_size - sizeof(std::atomic_size_t);
 | 
			
		||||
#else
 | 
			
		||||
 
 | 
			
		||||
@@ -17,43 +17,14 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#endif
 | 
			
		||||
#include <bit>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#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 {
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
@@ -675,17 +646,8 @@ struct AddEndian<T, SwapTag> {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Alias LETag/BETag as KeepTag/SwapTag depending on the system
 | 
			
		||||
#if COMMON_LITTLE_ENDIAN
 | 
			
		||||
 | 
			
		||||
using LETag = KeepTag;
 | 
			
		||||
using BETag = SwapTag;
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
using BETag = KeepTag;
 | 
			
		||||
using LETag = SwapTag;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
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>;
 | 
			
		||||
 | 
			
		||||
// Aliases for LE types
 | 
			
		||||
using u16_le = AddEndian<u16, LETag>::type;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
#include <mach/mach.h>
 | 
			
		||||
#elif defined(_WIN32)
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include "common/string_util.h"
 | 
			
		||||
#else
 | 
			
		||||
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
 | 
			
		||||
#include <pthread_np.h>
 | 
			
		||||
@@ -82,29 +83,8 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
 | 
			
		||||
// 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) {
 | 
			
		||||
    static const DWORD MS_VC_EXCEPTION = 0x406D1388;
 | 
			
		||||
 | 
			
		||||
#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) {
 | 
			
		||||
    }
 | 
			
		||||
    SetThreadDescription(GetCurrentThread(), UTF8ToUTF16W(name).data());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else // !MSVC_VER, so must be POSIX threads
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include "common/archives.h"
 | 
			
		||||
#include "common/error.h"
 | 
			
		||||
#include "common/file_util.h"
 | 
			
		||||
#include "common/logging/log.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");
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -97,10 +97,8 @@ struct FrameBufferUpdate {
 | 
			
		||||
static_assert(sizeof(FrameBufferUpdate) == 0x40, "Struct has incorrect size");
 | 
			
		||||
// TODO: Not sure if this padding is correct.
 | 
			
		||||
// Chances are the second block is stored at offset 0x24 rather than 0x20.
 | 
			
		||||
#ifndef _MSC_VER
 | 
			
		||||
static_assert(offsetof(FrameBufferUpdate, framebuffer_info[1]) == 0x20,
 | 
			
		||||
              "FrameBufferInfo element has incorrect alignment");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/// GSP command
 | 
			
		||||
struct Command {
 | 
			
		||||
 
 | 
			
		||||
@@ -64,22 +64,14 @@ private:
 | 
			
		||||
};
 | 
			
		||||
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)                                                  \
 | 
			
		||||
    static_assert(offsetof(Regs, field_name) == position * 4,                                      \
 | 
			
		||||
                  "Field " #field_name " has invalid position")
 | 
			
		||||
 | 
			
		||||
ASSERT_REG_POSITION(color_fill_top, 0x81);
 | 
			
		||||
ASSERT_REG_POSITION(backlight_top, 0x90);
 | 
			
		||||
ASSERT_REG_POSITION(color_fill_bottom, 0x281);
 | 
			
		||||
ASSERT_REG_POSITION(backlight_bottom, 0x290);
 | 
			
		||||
 | 
			
		||||
#undef ASSERT_REG_POSITION
 | 
			
		||||
#endif // !defined(_MSC_VER)
 | 
			
		||||
 | 
			
		||||
extern Regs g_regs;
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user