Header optimizations (#1684)

Shouldn't break anything. I hope.
This commit is contained in:
Ivan 2016-04-27 01:27:24 +03:00
parent da7472fe81
commit aafcf44581
89 changed files with 2370 additions and 2348 deletions

253
Utilities/BitSet.h Normal file
View File

@ -0,0 +1,253 @@
#pragma once
#include "types.h"
// Small bitset for enum class types with available values [0, BitSize).
// T must be either enum type or convertible to (registered with via simple_t<T>).
// Internal representation is single value of type T.
template<typename T, std::size_t BitSize = sizeof(T) * CHAR_BIT>
struct bitset_t
{
using type = simple_t<T>;
using under = std::underlying_type_t<type>;
static constexpr auto bitsize = BitSize;
bitset_t() = default;
constexpr bitset_t(type _enum_const)
: m_value(static_cast<type>(shift(_enum_const)))
{
}
constexpr bitset_t(under raw_value, const std::nothrow_t&)
: m_value(static_cast<T>(raw_value))
{
}
// Get underlying value
constexpr under _value() const
{
return static_cast<under>(m_value);
}
explicit constexpr operator bool() const
{
return _value() ? true : false;
}
bitset_t& operator +=(bitset_t rhs)
{
return *this = { _value() | rhs._value(), std::nothrow };
}
bitset_t& operator -=(bitset_t rhs)
{
return *this = { _value() & ~rhs._value(), std::nothrow };
}
bitset_t& operator &=(bitset_t rhs)
{
return *this = { _value() & rhs._value(), std::nothrow };
}
bitset_t& operator ^=(bitset_t rhs)
{
return *this = { _value() ^ rhs._value(), std::nothrow };
}
friend constexpr bitset_t operator +(bitset_t lhs, bitset_t rhs)
{
return{ lhs._value() | rhs._value(), std::nothrow };
}
friend constexpr bitset_t operator -(bitset_t lhs, bitset_t rhs)
{
return{ lhs._value() & ~rhs._value(), std::nothrow };
}
friend constexpr bitset_t operator &(bitset_t lhs, bitset_t rhs)
{
return{ lhs._value() & rhs._value(), std::nothrow };
}
friend constexpr bitset_t operator ^(bitset_t lhs, bitset_t rhs)
{
return{ lhs._value() ^ rhs._value(), std::nothrow };
}
bool test(bitset_t rhs) const
{
const under v = _value();
const under s = rhs._value();
return (v & s) != 0;
}
bool test_and_set(bitset_t rhs)
{
const under v = _value();
const under s = rhs._value();
*this = { v | s, std::nothrow };
return (v & s) != 0;
}
bool test_and_reset(bitset_t rhs)
{
const under v = _value();
const under s = rhs._value();
*this = { v & ~s, std::nothrow };
return (v & s) != 0;
}
bool test_and_complement(bitset_t rhs)
{
const under v = _value();
const under s = rhs._value();
*this = { v ^ s, std::nothrow };
return (v & s) != 0;
}
private:
static constexpr under shift(const T& value)
{
return static_cast<under>(value) < BitSize ? static_cast<under>(1) << static_cast<under>(value) : throw value;
}
T m_value;
};
template<typename T, typename RT = T>
constexpr RT make_bitset()
{
return RT{};
}
// Fold enum constants into bitset_t<> (must be implemented with constexpr initializer_list constructor instead)
template<typename T = void, typename Arg, typename... Args, typename RT = std::conditional_t<std::is_void<T>::value, bitset_t<Arg>, T>>
constexpr RT make_bitset(Arg&& _enum_const, Args&&... args)
{
return RT{ std::forward<Arg>(_enum_const) } + make_bitset<RT>(std::forward<Args>(args)...);
}
template<typename T, typename CT>
struct atomic_add<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
{
return{ atomic_storage<under>::fetch_or(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto fetch_op = &op1;
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
{
return{ atomic_storage<under>::or_fetch(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T, typename CT>
struct atomic_sub<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
{
return{ atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), ~right._value()), std::nothrow };
}
static constexpr auto fetch_op = &op1;
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
{
return{ atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), ~right._value()), std::nothrow };
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T, typename CT>
struct atomic_and<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
{
return{ atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto fetch_op = &op1;
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
{
return{ atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T, typename CT>
struct atomic_xor<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
{
return{ atomic_storage<under>::fetch_xor(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto fetch_op = &op1;
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
{
return{ atomic_storage<under>::xor_fetch(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T>
struct atomic_test_and_set<bitset_t<T>, T, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
static inline bool _op(bitset_t<T>& left, const T& value)
{
return atomic_storage<under>::bts(reinterpret_cast<under&>(left), static_cast<uint>(value));
}
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_reset<bitset_t<T>, T, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
static inline bool _op(bitset_t<T>& left, const T& value)
{
return atomic_storage<under>::btr(reinterpret_cast<under&>(left), static_cast<uint>(value));
}
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_complement<bitset_t<T>, T, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
static inline bool _op(bitset_t<T>& left, const T& value)
{
return atomic_storage<under>::btc(reinterpret_cast<under&>(left), static_cast<uint>(value));
}
static constexpr auto atomic_op = &_op;
};

View File

@ -296,11 +296,11 @@ namespace cfg
std::string to_string() const override
{
for (const auto& pair : bijective<T, const char*>::map)
for (std::size_t i = 0; i < sizeof(bijective<T, const char*>::map) / sizeof(bijective_pair<T, const char*>); i++)
{
if (pair.first == m_value)
if (bijective<T, const char*>::map[i].v1 == m_value)
{
return pair.second;
return bijective<T, const char*>::map[i].v2;
}
}
@ -309,11 +309,11 @@ namespace cfg
bool from_string(const std::string& value) override
{
for (const auto& pair : bijective<T, const char*>::map)
for (std::size_t i = 0; i < sizeof(bijective<T, const char*>::map) / sizeof(bijective_pair<T, const char*>); i++)
{
if (pair.second == value)
if (bijective<T, const char*>::map[i].v2 == value)
{
m_value = pair.first;
m_value = bijective<T, const char*>::map[i].v1;
return true;
}
}
@ -325,9 +325,9 @@ namespace cfg
{
std::vector<std::string> result;
for (const auto& pair : bijective<T, const char*>::map)
for (std::size_t i = 0; i < sizeof(bijective<T, const char*>::map) / sizeof(bijective_pair<T, const char*>); i++)
{
result.emplace_back(pair.second);
result.emplace_back(bijective<T, const char*>::map[i].v2);
}
return result;

View File

@ -5,6 +5,7 @@
#include <unordered_map>
#include <algorithm>
#include <cerrno>
#ifdef _WIN32
@ -90,6 +91,8 @@ static time_t to_time(const FILETIME& ft)
namespace fs
{
thread_local uint error = 0;
class device_manager final
{
mutable shared_mutex m_mutex;
@ -213,8 +216,8 @@ bool fs::stat(const std::string& path, stat_t& info)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
@ -231,6 +234,7 @@ bool fs::stat(const std::string& path, stat_t& info)
struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0)
{
fs::error = errno;
return false;
}
@ -259,8 +263,8 @@ bool fs::exists(const std::string& path)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
@ -270,7 +274,13 @@ bool fs::exists(const std::string& path)
return true;
#else
struct ::stat file_info;
return !::stat(path.c_str(), &file_info);
if (::stat(path.c_str(), &file_info) != 0)
{
fs::error = errno;
return false;
}
return true;
#endif
}
@ -286,7 +296,7 @@ bool fs::is_file(const std::string& path)
if (info.is_directory)
{
errno = EEXIST;
fs::error = EEXIST;
return false;
}
@ -300,8 +310,8 @@ bool fs::is_file(const std::string& path)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
@ -311,6 +321,7 @@ bool fs::is_file(const std::string& path)
struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0)
{
fs::error = errno;
return false;
}
#endif
@ -322,7 +333,7 @@ bool fs::is_file(const std::string& path)
if (S_ISDIR(file_info.st_mode))
#endif
{
errno = EEXIST;
fs::error = EEXIST;
return false;
}
@ -341,7 +352,7 @@ bool fs::is_dir(const std::string& path)
if (info.is_directory == false)
{
errno = EEXIST;
fs::error = EEXIST;
return false;
}
@ -355,8 +366,8 @@ bool fs::is_dir(const std::string& path)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
@ -366,6 +377,7 @@ bool fs::is_dir(const std::string& path)
struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0)
{
fs::error = errno;
return false;
}
#endif
@ -376,7 +388,7 @@ bool fs::is_dir(const std::string& path)
if (!S_ISDIR(file_info.st_mode))
#endif
{
errno = EEXIST;
fs::error = EEXIST;
return false;
}
@ -396,8 +408,8 @@ bool fs::create_dir(const std::string& path)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_ALREADY_EXISTS: errno = EEXIST; break;
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_ALREADY_EXISTS: fs::error = EEXIST; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
@ -406,7 +418,13 @@ bool fs::create_dir(const std::string& path)
return true;
#else
return !::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
if (::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0)
{
fs::error = errno;
return false;
}
return true;
#endif
}
@ -435,7 +453,7 @@ bool fs::remove_dir(const std::string& path)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
@ -444,7 +462,13 @@ bool fs::remove_dir(const std::string& path)
return true;
#else
return !::rmdir(path.c_str());
if (::rmdir(path.c_str()) != 0)
{
fs::error = errno;
return false;
}
return true;
#endif
}
@ -468,7 +492,7 @@ bool fs::rename(const std::string& from, const std::string& to)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to);
}
@ -477,7 +501,13 @@ bool fs::rename(const std::string& from, const std::string& to)
return true;
#else
return !::rename(from.c_str(), to.c_str());
if (::rename(from.c_str(), to.c_str()) != 0)
{
fs::error = errno;
return false;
}
return true;
#endif
}
@ -496,7 +526,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to);
}
@ -510,6 +540,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
const int input = ::open(from.c_str(), O_RDONLY);
if (input == -1)
{
fs::error = errno;
return false;
}
@ -519,7 +550,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
const int err = errno;
::close(input);
errno = err;
fs::error = err;
return false;
}
@ -538,7 +569,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
::close(input);
::close(output);
errno = err;
fs::error = err;
return false;
}
@ -561,8 +592,8 @@ bool fs::remove_file(const std::string& path)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
@ -571,7 +602,13 @@ bool fs::remove_file(const std::string& path)
return true;
#else
return !::unlink(path.c_str());
if (::unlink(path.c_str()) != 0)
{
fs::error = errno;
return false;
}
return true;
#endif
}
@ -590,8 +627,8 @@ bool fs::truncate_file(const std::string& path, u64 length)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
@ -607,7 +644,7 @@ bool fs::truncate_file(const std::string& path, u64 length)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_NEGATIVE_SEEK: errno = EINVAL; break;
case ERROR_NEGATIVE_SEEK: fs::error = EINVAL; break;
default: throw fmt::exception("Unknown Win32 error: %u (length=0x%llx)." HERE, error, length);
}
@ -618,7 +655,13 @@ bool fs::truncate_file(const std::string& path, u64 length)
CloseHandle(handle);
return true;
#else
return !::truncate(path.c_str(), length);
if (::truncate(path.c_str(), length) != 0)
{
fs::error = errno;
return false;
}
return true;
#endif
}
@ -629,10 +672,10 @@ void fs::file::xnull() const
void fs::file::xfail() const
{
throw fmt::exception("Unexpected fs::file error %d", errno);
throw fmt::exception("Unexpected fs::file error %u", fs::error);
}
bool fs::file::open(const std::string& path, mset<open_mode> mode)
bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
{
if (auto device = get_virtual_device(path))
{
@ -661,7 +704,7 @@ bool fs::file::open(const std::string& path, mset<open_mode> mode)
{
if (mode & fs::excl)
{
errno = EINVAL;
fs::error = EINVAL;
return false;
}
@ -675,9 +718,9 @@ bool fs::file::open(const std::string& path, mset<open_mode> mode)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_FILE_EXISTS: errno = EEXIST; break;
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_FILE_EXISTS: fs::error = EEXIST; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
@ -746,7 +789,7 @@ bool fs::file::open(const std::string& path, mset<open_mode> mode)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_NEGATIVE_SEEK: errno = EINVAL; break;
case ERROR_NEGATIVE_SEEK: fs::error = EINVAL; break;
default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
}
@ -871,6 +914,7 @@ bool fs::file::open(const std::string& path, mset<open_mode> mode)
if (fd == -1)
{
// TODO: errno
fs::error = errno;
return false;
}
@ -1086,8 +1130,8 @@ bool fs::dir::open(const std::string& path)
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
}
@ -1162,6 +1206,7 @@ bool fs::dir::open(const std::string& path)
if (!ptr)
{
// TODO: errno
fs::error = errno;
return false;
}

View File

@ -6,9 +6,13 @@
#include <type_traits>
#include "types.h"
#include "BitSet.h"
namespace fs
{
// Error code returned
extern thread_local uint error;
// File open mode flags
enum struct open_mode : u32
{
@ -20,14 +24,14 @@ namespace fs
excl,
};
constexpr mset<open_mode> read = open_mode::read; // Enable reading
constexpr mset<open_mode> write = open_mode::write; // Enable writing
constexpr mset<open_mode> append = open_mode::append; // Always append to the end of the file
constexpr mset<open_mode> create = open_mode::create; // Create file if it doesn't exist
constexpr mset<open_mode> trunc = open_mode::trunc; // Clear opened file if it's not empty
constexpr mset<open_mode> excl = open_mode::excl; // Failure if the file already exists (used with `create`)
constexpr bitset_t<open_mode> read = open_mode::read; // Enable reading
constexpr bitset_t<open_mode> write = open_mode::write; // Enable writing
constexpr bitset_t<open_mode> append = open_mode::append; // Always append to the end of the file
constexpr bitset_t<open_mode> create = open_mode::create; // Create file if it doesn't exist
constexpr bitset_t<open_mode> trunc = open_mode::trunc; // Clear opened file if it's not empty
constexpr bitset_t<open_mode> excl = open_mode::excl; // Failure if the file already exists (used with `create`)
constexpr mset<open_mode> rewrite = write + create + trunc;
constexpr bitset_t<open_mode> rewrite = write + create + trunc;
// File seek mode
enum class seek_mode : u32
@ -92,7 +96,7 @@ namespace fs
virtual bool remove(const std::string& path) = 0;
virtual bool trunc(const std::string& path, u64 length) = 0;
virtual std::unique_ptr<file_base> open(const std::string& path, mset<open_mode> mode) = 0;
virtual std::unique_ptr<file_base> open(const std::string& path, bitset_t<open_mode> mode) = 0;
virtual std::unique_ptr<dir_base> open_dir(const std::string& path) = 0;
};
@ -150,13 +154,13 @@ namespace fs
file() = default;
// Open file with specified mode
explicit file(const std::string& path, mset<open_mode> mode = ::fs::read)
explicit file(const std::string& path, bitset_t<open_mode> mode = ::fs::read)
{
open(path, mode);
}
// Open file with specified mode
bool open(const std::string& path, mset<open_mode> mode = ::fs::read);
bool open(const std::string& path, bitset_t<open_mode> mode = ::fs::read);
// Open memory for read
explicit file(const void* ptr, std::size_t size);

View File

@ -1,8 +1,53 @@
#include "Log.h"
#include "File.h"
#include "StrFmt.h"
#include <cstdarg>
#include <string>
// Thread-specific log prefix provider
thread_local std::string(*g_tls_log_prefix)() = nullptr;
namespace _log
{
struct listener
{
listener() = default;
virtual ~listener() = default;
virtual void log(const channel& ch, level sev, const std::string& text) = 0;
};
class file_writer
{
// Could be memory-mapped file
fs::file m_file;
public:
file_writer(const std::string& name);
virtual ~file_writer() = default;
// Append raw data
void log(const std::string& text);
// Get current file size (may be used by secondary readers)
std::size_t size() const;
};
struct file_listener : public file_writer, public listener
{
file_listener(const std::string& name)
: file_writer(name)
, listener()
{
}
// Encode level, current thread name, channel name and write log message
virtual void log(const channel& ch, level sev, const std::string& text) override;
};
static file_listener& get_logger()
{
// Use magic static
@ -10,8 +55,6 @@ namespace _log
return logger;
}
file_writer g_tty_file("TTY.log");
channel GENERAL(nullptr, level::notice);
channel LOADER("LDR", level::notice);
channel MEMORY("MEM", level::notice);
@ -20,15 +63,13 @@ namespace _log
channel PPU("PPU", level::notice);
channel SPU("SPU", level::notice);
channel ARMv7("ARMv7");
thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&) = nullptr;
}
void _log::channel::broadcast(const _log::channel& ch, _log::level sev, const char* fmt...)
{
va_list args;
va_start(args, fmt);
get_logger().log(ch, sev, fmt::_vformat(fmt, args));
get_logger().log(ch, sev, fmt::unsafe_vformat(fmt, args));
va_end(args);
}
@ -40,7 +81,7 @@ _log::file_writer::file_writer(const std::string& name)
{
if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append))
{
throw fmt::exception("Can't create log file %s (error %d)", name, errno);
throw fmt::exception("Can't create log file %s (error %d)", name, fs::error);
}
}
catch (...)
@ -78,10 +119,10 @@ void _log::file_listener::log(const _log::channel& ch, _log::level sev, const st
// TODO: print time?
if (auto func = g_tls_make_prefix)
if (auto prefix = g_tls_log_prefix)
{
msg += '{';
msg += func(ch, sev, text);
msg += prefix();
msg += "} ";
}

View File

@ -2,8 +2,6 @@
#include "types.h"
#include "Atomic.h"
#include "File.h"
#include "StrFmt.h"
namespace _log
{
@ -19,10 +17,6 @@ namespace _log
trace, // lowest level (usually disabled)
};
struct channel;
struct listener;
// Log channel
struct channel
{
// Channel prefix (added to every log message)
@ -33,23 +27,20 @@ namespace _log
// Constant initialization: name and initial log level
constexpr channel(const char* name, level enabled = level::trace)
: name{ name }
, enabled{ enabled }
: name(name)
, enabled(enabled)
{
}
// Log without formatting
void log(level sev, const std::string& text) const
{
if (sev <= enabled)
broadcast(*this, sev, "%s", text.c_str());
}
// Log with formatting
// Formatting function
template<typename... Args>
void format(level sev, const char* fmt, const Args&... args) const
{
#ifdef _MSC_VER
if (sev <= enabled)
#else
if (__builtin_expect(sev <= enabled, 0))
#endif
broadcast(*this, sev, fmt, ::unveil<Args>::get(args)...);
}
@ -75,49 +66,7 @@ namespace _log
static void broadcast(const channel& ch, level sev, const char* fmt...);
};
// Log listener (destination)
struct listener
{
listener() = default;
virtual ~listener() = default;
virtual void log(const channel& ch, level sev, const std::string& text) = 0;
};
class file_writer
{
// Could be memory-mapped file
fs::file m_file;
public:
file_writer(const std::string& name);
virtual ~file_writer() = default;
// Append raw data
void log(const std::string& text);
// Get current file size (may be used by secondary readers)
std::size_t size() const;
};
struct file_listener : public file_writer, public listener
{
file_listener(const std::string& name)
: file_writer(name)
, listener()
{
}
// Encode level, current thread name, channel name and write log message
virtual void log(const channel& ch, level sev, const std::string& text) override;
};
// Global variable for TTY.log
extern file_writer g_tty_file;
// Small set of predefined channels:
/* Small set of predefined channels */
extern channel GENERAL;
extern channel LOADER;
@ -127,14 +76,12 @@ namespace _log
extern channel PPU;
extern channel SPU;
extern channel ARMv7;
extern thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&);
}
template<>
struct bijective<_log::level, const char*>
{
static constexpr std::pair<_log::level, const char*> map[]
static constexpr bijective_pair<_log::level, const char*> map[]
{
{ _log::level::always, "Nothing" },
{ _log::level::fatal, "Fatal" },

View File

@ -75,5 +75,6 @@ constexpr std::uint32_t size32(const T(&)[Size])
#define Expects ASSERT
#define Ensures ASSERT
#define DECLARE(static_member) decltype(static_member) static_member
#define DECLARE(...) decltype(__VA_ARGS__) __VA_ARGS__
#define STR_CASE(value) case value: return #value

View File

@ -88,114 +88,6 @@ inline std::uint64_t cntlz64(std::uint64_t arg)
#endif
}
template<typename T>
struct add_flags_result_t
{
T result;
bool carry;
//bool overflow;
bool zero;
bool sign;
add_flags_result_t() = default;
// Straighforward ADD with flags
add_flags_result_t(T a, T b)
: result(a + b)
, carry(result < a)
//, overflow((result ^ ~(a ^ b)) >> (sizeof(T) * 8 - 1) != 0)
, zero(result == 0)
, sign(result >> (sizeof(T) * 8 - 1) != 0)
{
}
// Straighforward ADC with flags
add_flags_result_t(T a, T b, bool c)
: add_flags_result_t(a, b)
{
add_flags_result_t r(result, c);
result = r.result;
carry |= r.carry;
//overflow |= r.overflow;
zero = r.zero;
sign = r.sign;
}
};
inline add_flags_result_t<std::uint32_t> add32_flags(std::uint32_t a, std::uint32_t b)
{
//add_flags_result_t<std::uint32_t> r;
//r.carry = _addcarry_u32(0, a, b, &r.result) != 0;
//r.zero = r.result == 0;
//r.sign = r.result >> 31;
//return r;
return{ a, b };
}
inline add_flags_result_t<std::uint32_t> add32_flags(std::uint32_t a, std::uint32_t b, bool c)
{
return{ a, b, c };
}
inline add_flags_result_t<std::uint64_t> add64_flags(std::uint64_t a, std::uint64_t b)
{
return{ a, b };
}
inline add_flags_result_t<std::uint64_t> add64_flags(std::uint64_t a, std::uint64_t b, bool c)
{
return{ a, b, c };
}
// Compare 16 packed unsigned bytes (greater than)
inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B)
{
// (A xor 0x80) > (B xor 0x80)
const auto sign = _mm_set1_epi32(0x80808080);
return _mm_cmpgt_epi8(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
}
inline __m128i sse_cmpgt_epu16(__m128i A, __m128i B)
{
const auto sign = _mm_set1_epi32(0x80008000);
return _mm_cmpgt_epi16(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
}
inline __m128i sse_cmpgt_epu32(__m128i A, __m128i B)
{
const auto sign = _mm_set1_epi32(0x80000000);
return _mm_cmpgt_epi32(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
}
inline __m128 sse_exp2_ps(__m128 A)
{
const auto x0 = _mm_max_ps(_mm_min_ps(A, _mm_set1_ps(127.4999961f)), _mm_set1_ps(-127.4999961f));
const auto x1 = _mm_add_ps(x0, _mm_set1_ps(0.5f));
const auto x2 = _mm_sub_epi32(_mm_cvtps_epi32(x1), _mm_and_si128(_mm_castps_si128(_mm_cmpnlt_ps(_mm_setzero_ps(), x1)), _mm_set1_epi32(1)));
const auto x3 = _mm_sub_ps(x0, _mm_cvtepi32_ps(x2));
const auto x4 = _mm_mul_ps(x3, x3);
const auto x5 = _mm_mul_ps(x3, _mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(x4, _mm_set1_ps(0.023093347705f)), _mm_set1_ps(20.20206567f)), x4), _mm_set1_ps(1513.906801f)));
const auto x6 = _mm_mul_ps(x5, _mm_rcp_ps(_mm_sub_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(233.1842117f), x4), _mm_set1_ps(4368.211667f)), x5)));
return _mm_mul_ps(_mm_add_ps(_mm_add_ps(x6, x6), _mm_set1_ps(1.0f)), _mm_castsi128_ps(_mm_slli_epi32(_mm_add_epi32(x2, _mm_set1_epi32(127)), 23)));
}
inline __m128 sse_log2_ps(__m128 A)
{
const auto _1 = _mm_set1_ps(1.0f);
const auto _c = _mm_set1_ps(1.442695040f);
const auto x0 = _mm_max_ps(A, _mm_castsi128_ps(_mm_set1_epi32(0x00800000)));
const auto x1 = _mm_or_ps(_mm_and_ps(x0, _mm_castsi128_ps(_mm_set1_epi32(0x807fffff))), _1);
const auto x2 = _mm_rcp_ps(_mm_add_ps(x1, _1));
const auto x3 = _mm_mul_ps(_mm_sub_ps(x1, _1), x2);
const auto x4 = _mm_add_ps(x3, x3);
const auto x5 = _mm_mul_ps(x4, x4);
const auto x6 = _mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(-0.7895802789f), x5), _mm_set1_ps(16.38666457f)), x5), _mm_set1_ps(-64.1409953f));
const auto x7 = _mm_rcp_ps(_mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(-35.67227983f), x5), _mm_set1_ps(312.0937664f)), x5), _mm_set1_ps(-769.6919436f)));
const auto x8 = _mm_cvtepi32_ps(_mm_sub_epi32(_mm_srli_epi32(_mm_castps_si128(x0), 23), _mm_set1_epi32(127)));
return _mm_add_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(x5, x6), x7), x4), _c), _mm_add_ps(_mm_mul_ps(x4, _c), x8));
}
// Helper function, used by ""_u16, ""_u32, ""_u64
constexpr std::uint8_t to_u8(char c)
{

View File

@ -1,120 +1,90 @@
#include "stdafx.h"
#include "Utilities/Semaphore.h"
bool semaphore_t::try_wait()
#include <mutex>
#include <condition_variable>
struct benaphore::internal
{
// check m_value without interlocked op
if (m_var.load().value == 0)
{
return false;
}
std::mutex mutex;
// try to decrement m_value atomically
const auto old = m_var.fetch_op([](sync_var_t& var)
{
if (var.value)
{
var.value--;
}
});
std::size_t acq_order{};
std::size_t rel_order{};
// recheck atomic result
if (old.value == 0)
{
return false;
}
std::condition_variable cond;
};
return true;
}
bool semaphore_t::try_post()
void benaphore::wait_hard()
{
// check m_value without interlocked op
if (m_var.load().value >= max_value)
{
return false;
}
// try to increment m_value atomically
const auto old = m_var.fetch_op([&](sync_var_t& var)
{
if (var.value < max_value)
{
var.value++;
}
});
// recheck atomic result
if (old.value >= max_value)
{
return false;
}
if (old.waiters)
{
// notify waiting thread
std::lock_guard<std::mutex> lock(m_mutex);
m_cv.notify_one();
}
return true;
}
void semaphore_t::wait()
{
if (m_var.atomic_op([](sync_var_t& var) -> bool
{
if (var.value)
{
var.value--;
return true;
}
else
{
//var.waiters++;
return false;
}
}))
initialize_once();
std::unique_lock<std::mutex> lock(m_data->mutex);
// Notify non-zero waiter queue size
if (m_value.exchange(-1) == 1)
{
// Return immediately (acquired)
m_value = 0;
return;
}
std::unique_lock<std::mutex> lock(m_mutex);
// Remember the order
const std::size_t order = ++m_data->acq_order;
m_var.atomic_op([](sync_var_t& var)
// Wait for the appropriate rel_order (TODO)
while (m_data->rel_order < order)
{
var.waiters++;
});
m_data->cond.wait(lock);
}
while (!m_var.atomic_op([](sync_var_t& var) -> bool
if (order == m_data->acq_order && m_data->acq_order == m_data->rel_order)
{
if (var.value)
{
var.value--;
var.waiters--;
return true;
}
else
{
return false;
}
}))
{
m_cv.wait(lock);
// Cleaup
m_data->acq_order = 0;
m_data->rel_order = 0;
m_value.compare_and_swap(-1, 0);
}
}
bool semaphore_t::post_and_wait()
void benaphore::post_hard()
{
// TODO: merge these functions? Probably has a race condition.
if (try_wait()) return false;
initialize_once();
try_post();
wait();
std::unique_lock<std::mutex> lock(m_data->mutex);
return true;
if (m_value.compare_and_swap(0, 1) != -1)
{
// Do nothing (released)
return;
}
if (m_data->acq_order == m_data->rel_order)
{
m_value = 1;
return;
}
// Awake one thread
m_data->rel_order += 1;
// Unlock and notify
lock.unlock();
m_data->cond.notify_one();
}
void benaphore::initialize_once()
{
if (UNLIKELY(!m_data))
{
auto ptr = new benaphore::internal;
if (!m_data.compare_and_swap_test(nullptr, ptr))
{
delete ptr;
}
}
}
benaphore::~benaphore()
{
delete m_data;
}

