mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
parent
da7472fe81
commit
aafcf44581
253
Utilities/BitSet.h
Normal file
253
Utilities/BitSet.h
Normal 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;
|
||||
};
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 += "} ";
|
||||
}
|
||||
|
||||
|
@ -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" },
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -1,120 +1,90 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Semaphore.h"
|
||||
|
||||
bool semaphore_t::try_wait()
|
||||
{
|
||||
// check m_value without interlocked op
|
||||
if (m_var.load().value == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
// try to decrement m_value atomically
|
||||
const auto old = m_var.fetch_op([](sync_var_t& var)
|
||||
struct benaphore::internal
|
||||
{
|
||||
if (var.value)
|
||||
{
|
||||
var.value--;
|
||||
}
|
||||
});
|
||||
std::mutex mutex;
|
||||
|
||||
// recheck atomic result
|
||||
if (old.value == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::size_t acq_order{};
|
||||
std::size_t rel_order{};
|
||||
|
||||
return true;
|
||||
}
|
||||
std::condition_variable cond;
|
||||
};
|
||||
|
||||
bool semaphore_t::try_post()
|
||||
void benaphore::wait_hard()
|
||||
{
|
||||
// check m_value without interlocked op
|
||||
if (m_var.load().value >= max_value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
initialize_once();
|
||||
|
||||
// try to increment m_value atomically
|
||||
const auto old = m_var.fetch_op([&](sync_var_t& var)
|
||||
{
|
||||
if (var.value < max_value)
|
||||
{
|
||||
var.value++;
|
||||
}
|
||||
});
|
||||
std::unique_lock<std::mutex> lock(m_data->mutex);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}))
|
||||
// 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++;
|
||||
});
|
||||
|
||||
while (!m_var.atomic_op([](sync_var_t& var) -> bool
|
||||
{
|
||||
if (var.value)
|
||||
{
|
||||
var.value--;
|
||||
var.waiters--;
|
||||
|
||||
return true;
|
||||
m_data->cond.wait(lock);
|
||||
}
|
||||
else
|
||||
|
||||
if (order == m_data->acq_order && m_data->acq_order == m_data->rel_order)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
133
Utilities/StrUtil.h
Normal 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);
|
||||
}
|
@ -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
1037
Utilities/geometry.h
Normal file
File diff suppressed because it is too large
Load Diff
1351
Utilities/types.h
1351
Utilities/types.h
File diff suppressed because it is too large
Load Diff
@ -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 ",?????";
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#include "sceLibKernel.h"
|
||||
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
LOG_CHANNEL(sceLibKernel);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
@ -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)
|
||||
|
@ -1,5 +1,6 @@
|
||||
#ifdef _WIN32
|
||||
#include "Utilities/Log.h"
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "cellGame.h"
|
||||
|
||||
#include "Loader/PSF.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
LOG_CHANNEL(cellGame);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/BitField.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
enum
|
||||
|
@ -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",
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "cellSaveData.h"
|
||||
|
||||
#include "Loader/PSF.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
LOG_CHANNEL(cellSaveData);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include "cellSync2.h"
|
||||
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
LOG_CHANNEL(cellSync2);
|
||||
|
||||
vm::gvar<CellSync2CallerThreadType> gCellSync2CallerThreadTypePpuThread;
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#include "cellSysutil.h"
|
||||
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
LOG_CHANNEL(cellSysutil);
|
||||
|
||||
// Temporarily
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include "cellUserInfo.h"
|
||||
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
LOG_CHANNEL(cellUserInfo);
|
||||
|
||||
s32 cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
119
rpcs3/Emu/IdManager.cpp
Normal 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();
|
||||
}
|
||||
}
|
@ -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>();
|
||||
}
|
||||
|
||||
// Update optional ID storage
|
||||
template<typename T>
|
||||
static auto set_id_value(T* ptr, u32 id) -> decltype(static_cast<void>(std::declval<T&>().id))
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
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>
|
||||
|
@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
enum class FUNCTION {
|
||||
FUNCTION_DP2,
|
||||
FUNCTION_DP2A,
|
||||
|
@ -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);
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "OpenGL.h"
|
||||
#include "../GCM.h"
|
||||
|
||||
#include "Utilities/geometry.h"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "rsx_methods.h"
|
||||
|
||||
#include "Utilities/GSL.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#define CMD_DEBUG 0
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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/");
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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&)
|
||||
|
@ -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);
|
||||
|
@ -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, "" },
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
@ -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);
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user