View File

@ -2,39 +2,47 @@
#include "types.h"
#include "Atomic.h"
#include "Platform.h"
class semaphore_t
// Binary semaphore
class benaphore
{
// semaphore mutex
std::mutex m_mutex;
struct internal;
// semaphore condition variable
std::condition_variable m_cv;
// Reserved value (-1) enforces *_hard() calls
atomic_t<u32> m_value{};
struct alignas(8) sync_var_t
{
u32 value; // current semaphore value
u32 waiters; // current amount of waiters
};
atomic_t<internal*> m_data{};
// current semaphore value
atomic_t<sync_var_t> m_var;
void wait_hard();
void post_hard();
public:
// max semaphore value
const u32 max_value;
constexpr benaphore() = default;
semaphore_t(u32 max_value = 1, u32 value = 0)
: m_var(sync_var_t{ value, 0 })
, max_value(max_value)
~benaphore();
// Initialize internal data
void initialize_once();
void wait()
{
if (UNLIKELY(!m_value.compare_and_swap_test(1, 0)))
{
wait_hard();
}
}
bool try_wait();
bool try_wait()
{
return LIKELY(m_value.compare_and_swap_test(1, 0));
}
bool try_post();
void wait();
bool post_and_wait();
void post()
{
if (UNLIKELY(!m_value.compare_and_swap_test(0, 1)))
{
post_hard();
}
}
};

View File

@ -15,24 +15,6 @@ struct shared_mutex::internal
std::condition_variable ocv; // For current exclusive owner
};
shared_mutex::~shared_mutex()
{
delete m_data;
}
void shared_mutex::initialize_once()
{
if (!m_data)
{
auto ptr = new shared_mutex::internal;
if (!m_data.compare_and_swap_test(nullptr, ptr))
{
delete ptr;
}
}
}
void shared_mutex::lock_shared_hard()
{
initialize_once();
@ -81,17 +63,18 @@ void shared_mutex::unlock_shared_notify()
{
initialize_once();
// Mutex is locked for reliable notification because m_ctrl has been changed outside
std::lock_guard<std::mutex> lock(m_data->mutex);
std::unique_lock<std::mutex> lock(m_data->mutex);
if ((m_ctrl & SM_READER_MASK) == 0 && m_data->wq_size)
{
// Notify exclusive owner
lock.unlock();
m_data->ocv.notify_one();
}
else if (m_data->rq_size)
{
// Notify other readers
lock.unlock();
m_data->rcv.notify_one();
}
}
@ -141,17 +124,36 @@ void shared_mutex::unlock_notify()
{
initialize_once();
// Mutex is locked for reliable notification because m_ctrl has been changed outside
std::lock_guard<std::mutex> lock(m_data->mutex);
std::unique_lock<std::mutex> lock(m_data->mutex);
if (m_data->wq_size)
{
// Notify next exclusive owner
lock.unlock();
m_data->wcv.notify_one();
}
else if (m_data->rq_size)
{
// Notify all readers
lock.unlock();
m_data->rcv.notify_all();
}
}
void shared_mutex::initialize_once()
{
if (UNLIKELY(!m_data))
{
auto ptr = new shared_mutex::internal;
if (!m_data.compare_and_swap_test(nullptr, ptr))
{
delete ptr;
}
}
}
shared_mutex::~shared_mutex()
{
delete m_data;
}

View File

@ -35,11 +35,11 @@ class shared_mutex final
public:
constexpr shared_mutex() = default;
~shared_mutex();
// Initialize internal data
void initialize_once();
~shared_mutex();
bool try_lock_shared()
{
auto ctrl = m_ctrl.load();

View File

@ -1,5 +1,6 @@
#include "StrFmt.h"
#include "BEType.h"
#include "StrUtil.h"
#include <cassert>
#include <array>
@ -15,70 +16,7 @@ std::string v128::to_xyzw() const
return fmt::format("x: %g y: %g z: %g w: %g", _f[3], _f[2], _f[1], _f[0]);
}
std::string fmt::to_hex(u64 value, u64 count)
{
if (count - 1 >= 16)
{
throw exception("fmt::to_hex(): invalid count: 0x%llx", count);
}
count = std::max<u64>(count, 16 - cntlz64(value) / 4);
char res[16] = {};
for (size_t i = count - 1; ~i; i--, value /= 16)
{
res[i] = "0123456789abcdef"[value % 16];
}
return std::string(res, count);
}
std::string fmt::to_udec(u64 value)
{
char res[20] = {};
size_t first = sizeof(res);
if (!value)
{
res[--first] = '0';
}
for (; value; value /= 10)
{
res[--first] = '0' + (value % 10);
}
return std::string(&res[first], sizeof(res) - first);
}
std::string fmt::to_sdec(s64 svalue)
{
const bool sign = svalue < 0;
u64 value = sign ? -svalue : svalue;
char res[20] = {};
size_t first = sizeof(res);
if (!value)
{
res[--first] = '0';
}
for (; value; value /= 10)
{
res[--first] = '0' + (value % 10);
}
if (sign)
{
res[--first] = '-';
}
return std::string(&res[first], sizeof(res) - first);
}
std::string fmt::_vformat(const char* fmt, va_list _args) noexcept
std::string fmt::unsafe_vformat(const char* fmt, va_list _args) noexcept
{
// Fixed stack buffer for the first attempt
std::array<char, 4096> fixed_buf;
@ -115,18 +53,18 @@ std::string fmt::_vformat(const char* fmt, va_list _args) noexcept
}
}
std::string fmt::_format(const char* fmt...) noexcept
std::string fmt::unsafe_format(const char* fmt...) noexcept
{
va_list args;
va_start(args, fmt);
auto result = fmt::_vformat(fmt, args);
auto result = unsafe_vformat(fmt, args);
va_end(args);
return result;
}
fmt::exception_base::exception_base(const char* fmt...)
: std::runtime_error((va_start(m_args, fmt), _vformat(fmt, m_args)))
: std::runtime_error((va_start(m_args, fmt), unsafe_vformat(fmt, m_args)))
{
va_end(m_args);
}
@ -196,73 +134,11 @@ std::string fmt::trim(const std::string& source, const std::string& values)
return source.substr(begin, source.find_last_not_of(values) + 1);
}
std::string fmt::escape(const std::string& source, std::initializer_list<char> more)
{
const std::pair<std::string, std::string> escape_list[] =
{
{ "\\", "\\\\" },
{ "\a", "\\a" },
{ "\b", "\\b" },
{ "\f", "\\f" },
{ "\n", "\\n" },
{ "\r", "\\r" },
{ "\t", "\\t" },
{ "\v", "\\v" },
};
std::string result = fmt::replace_all(source, escape_list);
for (char c = 0; c < 32; c++)
{
result = fmt::replace_all(result, std::string(1, c), fmt::format("\\x%02X", c));
}
for (char c : more)
{
result = fmt::replace_all(result, std::string(1, c), fmt::format("\\x%02X", c));
}
return result;
}
std::string fmt::unescape(const std::string& source)
std::string fmt::to_upper(const std::string& string)
{
std::string result;
for (auto it = source.begin(); it != source.end();)
{
const char bs = *it++;
if (bs == '\\' && it != source.end())
{
switch (const char code = *it++)
{
case 'a': result += '\a'; break;
case 'b': result += '\b'; break;
case 'f': result += '\f'; break;
case 'n': result += '\n'; break;
case 'r': result += '\r'; break;
case 't': result += '\t'; break;
case 'v': result += '\v'; break;
case 'x':
{
// Detect hexadecimal character code (TODO)
if (source.end() - it >= 2)
{
result += std::stoi(std::string{ *it++, *it++ }, 0, 16);
}
}
// Octal/unicode not supported
default: result += code;
}
}
else
{
result += bs;
}
}
result.resize(string.size());
std::transform(string.begin(), string.end(), result.begin(), ::toupper);
return result;
}

View File

@ -2,114 +2,21 @@
#include <cstdarg>
#include <string>
#include <vector>
#include <functional>
#include <exception>
#include "Platform.h"
#include "types.h"
// Copy null-terminated string from std::string to char array with truncation
template<std::size_t N>
force_inline void strcpy_trunc(char(&dst)[N], const std::string& src)
{
const std::size_t count = src.size() >= N ? N - 1 : src.size();
std::memcpy(dst, src.c_str(), count);
dst[count] = '\0';
}
// Copy null-terminated string from char array to another char array with truncation
template<std::size_t N, std::size_t N2>
force_inline void strcpy_trunc(char(&dst)[N], const char(&src)[N2])
{
const std::size_t count = N2 >= N ? N - 1 : N2;
std::memcpy(dst, src, count);
dst[count] = '\0';
}
// Formatting helper, type-specific preprocessing for improving safety and functionality
template<typename T, typename>
struct unveil
{
// TODO
static inline const T& get(const T& arg)
{
return arg;
}
};
template<>
struct unveil<std::string, void>
{
static inline const char* get(const std::string& arg)
{
return arg.c_str();
}
};
namespace fmt
{
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
std::string replace_all(const std::string &src, const std::string& from, const std::string& to);
std::string unsafe_format(const char* fmt...) noexcept;
std::string unsafe_vformat(const char*, va_list) noexcept;
template<size_t list_size>
std::string replace_all(std::string src, const std::pair<std::string, std::string>(&list)[list_size])
{
for (size_t pos = 0; pos < src.length(); ++pos)
{
for (size_t i = 0; i < list_size; ++i)
{
const size_t comp_length = list[i].first.length();
if (src.length() - pos < comp_length)
continue;
if (src.substr(pos, comp_length) == list[i].first)
{
src = (pos ? src.substr(0, pos) + list[i].second : list[i].second) + src.substr(pos + comp_length);
pos += list[i].second.length() - 1;
break;
}
}
}
return src;
}
template<size_t list_size>
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>>(&list)[list_size])
{
for (size_t pos = 0; pos < src.length(); ++pos)
{
for (size_t i = 0; i < list_size; ++i)
{
const size_t comp_length = list[i].first.length();
if (src.length() - pos < comp_length)
continue;
if (src.substr(pos, comp_length) == list[i].first)
{
src = (pos ? src.substr(0, pos) + list[i].second() : list[i].second()) + src.substr(pos + comp_length);
pos += list[i].second().length() - 1;
break;
}
}
}
return src;
}
std::string to_hex(u64 value, u64 count = 1);
std::string to_udec(u64 value);
std::string to_sdec(s64 value);
std::string _format(const char* fmt...) noexcept;
std::string _vformat(const char*, va_list) noexcept;
// Formatting function with special functionality (fmt::unveil)
// Formatting function
template<typename... Args>
force_inline std::string format(const char* fmt, const Args&... args) noexcept
inline std::string format(const char* fmt, const Args&... args) noexcept
{
return _format(fmt, ::unveil<Args>::get(args)...);
return unsafe_format(fmt, ::unveil<Args>::get(args)...);
}
// Helper class
@ -143,86 +50,4 @@ namespace fmt
if (static_cast<From>(result) != value) throw fmt::exception(format_str, value, args...);
return result;
}
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
std::string trim(const std::string& source, const std::string& values = " \t");
template<typename T>
std::string merge(const T& source, const std::string& separator)
{
if (!source.size())
{
return{};
}
std::string result;
auto it = source.begin();
auto end = source.end();
for (--end; it != end; ++it)
{
result += *it + separator;
}
return result + source.back();
}
template<typename T>
std::string merge(std::initializer_list<T> sources, const std::string& separator)
{
if (!sources.size())
{
return{};
}
std::string result;
bool first = true;
for (auto &v : sources)
{
if (first)
{
result = fmt::merge(v, separator);
first = false;
}
else
{
result += separator + fmt::merge(v, separator);
}
}
return result;
}
template<typename IT>
std::string to_lower(IT _begin, IT _end)
{
std::string result; result.resize(_end - _begin);
std::transform(_begin, _end, result.begin(), ::tolower);
return result;
}
template<typename T>
std::string to_lower(const T& string)
{
return to_lower(std::begin(string), std::end(string));
}
template<typename IT>
std::string to_upper(IT _begin, IT _end)
{
std::string result; result.resize(_end - _begin);
std::transform(_begin, _end, result.begin(), ::toupper);
return result;
}
template<typename T>
std::string to_upper(const T& string)
{
return to_upper(std::begin(string), std::end(string));
}
std::string escape(const std::string& source, std::initializer_list<char> more = {});
std::string unescape(const std::string& source);
bool match(const std::string &source, const std::string &mask);
}

133
Utilities/StrUtil.h Normal file
View File

@ -0,0 +1,133 @@
#pragma once
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <functional>
// Copy null-terminated string from std::string to char array with truncation
template<std::size_t N>
inline void strcpy_trunc(char(&dst)[N], const std::string& src)
{
const std::size_t count = src.size() >= N ? N - 1 : src.size();
std::memcpy(dst, src.c_str(), count);
dst[count] = '\0';
}
// Copy null-terminated string from char array to another char array with truncation
template<std::size_t N, std::size_t N2>
inline void strcpy_trunc(char(&dst)[N], const char(&src)[N2])
{
const std::size_t count = N2 >= N ? N - 1 : N2;
std::memcpy(dst, src, count);
dst[count] = '\0';
}
namespace fmt
{
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
std::string replace_all(const std::string &src, const std::string& from, const std::string& to);
template<size_t list_size>
std::string replace_all(std::string src, const std::pair<std::string, std::string>(&list)[list_size])
{
for (size_t pos = 0; pos < src.length(); ++pos)
{
for (size_t i = 0; i < list_size; ++i)
{
const size_t comp_length = list[i].first.length();
if (src.length() - pos < comp_length)
continue;
if (src.substr(pos, comp_length) == list[i].first)
{
src = (pos ? src.substr(0, pos) + list[i].second : list[i].second) + src.substr(pos + comp_length);
pos += list[i].second.length() - 1;
break;
}
}
}
return src;
}
template<size_t list_size>
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>>(&list)[list_size])
{
for (size_t pos = 0; pos < src.length(); ++pos)
{
for (size_t i = 0; i < list_size; ++i)
{
const size_t comp_length = list[i].first.length();
if (src.length() - pos < comp_length)
continue;
if (src.substr(pos, comp_length) == list[i].first)
{
src = (pos ? src.substr(0, pos) + list[i].second() : list[i].second()) + src.substr(pos + comp_length);
pos += list[i].second().length() - 1;
break;
}
}
}
return src;
}
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
std::string trim(const std::string& source, const std::string& values = " \t");
template<typename T>
std::string merge(const T& source, const std::string& separator)
{
if (!source.size())
{
return{};
}
std::string result;
auto it = source.begin();
auto end = source.end();
for (--end; it != end; ++it)
{
result += *it + separator;
}
return result + source.back();
}
template<typename T>
std::string merge(std::initializer_list<T> sources, const std::string& separator)
{
if (!sources.size())
{
return{};
}
std::string result;
bool first = true;
for (auto &v : sources)
{
if (first)
{
result = fmt::merge(v, separator);
first = false;
}
else
{
result += separator + fmt::merge(v, separator);
}
}
return result;
}
std::string to_upper(const std::string& string);
bool match(const std::string &source, const std::string &mask);
}

View File

@ -1294,11 +1294,20 @@ extern std::mutex& get_current_thread_mutex()
// TODO
extern atomic_t<u32> g_thread_count(0);
extern thread_local std::string(*g_tls_log_prefix)();
void thread_ctrl::initialize()
{
// Initialize TLS variable
g_tls_this_thread = this;
g_tls_log_prefix = []
{
return g_tls_this_thread->m_name;
};
++g_thread_count;
#if defined(_MSC_VER)
struct THREADNAME_INFO
@ -1328,13 +1337,6 @@ void thread_ctrl::initialize()
}
#endif
_log::g_tls_make_prefix = [](const auto&, auto, const auto&)
{
return g_tls_this_thread->m_name;
};
++g_thread_count;
}
void thread_ctrl::set_exception() noexcept
@ -1378,7 +1380,7 @@ thread_ctrl::~thread_ctrl()
void thread_ctrl::initialize_once() const
{
if (!m_data)
if (UNLIKELY(!m_data))
{
auto ptr = new thread_ctrl::internal;
@ -1391,10 +1393,10 @@ void thread_ctrl::initialize_once() const
void thread_ctrl::join()
{
if (m_thread.joinable())
if (LIKELY(m_thread.joinable()))
{
// Increase contention counter
if (m_joining++)
if (UNLIKELY(m_joining++))
{
// Hard way
initialize_once();
@ -1408,7 +1410,7 @@ void thread_ctrl::join()
m_thread.join();
// Notify others if necessary
if (m_joining > 1)
if (UNLIKELY(m_joining > 1))
{
initialize_once();
@ -1420,7 +1422,7 @@ void thread_ctrl::join()
}
}
if (m_data && m_data->exception)
if (UNLIKELY(m_data && m_data->exception))
{
std::rethrow_exception(m_data->exception);
}

1037
Utilities/geometry.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -106,10 +106,10 @@ static std::string fmt_shift(u32 type, u32 amount)
{
switch (type)
{
case arm_code::SRType_LSL: return ",lsl #" + fmt::to_udec(amount);
case arm_code::SRType_LSR: return ",lsr #" + fmt::to_udec(amount);
case arm_code::SRType_ASR: return ",asr #" + fmt::to_udec(amount);
case arm_code::SRType_ROR: return ",ror #" + fmt::to_udec(amount);
case arm_code::SRType_LSL: return fmt::format(",lsl #%u", amount);
case arm_code::SRType_LSR: return fmt::format(",lsr #%u", amount);
case arm_code::SRType_ASR: return fmt::format(",asr #%u", amount);
case arm_code::SRType_ROR: return fmt::format(",ror #%u", amount);
case arm_code::SRType_RRX: return ",rrx";
default: return ",?????";
}

View File

@ -57,3 +57,23 @@ s32 arm_error_code::report(s32 error, const char* text)
LOG_ERROR(ARMv7, "Illegal call to ppu_report_error(0x%x, '%s')!");
return error;
}
std::vector<arm_function_t>& arm_function_manager::access()
{
static std::vector<arm_function_t> list
{
nullptr,
[](ARMv7Thread& cpu) { cpu.state += cpu_state::ret; },
};
return list;
}
u32 arm_function_manager::add_function(arm_function_t function)
{
auto& list = access();
list.push_back(function);
return ::size32(list) - 1;
}

View File

@ -439,25 +439,9 @@ class arm_function_manager
};
// Access global function list
static never_inline auto& access()
{
static std::vector<arm_function_t> list
{
nullptr,
[](ARMv7Thread& cpu) { cpu.state += cpu_state::ret; },
};
static std::vector<arm_function_t>& access();
return list;
}
static never_inline u32 add_function(arm_function_t function)
{
auto& list = access();
list.push_back(function);
return ::size32(list) - 1;
}
static u32 add_function(arm_function_t function);
public:
// Register function (shall only be called during global initialization)

View File

@ -57,6 +57,35 @@ arm_static_module::arm_static_module(const char* name)
arm_module_manager::register_module(this);
}
std::unordered_map<std::string, arm_static_module*>& arm_module_manager::access()
{
static std::unordered_map<std::string, arm_static_module*> map;
return map;
}
void arm_module_manager::register_module(arm_static_module* module)
{
access().emplace(module->name, module);
}
arm_static_function& arm_module_manager::access_static_function(const char* module, u32 fnid)
{
return access().at(module)->functions[fnid];
}
arm_static_variable& arm_module_manager::access_static_variable(const char* module, u32 vnid)
{
return access().at(module)->variables[vnid];
}
const arm_static_module* arm_module_manager::get_module(const std::string& name)
{
const auto& map = access();
const auto found = map.find(name);
return found != map.end() ? found->second : nullptr;
}
static void arm_initialize_modules()
{
const std::initializer_list<const arm_static_module*> registered

View File

@ -57,35 +57,16 @@ class arm_module_manager final
{
friend class arm_static_module;
static never_inline auto& access()
{
static std::unordered_map<std::string, arm_static_module*> map;
static std::unordered_map<std::string, arm_static_module*>& access();
return map;
}
static void register_module(arm_static_module* module);
static never_inline void register_module(arm_static_module* module)
{
access().emplace(module->name, module);
}
static arm_static_function& access_static_function(const char* module, u32 fnid);
static never_inline auto& access_static_function(const char* module, u32 fnid)
{
return access().at(module)->functions[fnid];
}
static never_inline auto& access_static_variable(const char* module, u32 vnid)
{
return access().at(module)->variables[vnid];
}
static arm_static_variable& access_static_variable(const char* module, u32 vnid);
public:
static never_inline const arm_static_module* get_module(const std::string& name)
{
const auto& map = access();
const auto found = map.find(name);
return found != map.end() ? found->second : nullptr;
}
static const arm_static_module* get_module(const std::string& name);
template<typename T, T Func>
static void register_static_function(const char* module, const char* name, arm_function_t func, u32 fnid, u32 flags)

View File

@ -122,6 +122,8 @@ void ARMv7Thread::cpu_init()
TLS = armv7_get_tls(id);
}
extern thread_local std::string(*g_tls_log_prefix)();
void ARMv7Thread::cpu_task()
{
if (custom_task)
@ -131,7 +133,7 @@ void ARMv7Thread::cpu_task()
return custom_task(*this);
}
_log::g_tls_make_prefix = [](const auto&, auto, const auto&)
g_tls_log_prefix = []
{
const auto cpu = static_cast<ARMv7Thread*>(get_current_cpu_thread());

View File

@ -5,6 +5,8 @@
#include "sceLibKernel.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(sceLibKernel);
extern u64 get_system_time();

View File

@ -8,6 +8,8 @@
LOG_CHANNEL(sceLibc);
extern fs::file g_tty;
// TODO
vm::ptr<void> g_dso;
@ -95,7 +97,7 @@ std::string arm_fmt(ARMv7Thread& cpu, vm::cptr<char> fmt, u32 g_count)
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
result += fmt::to_sdec(value);
result += fmt::format("%lld", value);
continue;
}
case 'x':
@ -111,7 +113,7 @@ std::string arm_fmt(ARMv7Thread& cpu, vm::cptr<char> fmt, u32 g_count)
result += cf == 'x' ? "0x" : "0X";
}
const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::to_upper(fmt::to_hex(value));
const std::string& hex = fmt::format(cf == 'x' ? "%llx" : "%llX", value);
if (hex.length() >= width)
{
@ -211,7 +213,10 @@ namespace sce_libc_func
const std::string& result = arm_fmt(cpu, fmt, va_args.count);
sceLibc.trace("*** -> '%s'", result);
_log::g_tty_file.log(result);
if (g_tty)
{
g_tty.write(result);
}
}
void sprintf(ARMv7Thread& cpu, vm::ptr<char> str, vm::cptr<char> fmt, arm_va_args_t va_args)

View File

@ -1,5 +1,6 @@
#ifdef _WIN32
#include "Utilities/Log.h"
#include "Utilities/StrFmt.h"
#include "Utilities/Config.h"
#include "Emu/System.h"

View File

@ -108,7 +108,7 @@ bool cpu_thread::check_status()
const auto state_ = state.load();
if (state_ & to_mset(cpu_state::ret, cpu_state::stop))
if (state_ & make_bitset(cpu_state::ret, cpu_state::stop))
{
return true;
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "Utilities/Thread.h"
#include "Utilities/BitSet.h"
// CPU Thread Type
enum class cpu_type : u32
@ -27,7 +28,7 @@ enum struct cpu_state : u32
};
// CPU Thread State flags: pause state union
constexpr mset<cpu_state> cpu_state_pause = to_mset(cpu_state::suspend, cpu_state::dbg_global_pause, cpu_state::dbg_pause);
constexpr bitset_t<cpu_state> cpu_state_pause = make_bitset(cpu_state::suspend, cpu_state::dbg_global_pause, cpu_state::dbg_pause);
class cpu_thread : public named_thread
{
@ -38,13 +39,14 @@ public:
virtual ~cpu_thread() override;
const std::string name;
const u32 id = -1;
const cpu_type type;
const id_value<> id{};
cpu_thread(cpu_type type, const std::string& name);
// Public thread state
atomic_t<mset<cpu_state>> state{ cpu_state::stop };
atomic_t<bitset_t<cpu_state>> state{ cpu_state::stop };
// Recursively enter sleep state
void sleep()

View File

@ -440,7 +440,7 @@ public:
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec);
Demuxer* dmux;
const u32 id{};
const id_value<> id{};
const u32 memAddr;
const u32 memSize;
const u32 fidMajor;

View File

@ -6,6 +6,8 @@
#include "Emu/Cell/lv2/sys_fs.h"
#include "cellFs.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(cellFs);
s32 cellFsOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<void> arg, u64 size)

View File

@ -8,6 +8,7 @@
#include "cellGame.h"
#include "Loader/PSF.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(cellGame);

View File

@ -1,5 +1,7 @@
#pragma once
#include "Utilities/BitField.h"
namespace vm { using namespace ps3; }
enum

View File

@ -5,6 +5,8 @@
#include "cellSysutil.h"
#include "cellNetCtl.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(cellNetCtl);
cfg::map_entry<s32> g_cfg_net_status(cfg::root.net, "Connection status",

View File

@ -5,6 +5,7 @@
#include "cellSaveData.h"
#include "Loader/PSF.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(cellSaveData);

View File

@ -1,5 +1,7 @@
#pragma once
#include "Utilities/BitField.h"
namespace vm { using namespace ps3; }
// Return Codes
@ -374,23 +376,6 @@ struct alignas(128) CellSyncLFQueue
vm::bptr<void, u64> m_eaSignal; // 0x70
be_t<u32> m_v2; // 0x78
be_t<u32> m_eq_id; // 0x7C
std::string dump()
{
std::string res = "CellSyncLFQueue dump:";
auto data = (be_t<u64>*)this;
for (u32 i = 0; i < sizeof(CellSyncLFQueue) / sizeof(u64); i += 2)
{
res += "\n*** 0x";
res += fmt::to_hex(data[i + 0], 16);
res += " 0x";
res += fmt::to_hex(data[i + 1], 16);
}
return res;
}
};
CHECK_SIZE_ALIGN(CellSyncLFQueue, 128, 128);

View File

@ -4,6 +4,8 @@
#include "cellSync2.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(cellSync2);
vm::gvar<CellSync2CallerThreadType> gCellSync2CallerThreadTypePpuThread;

View File

@ -5,6 +5,8 @@
#include "cellSysutil.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(cellSysutil);
// Temporarily

View File

@ -4,6 +4,8 @@
#include "cellUserInfo.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(cellUserInfo);
s32 cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)

View File

@ -24,7 +24,7 @@ cfg::map_entry<u8> g_cfg_video_out_aspect_ratio(cfg::root.video, "Aspect ratio",
{ "16x9", CELL_VIDEO_OUT_ASPECT_16_9 },
});
const extern std::unordered_map<u8, size2i> g_video_out_resolution_map
const extern std::unordered_map<u8, std::pair<int, int>> g_video_out_resolution_map
{
{ CELL_VIDEO_OUT_RESOLUTION_1080, { 1920, 1080 } },
{ CELL_VIDEO_OUT_RESOLUTION_720, { 1280, 720 } },
@ -133,7 +133,7 @@ ppu_error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptr<CellVideoOutCo
config->resolutionId = g_cfg_video_out_resolution.get();
config->format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8;
config->aspect = g_cfg_video_out_aspect_ratio.get();
config->pitch = 4 * g_video_out_resolution_map.at(g_cfg_video_out_resolution.get()).width;
config->pitch = 4 * g_video_out_resolution_map.at(g_cfg_video_out_resolution.get()).first;
return CELL_OK;

View File

@ -10,11 +10,13 @@
#include "sceNp.h"
#include "sceNpTrophy.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(sceNpTrophy);
struct trophy_context_t
{
const u32 id{};
const id_value<> id{};
std::string trp_name;
fs::file trp_stream;
@ -23,7 +25,7 @@ struct trophy_context_t
struct trophy_handle_t
{
const u32 id{};
const id_value<> id{};
};
// Functions

View File

@ -10,6 +10,8 @@ LOG_CHANNEL(sysPrxForUser);
extern u64 get_system_time();
extern fs::file g_tty;
vm::gvar<s32> sys_prx_version; // ???
#define TLS_SYS 0x30
@ -163,7 +165,10 @@ s32 console_write(vm::ptr<char> data, u32 len)
{
sysPrxForUser.warning("console_write(data=*0x%x, len=%d)", data, len);
_log::g_tty_file.log({ data.get_ptr(), len });
if (g_tty)
{
g_tty.write(data.get_ptr(), len);
}
return CELL_OK;
}

View File

@ -3,6 +3,8 @@
extern _log::channel sysPrxForUser;
extern fs::file g_tty;
// TODO
static std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count)
{
@ -83,7 +85,7 @@ static std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count)
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
result += fmt::to_sdec(value);
result += fmt::format("%lld", value);
continue;
}
case 'x':
@ -99,7 +101,7 @@ static std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count)
result += cf == 'x' ? "0x" : "0X";
}
const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::to_upper(fmt::to_hex(value));
const std::string& hex = fmt::format(cf == 'x' ? "%llx" : "%llX", value);
if (hex.length() >= width)
{
@ -132,7 +134,7 @@ static std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count)
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
result += fmt::to_udec(value);
result += fmt::format("%llu", value);
continue;
}
}
@ -336,7 +338,10 @@ s32 _sys_printf(PPUThread& ppu, vm::cptr<char> fmt, ppu_va_args_t va_args)
{
sysPrxForUser.warning("_sys_printf(fmt=*0x%x, ...)", fmt);
_log::g_tty_file.log(ps3_fmt(ppu, fmt, va_args.count));
if (g_tty)
{
g_tty.write(ps3_fmt(ppu, fmt, va_args.count));
}
return CELL_OK;
}

View File

@ -210,7 +210,7 @@ s32 sys_lwcond_wait(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
{
sysPrxForUser.trace("sys_lwcond_wait(lwcond=*0x%x, timeout=0x%llx)", lwcond, timeout);
const be_t<u32> tid = ppu.id;
const be_t<u32> tid(ppu.id);
const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex;

View File

@ -74,7 +74,7 @@ s32 sys_lwmutex_lock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout
{
sysPrxForUser.trace("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout);
const be_t<u32> tid = ppu.id;
const be_t<u32> tid(ppu.id);
// try to lock lightweight mutex
const be_t<u32> old_owner = lwmutex->vars.owner.compare_and_swap(lwmutex_free, tid);
@ -168,7 +168,7 @@ s32 sys_lwmutex_trylock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
{
sysPrxForUser.trace("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex);
const be_t<u32> tid = ppu.id;
const be_t<u32> tid(ppu.id);
// try to lock lightweight mutex
const be_t<u32> old_owner = lwmutex->vars.owner.compare_and_swap(lwmutex_free, tid);
@ -235,7 +235,7 @@ s32 sys_lwmutex_unlock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
{
sysPrxForUser.trace("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex);
const be_t<u32> tid = ppu.id;
const be_t<u32> tid(ppu.id);
// check owner
if (lwmutex->vars.owner.load() != tid)

View File

@ -2377,3 +2377,23 @@ s32 ppu_error_code::report(s32 error, const char* text)
LOG_ERROR(PPU, "Illegal call to ppu_error_code::report(0x%x, '%s')!");
return error;
}
std::vector<ppu_function_t>& ppu_function_manager::access()
{
static std::vector<ppu_function_t> list
{
nullptr,
[](PPUThread& ppu) { ppu.state += cpu_state::ret; },
};
return list;
}
u32 ppu_function_manager::add_function(ppu_function_t function)
{
auto& list = access();
list.push_back(function);
return ::size32(list) - 1;
}

View File

@ -243,25 +243,9 @@ class ppu_function_manager
};
// Access global function list
static never_inline auto& access()
{
static std::vector<ppu_function_t> list
{
nullptr,
[](PPUThread& ppu) { ppu.state += cpu_state::ret; },
};
static std::vector<ppu_function_t>& access();
return list;
}
static never_inline u32 add_function(ppu_function_t function)
{
auto& list = access();
list.push_back(function);
return ::size32(list) - 1;
}
static u32 add_function(ppu_function_t function);
public:
// Register function (shall only be called during global initialization)

View File

@ -3,6 +3,7 @@
#include "PPUThread.h"
#include "PPUInterpreter.h"
// TODO: fix rol8 and rol16 for __GNUG__ (probably with __asm__)
inline u8 rol8(const u8 x, const u8 n) { return x << n | x >> (8 - n); }
inline u16 rol16(const u16 x, const u16 n) { return x << n | x >> (16 - n); }
inline u32 rol32(const u32 x, const u32 n) { return x << n | x >> (32 - n); }
@ -10,16 +11,16 @@ inline u64 rol64(const u64 x, const u64 n) { return x << n | x >> (64 - n); }
inline u64 dup32(const u32 x) { return x | static_cast<u64>(x) << 32; }
#if defined(__GNUG__)
inline std::uint64_t UMULH64(std::uint64_t a, std::uint64_t b)
inline u64 UMULH64(u64 a, u64 b)
{
std::uint64_t result;
u64 result;
__asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b));
return result;
}
inline std::int64_t MULH64(std::int64_t a, std::int64_t b)
inline s64 MULH64(s64 a, s64 b)
{
std::int64_t result;
s64 result;
__asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b));
return result;
}
@ -30,6 +31,95 @@ inline std::int64_t MULH64(std::int64_t a, std::int64_t b)
#define MULH64 __mulh
#endif
// Compare 16 packed unsigned bytes (greater than)
inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B)
{
// (A xor 0x80) > (B xor 0x80)
const auto sign = _mm_set1_epi32(0x80808080);
return _mm_cmpgt_epi8(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
}
inline __m128i sse_cmpgt_epu16(__m128i A, __m128i B)
{
const auto sign = _mm_set1_epi32(0x80008000);
return _mm_cmpgt_epi16(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
}
inline __m128i sse_cmpgt_epu32(__m128i A, __m128i B)
{
const auto sign = _mm_set1_epi32(0x80000000);
return _mm_cmpgt_epi32(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
}
inline __m128 sse_exp2_ps(__m128 A)
{
const auto x0 = _mm_max_ps(_mm_min_ps(A, _mm_set1_ps(127.4999961f)), _mm_set1_ps(-127.4999961f));
const auto x1 = _mm_add_ps(x0, _mm_set1_ps(0.5f));
const auto x2 = _mm_sub_epi32(_mm_cvtps_epi32(x1), _mm_and_si128(_mm_castps_si128(_mm_cmpnlt_ps(_mm_setzero_ps(), x1)), _mm_set1_epi32(1)));
const auto x3 = _mm_sub_ps(x0, _mm_cvtepi32_ps(x2));
const auto x4 = _mm_mul_ps(x3, x3);
const auto x5 = _mm_mul_ps(x3, _mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(x4, _mm_set1_ps(0.023093347705f)), _mm_set1_ps(20.20206567f)), x4), _mm_set1_ps(1513.906801f)));
const auto x6 = _mm_mul_ps(x5, _mm_rcp_ps(_mm_sub_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(233.1842117f), x4), _mm_set1_ps(4368.211667f)), x5)));
return _mm_mul_ps(_mm_add_ps(_mm_add_ps(x6, x6), _mm_set1_ps(1.0f)), _mm_castsi128_ps(_mm_slli_epi32(_mm_add_epi32(x2, _mm_set1_epi32(127)), 23)));
}
inline __m128 sse_log2_ps(__m128 A)
{
const auto _1 = _mm_set1_ps(1.0f);
const auto _c = _mm_set1_ps(1.442695040f);
const auto x0 = _mm_max_ps(A, _mm_castsi128_ps(_mm_set1_epi32(0x00800000)));
const auto x1 = _mm_or_ps(_mm_and_ps(x0, _mm_castsi128_ps(_mm_set1_epi32(0x807fffff))), _1);
const auto x2 = _mm_rcp_ps(_mm_add_ps(x1, _1));
const auto x3 = _mm_mul_ps(_mm_sub_ps(x1, _1), x2);
const auto x4 = _mm_add_ps(x3, x3);
const auto x5 = _mm_mul_ps(x4, x4);
const auto x6 = _mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(-0.7895802789f), x5), _mm_set1_ps(16.38666457f)), x5), _mm_set1_ps(-64.1409953f));
const auto x7 = _mm_rcp_ps(_mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(-35.67227983f), x5), _mm_set1_ps(312.0937664f)), x5), _mm_set1_ps(-769.6919436f)));
const auto x8 = _mm_cvtepi32_ps(_mm_sub_epi32(_mm_srli_epi32(_mm_castps_si128(x0), 23), _mm_set1_epi32(127)));
return _mm_add_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(x5, x6), x7), x4), _c), _mm_add_ps(_mm_mul_ps(x4, _c), x8));
}
template<typename T>
struct add_flags_result_t
{
T result;
bool carry;
bool zero;
bool sign;
add_flags_result_t() = default;
// Straighforward ADD with flags
add_flags_result_t(T a, T b)
: result(a + b)
, carry(result < a)
, zero(result == 0)
, sign(result >> (sizeof(T) * 8 - 1) != 0)
{
}
// Straighforward ADC with flags
add_flags_result_t(T a, T b, bool c)
: add_flags_result_t(a, b)
{
add_flags_result_t r(result, c);
result = r.result;
carry |= r.carry;
zero = r.zero;
sign = r.sign;
}
};
static add_flags_result_t<u64> add64_flags(u64 a, u64 b)
{
return{ a, b };
}
static add_flags_result_t<u64> add64_flags(u64 a, u64 b, bool c)
{
return{ a, b, c };
}
extern u64 get_timebased_time();
extern void ppu_execute_syscall(PPUThread& ppu, u64 code);
extern void ppu_execute_function(PPUThread& ppu, u32 index);

View File

@ -80,6 +80,35 @@ ppu_static_module::ppu_static_module(const char* name)
ppu_module_manager::register_module(this);
}
std::unordered_map<std::string, ppu_static_module*>& ppu_module_manager::access()
{
static std::unordered_map<std::string, ppu_static_module*> map;
return map;
}
void ppu_module_manager::register_module(ppu_static_module* module)
{
access().emplace(module->name, module);
}
ppu_static_function& ppu_module_manager::access_static_function(const char* module, u32 fnid)
{
return access().at(module)->functions[fnid];
}
ppu_static_variable& ppu_module_manager::access_static_variable(const char* module, u32 vnid)
{
return access().at(module)->variables[vnid];
}
const ppu_static_module* ppu_module_manager::get_module(const std::string& name)
{
const auto& map = access();
const auto found = map.find(name);
return found != map.end() ? found->second : nullptr;
}
// Initialize static modules.
static void ppu_initialize_modules()
{

View File

@ -68,35 +68,16 @@ class ppu_module_manager final
{
friend class ppu_static_module;
static never_inline auto& access()
{
static std::unordered_map<std::string, ppu_static_module*> map;
static std::unordered_map<std::string, ppu_static_module*>& access();
return map;
}
static void register_module(ppu_static_module* module);
static never_inline void register_module(ppu_static_module* module)
{
access().emplace(module->name, module);
}
static ppu_static_function& access_static_function(const char* module, u32 fnid);
static never_inline auto& access_static_function(const char* module, u32 fnid)
{
return access().at(module)->functions[fnid];
}
static never_inline auto& access_static_variable(const char* module, u32 vnid)
{
return access().at(module)->variables[vnid];
}
static ppu_static_variable& access_static_variable(const char* module, u32 vnid);
public:
static never_inline const ppu_static_module* get_module(const std::string& name)
{
const auto& map = access();
const auto found = map.find(name);
return found != map.end() ? found->second : nullptr;
}
static const ppu_static_module* get_module(const std::string& name);
template<typename T, T Func>
static void register_static_function(const char* module, const char* name, ppu_function_t func, u32 fnid, u32 flags)

View File

@ -76,6 +76,8 @@ void PPUThread::cpu_init()
GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200;
}
extern thread_local std::string(*g_tls_log_prefix)();
void PPUThread::cpu_task()
{
//SetHostRoundingMode(FPSCR_RN_NEAR);
@ -87,7 +89,7 @@ void PPUThread::cpu_task()
return custom_task(*this);
}
_log::g_tls_make_prefix = [](const auto&, auto, const auto&)
g_tls_log_prefix = []
{
const auto cpu = static_cast<PPUThread*>(get_current_cpu_thread());

View File

@ -2184,7 +2184,7 @@ void spu_recompiler::BR(spu_opcode_t op)
c->mov(*addr, target | 0x2000000);
//c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self
//c->je(labels[target / 4]);
c->lock().or_(SPU_OFF_32(state), (to_mset(cpu_state::stop) + cpu_state::ret)._value());
c->lock().or_(SPU_OFF_32(state), make_bitset(cpu_state::stop, cpu_state::ret)._value());
c->jmp(*end);
c->unuse(*addr);
return;

View File

@ -7,6 +7,26 @@
#include <fenv.h>
// Compare 16 packed unsigned bytes (greater than)
inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B)
{
// (A xor 0x80) > (B xor 0x80)
const auto sign = _mm_set1_epi32(0x80808080);
return _mm_cmpgt_epi8(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
}
inline __m128i sse_cmpgt_epu16(__m128i A, __m128i B)
{
const auto sign = _mm_set1_epi32(0x80008000);
return _mm_cmpgt_epi16(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
}
inline __m128i sse_cmpgt_epu32(__m128i A, __m128i B)
{
const auto sign = _mm_set1_epi32(0x80000000);
return _mm_cmpgt_epi32(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
}
void spu_interpreter::UNK(SPUThread& spu, spu_opcode_t op)
{
throw EXCEPTION("Unknown/Illegal instruction (0x%08x)", op.opcode);

View File

@ -116,6 +116,8 @@ void SPUThread::cpu_init()
gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer
}
extern thread_local std::string(*g_tls_log_prefix)();
void SPUThread::cpu_task()
{
std::fesetround(FE_TOWARDZERO);
@ -127,7 +129,7 @@ void SPUThread::cpu_task()
return custom_task(*this);
}
_log::g_tls_make_prefix = [](const auto&, auto, const auto&)
g_tls_log_prefix = []
{
const auto cpu = static_cast<SPUThread*>(get_current_cpu_thread());

View File

@ -84,7 +84,8 @@ public:
const u64 name;
const u64 ipc_key;
const s32 size;
const u32 id{};
const id_value<> id{};
lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size)
: protocol(protocol)

View File

@ -7,6 +7,9 @@
#include "Emu/Cell/ErrorCodes.h"
#include "sys_fs.h"
#include "Utilities/StrUtil.h"
#include <cerrno>
LOG_CHANNEL(sys_fs);
s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6)
@ -42,7 +45,7 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
return CELL_FS_EISDIR;
}
mset<fs::open_mode> open_mode{};
bitset_t<fs::open_mode> open_mode{};
switch (flags & CELL_FS_O_ACCMODE)
{
@ -349,7 +352,7 @@ s32 sys_fs_rmdir(vm::cptr<char> path)
if (!fs::remove_dir(vfs::get(path.get_ptr())))
{
switch (auto error = errno)
switch (auto error = fs::error)
{
case ENOENT: return CELL_FS_ENOENT;
default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error);
@ -369,7 +372,7 @@ s32 sys_fs_unlink(vm::cptr<char> path)
if (!fs::remove_file(vfs::get(path.get_ptr())))
{
switch (auto error = errno)
switch (auto error = fs::error)
{
case ENOENT: return CELL_FS_ENOENT;
default: sys_fs.error("sys_fs_unlink(): unknown error %d", error);
@ -448,7 +451,7 @@ s32 sys_fs_truncate(vm::cptr<char> path, u64 size)
if (!fs::truncate_file(vfs::get(path.get_ptr()), size))
{
switch (auto error = errno)
switch (auto error = fs::error)
{
case ENOENT: return CELL_FS_ENOENT;
default: sys_fs.error("sys_fs_truncate(): unknown error %d", error);
@ -475,7 +478,7 @@ s32 sys_fs_ftruncate(u32 fd, u64 size)
if (!file->file.trunc(size))
{
switch (auto error = errno)
switch (auto error = fs::error)
{
case 0:
default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error);

View File

@ -173,7 +173,7 @@ struct lv2_fs_object_t
static constexpr u32 id_min = 3;
static constexpr u32 id_max = 255;
const u32 id{};
const id_value<> id{};
};
struct lv2_file_t : lv2_fs_object_t

View File

@ -6,7 +6,7 @@ class PPUThread;
struct lv2_int_tag_t
{
const u32 id{};
const id_value<> id{};
std::shared_ptr<struct lv2_int_serv_t> handler;
};
@ -14,7 +14,8 @@ struct lv2_int_tag_t
struct lv2_int_serv_t
{
const std::shared_ptr<PPUThread> thread;
const u32 id{};
const id_value<> id{};
atomic_t<u32> signal{ 0 }; // signal count

View File

@ -46,13 +46,15 @@ struct sys_page_attr_t
struct lv2_memory_container_t
{
const u32 size; // amount of "physical" memory in this container
const u32 id{};
// Amount of "physical" memory in this container
const u32 size;
// amount of memory allocated
const id_value<> id{};
// Amount of memory allocated
atomic_t<u32> used{ 0 };
// allocations (addr -> size)
// Allocations (addr -> size)
std::map<u32, u32> allocs;
lv2_memory_container_t(u32 size)

View File

@ -8,7 +8,8 @@ struct lv2_memory_t
const u32 align; // required alignment
const u64 flags;
const std::shared_ptr<lv2_memory_container_t> ct; // memory container the physical memory is taken from
const u32 id{};
const id_value<> id{};
atomic_t<u32> addr{ 0 }; // actual mapping address

View File

@ -74,7 +74,7 @@ struct sys_prx_get_module_list_t
struct lv2_prx_t
{
const u32 id{};
const id_value<> id{};
bool is_started = false;

View File

@ -28,7 +28,7 @@ public:
void on_stop() override;
const u32 id{}; // Timer id
const id_value<> id{};
atomic_t<u32> state{ SYS_TIMER_STATE_RUN }; // Timer state

View File

@ -8,6 +8,8 @@
LOG_CHANNEL(sys_tty);
extern fs::file g_tty;
s32 sys_tty_read(s32 ch, vm::ptr<char> buf, u32 len, vm::ptr<u32> preadlen)
{
sys_tty.todo("sys_tty_read(ch=%d, buf=*0x%x, len=%d, preadlen=*0x%x)", ch, buf, len, preadlen);
@ -34,7 +36,10 @@ s32 sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwritelen)
return CELL_OK;
}
_log::g_tty_file.log({ buf.get_ptr(), len });
if (g_tty)
{
g_tty.write(buf.get_ptr(), len);
}
*pwritelen = len;

119
rpcs3/Emu/IdManager.cpp Normal file
View File

@ -0,0 +1,119 @@
#include "stdafx.h"
#include "IdManager.h"
std::vector<id_manager::typeinfo>& id_manager::typeinfo::access()
{
static std::vector<typeinfo> list;
return list;
}
u32 id_manager::typeinfo::add_type(typeinfo info)
{
auto& list = access();
list.emplace_back(info);
return ::size32(list) - 1;
}
idm::map_type::pointer idm::allocate_id(u32 tag, u32 min, u32 max)
{
// Check all IDs starting from "next id"
for (u32 i = 0; i <= max - min; i++)
{
// Fix current ID (wrap around)
if (g_id[tag] < min || g_id[tag] > max) g_id[tag] = min;
// Get ID
const auto r = g_map[tag].emplace(g_id[tag]++, nullptr);
if (r.second)
{
return &*r.first;
}
}
// Nothing found
return nullptr;
}
std::shared_ptr<void> idm::deallocate_id(u32 tag, u32 id)
{
const auto found = g_map[tag].find(id);
if (found == g_map[tag].end()) return nullptr;
auto ptr = std::move(found->second);
g_map[tag].erase(found);
return ptr;
}
idm::map_type::pointer idm::find_id(u32 type, u32 id)
{
const auto found = g_map[type].find(id);
if (found == g_map[type].end()) return nullptr;
return &*found;
}
std::shared_ptr<void> idm::delete_id(u32 type, u32 tag, u32 id)
{
writer_lock lock(g_mutex);
auto&& ptr = deallocate_id(tag, id);
g_map[type].erase(id);
return ptr;
}
void idm::init()
{
g_map.resize(id_manager::typeinfo::get().size(), {});
g_id.resize(id_manager::typeinfo::get().size(), 0);
}
void idm::clear()
{
// Call recorded finalization functions for all IDs
for (std::size_t i = 0; i < g_map.size(); i++)
{
for (auto& id : g_map[i])
{
id_manager::typeinfo::get()[i].on_stop(id.second.get());
}
g_map[i].clear();
g_id[i] = 0;
}
}
std::shared_ptr<void> fxm::remove(u32 type)
{
writer_lock lock(g_mutex);
return std::move(g_map[type]);
}
void fxm::init()
{
g_map.resize(id_manager::typeinfo::get().size(), {});
}
void fxm::clear()
{
// Call recorded finalization functions for all IDs
for (std::size_t i = 0; i < g_map.size(); i++)
{
if (g_map[i])
{
id_manager::typeinfo::get()[i].on_stop(g_map[i].get());
}
g_map[i].reset();
}
}

View File

@ -1,7 +1,13 @@
#pragma once
#include "Utilities/types.h"
#include "Utilities/Macro.h"
#include "Utilities/Platform.h"
#include "Utilities/SharedMutex.h"
#include <memory>
#include <vector>
#include <unordered_map>
#include <set>
#include <map>
@ -27,25 +33,6 @@ namespace id_manager
static constexpr u32 max = T::id_max;
};
// Optional ID storage
template<typename T, typename = void>
struct id_storage
{
static const u32* get(T*)
{
return nullptr;
}
};
template<typename T>
struct id_storage<T, void_t<decltype(&T::id)>>
{
static const u32* get(T* ptr)
{
return &ptr->id;
}
};
// Optional object initialization function (called after ID registration)
template<typename T, typename = void>
struct on_init
@ -82,7 +69,6 @@ namespace id_manager
}
};
template<typename>
class typeinfo
{
// Global variable for each registered type
@ -93,24 +79,12 @@ namespace id_manager
};
// Access global type list
static never_inline auto& access()
{
static std::vector<typeinfo> list;
static std::vector<typeinfo>& access();
return list;
}
static never_inline u32 add_type(typeinfo info)
{
auto& list = access();
list.emplace_back(info);
return ::size32(list) - 1;
}
// Add to the global list
static u32 add_type(typeinfo info);
public:
const std::type_info* info;
void(*on_init)(void*);
void(*on_stop)(void*);
@ -131,10 +105,9 @@ namespace id_manager
}
};
template<typename TAG> template<typename T>
const u32 typeinfo<TAG>::registered<T>::index = typeinfo<TAG>::add_type(
template<typename T>
const u32 typeinfo::registered<T>::index = typeinfo::add_type(
{
&typeid(T),
PURE_EXPR(id_manager::on_init<T>::func(static_cast<T*>(ptr)), void* ptr),
PURE_EXPR(id_manager::on_stop<T>::func(static_cast<T*>(ptr)), void* ptr),
});
@ -160,23 +133,18 @@ class idm
using map_type = std::unordered_map<u32, std::shared_ptr<void>, id_hash_t>;
static shared_mutex g_mutex;
// Type Index -> ID -> Object. Use global since only one process is supported atm.
static std::vector<map_type> g_map;
// Next ID for each category
static std::vector<u32> g_id;
static shared_mutex g_mutex;
static const auto& get_types()
{
return id_manager::typeinfo<idm>::get();
}
template<typename T>
static inline u32 get_type()
{
return id_manager::typeinfo<idm>::get_index<T>();
return id_manager::typeinfo::get_index<T>();
}
template<typename T>
@ -185,44 +153,25 @@ class idm
return get_type<typename id_manager::id_traits<T>::tag>();
}
// Prepares new ID, returns nullptr if out of resources
static map_type::pointer allocate_id(u32 tag, u32 min, u32 max)
// Update optional ID storage
template<typename T>
static auto set_id_value(T* ptr, u32 id) -> decltype(static_cast<void>(std::declval<T&>().id))
{
// Check all IDs starting from "next id"
for (u32 i = 0; i <= max - min; i++)
{
// Fix current ID (wrap around)
if (g_id[tag] < min || g_id[tag] > max) g_id[tag] = min;
// Get ID
const auto r = g_map[tag].emplace(g_id[tag]++, nullptr);
if (r.second)
{
return &*r.first;
}
}
// Nothing found
return nullptr;
ptr->id = id;
}
static void set_id_value(...)
{
}
// Prepares new ID, returns nullptr if out of resources
static map_type::pointer allocate_id(u32 tag, u32 min, u32 max);
// Deallocate ID, returns object
static std::shared_ptr<void> deallocate_id(u32 tag, u32 id)
{
const auto found = g_map[tag].find(id);
if (found == g_map[tag].end()) return nullptr;
auto ptr = std::move(found->second);
g_map[tag].erase(found);
return ptr;
}
static std::shared_ptr<void> deallocate_id(u32 tag, u32 id);
// Allocate new ID and construct it from the provider()
template<typename T, typename F, typename = std::result_of_t<F()>>
template<typename T, typename F>
static map_type::pointer create_id(F&& provider)
{
writer_lock lock(g_mutex);
@ -231,14 +180,11 @@ class idm
{
try
{
// Get object, write it
// Get object, store it
place->second = provider();
// Update ID storage if available
if (const u32* id = id_manager::id_storage<T>::get(static_cast<T*>(place->second.get())))
{
*const_cast<u32*>(id) = place->first;
}
// Update ID value if required
set_id_value(static_cast<T*>(place->second.get()), place->first);
return &*g_map[get_type<T>()].emplace(*place).first;
}
@ -252,41 +198,18 @@ class idm
return nullptr;
}
// Get ID (internal)
static map_type::pointer find_id(u32 type, u32 id);
// Remove ID and return object
static std::shared_ptr<void> delete_id(u32 type, u32 tag, u32 id)
{
writer_lock lock(g_mutex);
auto&& ptr = deallocate_id(tag, id);
g_map[type].erase(id);
return ptr;
}
static std::shared_ptr<void> delete_id(u32 type, u32 tag, u32 id);
public:
// Initialize object manager
static void init()
{
g_map.resize(get_types().size(), {});
g_id.resize(get_types().size(), 0);
}
static void init();
// Remove all objects
static void clear()
{
// Call recorded finalization functions for all IDs
for (std::size_t i = 0; i < g_map.size(); i++)
{
for (auto& id : g_map[i])
{
get_types()[i].on_stop(id.second.get());
}
g_map[i].clear();
g_id[i] = 0;
}
}
static void clear();
// Add a new ID of specified type with specified constructor arguments (returns object or nullptr)
template<typename T, typename Make = T, typename... Args>
@ -346,7 +269,7 @@ public:
{
reader_lock lock(g_mutex);
return g_map[get_type<T>()].count(id) != 0;
return find_id(get_type<T>(), id) != nullptr;
}
// Get ID
@ -355,9 +278,9 @@ public:
{
reader_lock lock(g_mutex);
const auto found = g_map[get_type<T>()].find(id);
const auto found = find_id(get_type<T>(), id);
if (found == g_map[get_type<T>()].end())
if (UNLIKELY(found == nullptr))
{
return nullptr;
}
@ -387,7 +310,7 @@ public:
{
auto&& ptr = delete_id(get_type<T>(), get_tag<T>(), id);
if (ptr)
if (LIKELY(ptr))
{
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
}
@ -401,7 +324,7 @@ public:
{
auto&& ptr = delete_id(get_type<T>(), get_tag<T>(), id);
if (ptr)
if (LIKELY(ptr))
{
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
}
@ -458,45 +381,20 @@ class fxm
static shared_mutex g_mutex;
static inline const auto& get_types()
{
return id_manager::typeinfo<fxm>::get();
}
template<typename T>
static inline u32 get_type()
{
return id_manager::typeinfo<fxm>::get_index<T>();
return id_manager::typeinfo::get_index<T>();
}
static std::shared_ptr<void> remove(u32 type)
{
writer_lock lock(g_mutex);
return std::move(g_map[type]);
}
static std::shared_ptr<void> remove(u32 type);
public:
// Initialize object manager
static void init()
{
g_map.resize(get_types().size(), {});
}
static void init();
// Remove all objects
static void clear()
{
// Call recorded finalization functions for all IDs
for (std::size_t i = 0; i < g_map.size(); i++)
{
if (g_map[i])
{
get_types()[i].on_stop(g_map[i].get());
}
g_map[i].reset();
}
}
static void clear();
// Create the object (returns nullptr if it already exists)
template<typename T, typename Make = T, typename... Args>

View File

@ -1,7 +1,10 @@
#pragma once
#include <string>
#include <vector>
#include "Utilities/StrUtil.h"
enum class FUNCTION {
FUNCTION_DP2,
FUNCTION_DP2A,
@ -220,4 +223,4 @@ public:
return name + "." + fmt::merge({ swizzles }, ".");
}
};
};

View File

@ -680,7 +680,7 @@ void GLGSRender::flip(int buffer)
coordi aspect_ratio;
if (1) //enable aspect ratio
{
sizei csize = m_frame->client_size();
sizei csize(m_frame->client_width(), m_frame->client_height());
sizei new_size = csize;
const double aq = (double)buffer_width / buffer_height;
@ -702,7 +702,7 @@ void GLGSRender::flip(int buffer)
}
else
{
aspect_ratio.size = m_frame->client_size();
aspect_ratio.size = { m_frame->client_width(), m_frame->client_height() };
}
gl::screen.clear(gl::buffers::color_depth_stencil);

View File

@ -10,6 +10,8 @@
#include "OpenGL.h"
#include "../GCM.h"
#include "Utilities/geometry.h"
namespace gl
{
#ifdef _DEBUG

View File

@ -7,7 +7,7 @@
// temporarily (u8 value is really CellVideoOutResolutionId, but HLE declarations shouldn't be available for the rest of emu, even indirectly)
extern cfg::map_entry<u8> g_cfg_video_out_resolution;
extern const std::unordered_map<u8, size2i> g_video_out_resolution_map;
extern const std::unordered_map<u8, std::pair<int, int>> g_video_out_resolution_map;
draw_context_t GSFrameBase::new_context()
{
@ -20,8 +20,9 @@ draw_context_t GSFrameBase::new_context()
}
GSRender::GSRender(frame_type type)
: m_frame(Emu.GetCallbacks().get_gs_frame(type, g_video_out_resolution_map.at(g_cfg_video_out_resolution.get())).release())
{
const auto size = g_video_out_resolution_map.at(g_cfg_video_out_resolution.get());
m_frame = Emu.GetCallbacks().get_gs_frame(type, size.first, size.second).release();
}
GSRender::~GSRender()

View File

@ -37,7 +37,8 @@ public:
virtual void set_current(draw_context_t ctx) = 0;
virtual void flip(draw_context_t ctx) = 0;
virtual size2i client_size() = 0;
virtual int client_width() = 0;
virtual int client_height() = 0;
virtual void* handle() const = 0;

View File

@ -10,6 +10,7 @@
#include "rsx_methods.h"
#include "Utilities/GSL.h"
#include "Utilities/StrUtil.h"
#define CMD_DEBUG 0

View File

@ -8,9 +8,9 @@
#include "RSXVertexProgram.h"
#include "RSXFragmentProgram.h"
#include "Utilities/Semaphore.h"
#include "Utilities/Thread.h"
#include "Utilities/Timer.h"
#include "Utilities/geometry.h"
extern u64 get_system_time();
@ -54,7 +54,7 @@ namespace rsx
template<>
struct bijective<rsx::shader_language, const char*>
{
static constexpr std::pair<rsx::shader_language, const char*> map[]
static constexpr bijective_pair<rsx::shader_language, const char*> map[]
{
{ rsx::shader_language::glsl, "glsl" },
{ rsx::shader_language::hlsl, "hlsl" },
@ -281,7 +281,6 @@ namespace rsx
double fps_limit = 59.94;
public:
semaphore_t sem_flip;
u64 last_flip_time;
vm::ps3::ptr<void(u32)> flip_handler = vm::null;
vm::ps3::ptr<void(u32)> user_handler = vm::null;

View File

@ -376,7 +376,7 @@ VKGSRender::VKGSRender() : GSRender(frame_type::Vulkan)
vk::set_current_thread_ctx(m_thread_context);
vk::set_current_renderer(m_swap_chain->get_device());
m_swap_chain->init_swapchain(m_frame->client_size().width, m_frame->client_size().height);
m_swap_chain->init_swapchain(m_frame->client_width(), m_frame->client_height());
//create command buffer...
m_command_buffer_pool.create((*m_device));
@ -582,8 +582,8 @@ void VKGSRender::end()
rp_begin.framebuffer = m_framebuffer_to_clean.back()->value;
rp_begin.renderArea.offset.x = 0;
rp_begin.renderArea.offset.y = 0;
rp_begin.renderArea.extent.width = m_frame->client_size().width;
rp_begin.renderArea.extent.height = m_frame->client_size().height;
rp_begin.renderArea.extent.width = m_frame->client_width();
rp_begin.renderArea.extent.height = m_frame->client_height();
vkCmdBeginRenderPass(m_command_buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
@ -1106,7 +1106,7 @@ void VKGSRender::flip(int buffer)
coordi aspect_ratio;
if (1) //enable aspect ratio
{
sizei csize = m_frame->client_size();
sizei csize = { m_frame->client_width(), m_frame->client_height() };
sizei new_size = csize;
const double aq = (double)buffer_width / buffer_height;
@ -1128,7 +1128,7 @@ void VKGSRender::flip(int buffer)
}
else
{
aspect_ratio.size = m_frame->client_size();
aspect_ratio.size = { m_frame->client_width(), m_frame->client_height() };
}
VkSwapchainKHR swap_chain = (VkSwapchainKHR)(*m_swap_chain);

View File

@ -674,8 +674,6 @@ namespace rsx
});
}
rsx->sem_flip.post_and_wait();
if (double limit = g_cfg_rsx_frame_limit.get())
{
if (limit < 0) limit = rsx->fps_limit; // TODO

View File

@ -17,6 +17,8 @@
#include "Loader/PSF.h"
#include "Loader/ELF.h"
#include "Utilities/StrUtil.h"
#include "../Crypto/unself.h"
cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot");
@ -31,6 +33,8 @@ extern atomic_t<u32> g_thread_count;
extern u64 get_system_time();
fs::file g_tty;
namespace rpcs3
{
event<void>& on_run() { static event<void> on_run; return on_run; }
@ -48,6 +52,11 @@ Emulator::Emulator()
void Emulator::Init()
{
if (!g_tty)
{
g_tty.open(fs::get_config_dir() + "TTY.log", fs::rewrite + fs::append);
}
idm::init();
fxm::init();
@ -424,7 +433,7 @@ DECLARE(fxm::g_map);
DECLARE(fxm::g_mutex);
#ifndef _MSC_VER
constexpr std::pair<elf_error, const char*> bijective<elf_error, const char*>::map[];
constexpr std::pair<_log::level, const char*> bijective<_log::level, const char*>::map[];
constexpr std::pair<rsx::shader_language, const char*> bijective<rsx::shader_language, const char*>::map[];
constexpr DECLARE(bijective<elf_error, const char*>::map);
constexpr DECLARE(bijective<_log::level, const char*>::map);
constexpr DECLARE(bijective<rsx::shader_language, const char*>::map);
#endif

View File

@ -14,7 +14,7 @@ struct EmuCallbacks
std::function<std::shared_ptr<class KeyboardHandlerBase>()> get_kb_handler;
std::function<std::shared_ptr<class MouseHandlerBase>()> get_mouse_handler;
std::function<std::shared_ptr<class PadHandlerBase>()> get_pad_handler;
std::function<std::unique_ptr<class GSFrameBase>(frame_type, size2i)> get_gs_frame;
std::function<std::unique_ptr<class GSFrameBase>(frame_type, int, int)> get_gs_frame;
std::function<std::shared_ptr<class GSRender>()> get_gs_render;
std::function<std::shared_ptr<class AudioThread>()> get_audio;
std::function<std::shared_ptr<class MsgDialogBase>()> get_msg_dialog;

View File

@ -4,6 +4,8 @@
#include "VFS.h"
#include "Utilities/StrUtil.h"
cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_executable_dir()
cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/");
cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/");

View File

@ -169,7 +169,7 @@ void LogFrame::OnTimer(wxTimerEvent& event)
const auto start = std::chrono::high_resolution_clock::now();
// Check TTY logs
while (const u64 size = std::min<u64>(sizeof(buf), _log::g_tty_file.size() - m_tty_file.pos()))
while (const u64 size = std::min<u64>(sizeof(buf), m_tty_file.size() - m_tty_file.pos()))
{
const wxString& text = get_utf8(m_tty_file, size);

View File

@ -7,8 +7,8 @@
extern cfg::bool_entry g_cfg_rsx_debug_output;
GLGSFrame::GLGSFrame(size2i size)
: GSFrame("OpenGL", size)
GLGSFrame::GLGSFrame(int w, int h)
: GSFrame("OpenGL", w, h)
{
const int context_attrs[] =
{
@ -26,7 +26,7 @@ GLGSFrame::GLGSFrame(size2i size)
0
};
m_canvas = new wxGLCanvas(this, wxID_ANY, context_attrs, wxDefaultPosition, { size.width, size.height });
m_canvas = new wxGLCanvas(this, wxID_ANY, context_attrs, wxDefaultPosition, { w, h });
m_canvas->Bind(wxEVT_LEFT_DCLICK, &GSFrame::OnLeftDclick, this);
}

View File

@ -8,7 +8,7 @@ class GLGSFrame : public GSFrame
wxGLCanvas* m_canvas;
public:
GLGSFrame(size2i);
GLGSFrame(int w, int h);
void* make_context() override;
void set_current(draw_context_t context) override;

View File

@ -12,12 +12,12 @@ BEGIN_EVENT_TABLE(GSFrame, wxFrame)
EVT_SIZE(GSFrame::OnSize)
END_EVENT_TABLE()
GSFrame::GSFrame(const wxString& title, size2i size)
GSFrame::GSFrame(const wxString& title, int w, int h)
: wxFrame(nullptr, wxID_ANY, "GSFrame[" + title + "]")
{
SetIcon(wxGetApp().m_MainFrame->GetIcon());
SetClientSize(size.width, size.height);
SetClientSize(w, h);
wxGetApp().Bind(wxEVT_KEY_DOWN, &GSFrame::OnKeyDown, this);
Bind(wxEVT_CLOSE_WINDOW, &GSFrame::OnClose, this);
Bind(wxEVT_LEFT_DCLICK, &GSFrame::OnLeftDclick, this);
@ -86,10 +86,14 @@ void GSFrame::delete_context(void* ctx)
{
}
size2i GSFrame::client_size()
int GSFrame::client_width()
{
wxSize size = GetClientSize();
return{ size.GetWidth(), size.GetHeight() };
return GetClientSize().GetWidth();
}
int GSFrame::client_height()
{
return GetClientSize().GetHeight();
}
void GSFrame::flip(draw_context_t)

View File

@ -7,7 +7,7 @@ class GSFrame : public wxFrame, public GSFrameBase
u64 m_frames = 0;
public:
GSFrame(const wxString& title, size2i);
GSFrame(const wxString& title, int w, int h);
protected:
virtual void OnPaint(wxPaintEvent& event);
@ -28,7 +28,8 @@ protected:
void set_current(draw_context_t context) override;
void delete_context(void* context) override;
void flip(draw_context_t context) override;
size2i client_size() override;
int client_width() override;
int client_height() override;
public:
void OnLeftDclick(wxMouseEvent&)

View File

@ -453,7 +453,7 @@ void InterpreterDisAsmFrame::DoStep(wxCommandEvent& WXUNUSED(event))
{
if (cpu)
{
if (cpu->state.atomic_op([](mset<cpu_state>& state) -> bool
if (cpu->state.atomic_op([](bitset_t<cpu_state>& state) -> bool
{
state += cpu_state::dbg_step;
return state.test_and_reset(cpu_state::dbg_pause);

View File

@ -157,7 +157,7 @@ enum class elf_error
template<>
struct bijective<elf_error, const char*>
{
static constexpr std::pair<elf_error, const char*> map[]
static constexpr bijective_pair<elf_error, const char*> map[]
{
{ elf_error::ok, "" },

View File

@ -16,7 +16,7 @@ bool TRPLoader::Install(const std::string& dest, bool show)
const std::string& local_path = vfs::get(dest);
if (!fs::create_dir(local_path) && errno != EEXIST)
if (!fs::create_dir(local_path) && fs::error != EEXIST)
{
return false;
}

View File

@ -74,7 +74,9 @@
</ClCompile>
<ClCompile Include="..\Utilities\Config.cpp" />
<ClCompile Include="..\Utilities\rXml.cpp" />
<ClCompile Include="..\Utilities\Semaphore.cpp" />
<ClCompile Include="..\Utilities\Semaphore.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\Utilities\SharedMutex.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
@ -227,6 +229,7 @@
<ClCompile Include="Emu\Cell\SPUASMJITRecompiler.cpp" />
<ClCompile Include="Emu\Cell\SPUDisAsm.cpp" />
<ClCompile Include="Emu\Cell\SPUInterpreter.cpp" />
<ClCompile Include="Emu\IdManager.cpp" />
<ClCompile Include="Emu\Memory\wait_engine.cpp" />
<ClCompile Include="Emu\RSX\CgBinaryFragmentProgram.cpp" />
<ClCompile Include="Emu\RSX\CgBinaryVertexProgram.cpp" />
@ -357,7 +360,9 @@
<ClInclude Include="..\Utilities\AutoPause.h" />
<ClInclude Include="..\Utilities\BEType.h" />
<ClInclude Include="..\Utilities\BitField.h" />
<ClInclude Include="..\Utilities\BitSet.h" />
<ClInclude Include="..\Utilities\event.h" />
<ClInclude Include="..\Utilities\geometry.h" />
<ClInclude Include="..\Utilities\GSL.h" />
<ClInclude Include="..\Utilities\Platform.h" />
<ClInclude Include="..\Utilities\Log.h" />
@ -369,6 +374,7 @@
<ClInclude Include="..\Utilities\SharedMutex.h" />
<ClInclude Include="..\Utilities\SleepQueue.h" />
<ClInclude Include="..\Utilities\StrFmt.h" />
<ClInclude Include="..\Utilities\StrUtil.h" />
<ClInclude Include="..\Utilities\Thread.h" />
<ClInclude Include="..\Utilities\Timer.h" />
<ClInclude Include="..\Utilities\types.h" />

View File

@ -851,6 +851,9 @@
<ClCompile Include="Emu\Memory\wait_engine.cpp">
<Filter>Emu\Memory</Filter>
</ClCompile>
<ClCompile Include="Emu\IdManager.cpp">
<Filter>Emu</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">
@ -1606,5 +1609,14 @@
<ClInclude Include="Emu\Cell\lv2\IPC.h">
<Filter>Emu\Cell\lv2</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\StrUtil.h">
<Filter>Utilities</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\geometry.h">
<Filter>Utilities</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\BitSet.h">
<Filter>Utilities</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -164,14 +164,14 @@ bool Rpcs3App::OnInit()
callbacks.get_pad_handler = PURE_EXPR(g_cfg_pad_handler.get()());
callbacks.get_gs_frame = [](frame_type type, size2i size) -> std::unique_ptr<GSFrameBase>
callbacks.get_gs_frame = [](frame_type type, int w, int h) -> std::unique_ptr<GSFrameBase>
{
switch (type)
{
case frame_type::OpenGL: return std::make_unique<GLGSFrame>(size);
case frame_type::DX12: return std::make_unique<GSFrame>("DirectX 12", size);
case frame_type::Null: return std::make_unique<GSFrame>("Null", size);
case frame_type::Vulkan: return std::make_unique<GSFrame>("Vulkan", size);
case frame_type::OpenGL: return std::make_unique<GLGSFrame>(w, h);
case frame_type::DX12: return std::make_unique<GSFrame>("DirectX 12", w, h);
case frame_type::Null: return std::make_unique<GSFrame>("Null", w, h);
case frame_type::Vulkan: return std::make_unique<GSFrame>("Vulkan", w, h);
}
throw EXCEPTION("Invalid Frame Type (0x%x)", type);

View File

@ -19,16 +19,12 @@
#pragma warning( disable : 4351 )
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <climits>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <string>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <memory>
#include <vector>
@ -54,6 +50,5 @@ using namespace std::chrono_literals;
#include "Utilities/BEType.h"
#include "Utilities/Atomic.h"
#include "Utilities/StrFmt.h"
#include "Utilities/BitField.h"
#include "Utilities/File.h"
#include "Utilities/Log.h"