Header optimizations (#1684)

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

253
Utilities/BitSet.h Normal file
View File

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

View File

@ -296,11 +296,11 @@ namespace cfg
std::string to_string() const override 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 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; return true;
} }
} }
@ -325,9 +325,9 @@ namespace cfg
{ {
std::vector<std::string> result; 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; return result;

View File

@ -5,6 +5,7 @@
#include <unordered_map> #include <unordered_map>
#include <algorithm> #include <algorithm>
#include <cerrno>
#ifdef _WIN32 #ifdef _WIN32
@ -90,6 +91,8 @@ static time_t to_time(const FILETIME& ft)
namespace fs namespace fs
{ {
thread_local uint error = 0;
class device_manager final class device_manager final
{ {
mutable shared_mutex m_mutex; 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 // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) switch (DWORD error = GetLastError())
{ {
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
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); 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; struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0) if (::stat(path.c_str(), &file_info) != 0)
{ {
fs::error = errno;
return false; return false;
} }
@ -259,8 +263,8 @@ bool fs::exists(const std::string& path)
// TODO: convert Win32 error code to errno // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) switch (DWORD error = GetLastError())
{ {
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
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); 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; return true;
#else #else
struct ::stat file_info; 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 #endif
} }
@ -286,7 +296,7 @@ bool fs::is_file(const std::string& path)
if (info.is_directory) if (info.is_directory)
{ {
errno = EEXIST; fs::error = EEXIST;
return false; return false;
} }
@ -300,8 +310,8 @@ bool fs::is_file(const std::string& path)
// TODO: convert Win32 error code to errno // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) switch (DWORD error = GetLastError())
{ {
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
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); 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; struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0) if (::stat(path.c_str(), &file_info) != 0)
{ {
fs::error = errno;
return false; return false;
} }
#endif #endif
@ -322,7 +333,7 @@ bool fs::is_file(const std::string& path)
if (S_ISDIR(file_info.st_mode)) if (S_ISDIR(file_info.st_mode))
#endif #endif
{ {
errno = EEXIST; fs::error = EEXIST;
return false; return false;
} }
@ -341,7 +352,7 @@ bool fs::is_dir(const std::string& path)
if (info.is_directory == false) if (info.is_directory == false)
{ {
errno = EEXIST; fs::error = EEXIST;
return false; return false;
} }
@ -355,8 +366,8 @@ bool fs::is_dir(const std::string& path)
// TODO: convert Win32 error code to errno // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) switch (DWORD error = GetLastError())
{ {
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
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); 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; struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0) if (::stat(path.c_str(), &file_info) != 0)
{ {
fs::error = errno;
return false; return false;
} }
#endif #endif
@ -376,7 +388,7 @@ bool fs::is_dir(const std::string& path)
if (!S_ISDIR(file_info.st_mode)) if (!S_ISDIR(file_info.st_mode))
#endif #endif
{ {
errno = EEXIST; fs::error = EEXIST;
return false; return false;
} }
@ -396,8 +408,8 @@ bool fs::create_dir(const std::string& path)
// TODO: convert Win32 error code to errno // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) switch (DWORD error = GetLastError())
{ {
case ERROR_ALREADY_EXISTS: errno = EEXIST; break; case ERROR_ALREADY_EXISTS: fs::error = EEXIST; break;
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); 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; return true;
#else #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 #endif
} }
@ -435,7 +453,7 @@ bool fs::remove_dir(const std::string& path)
// TODO: convert Win32 error code to errno // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) 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); 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; return true;
#else #else
return !::rmdir(path.c_str()); if (::rmdir(path.c_str()) != 0)
{
fs::error = errno;
return false;
}
return true;
#endif #endif
} }
@ -468,7 +492,7 @@ bool fs::rename(const std::string& from, const std::string& to)
// TODO: convert Win32 error code to errno // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) 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); 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; return true;
#else #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 #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 // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) 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); 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); const int input = ::open(from.c_str(), O_RDONLY);
if (input == -1) if (input == -1)
{ {
fs::error = errno;
return false; return false;
} }
@ -519,7 +550,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
const int err = errno; const int err = errno;
::close(input); ::close(input);
errno = err; fs::error = err;
return false; return false;
} }
@ -538,7 +569,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
::close(input); ::close(input);
::close(output); ::close(output);
errno = err; fs::error = err;
return false; return false;
} }
@ -561,8 +592,8 @@ bool fs::remove_file(const std::string& path)
// TODO: convert Win32 error code to errno // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) switch (DWORD error = GetLastError())
{ {
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
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); 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; return true;
#else #else
return !::unlink(path.c_str()); if (::unlink(path.c_str()) != 0)
{
fs::error = errno;
return false;
}
return true;
#endif #endif
} }
@ -590,8 +627,8 @@ bool fs::truncate_file(const std::string& path, u64 length)
// TODO: convert Win32 error code to errno // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) switch (DWORD error = GetLastError())
{ {
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
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); 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 // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) 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); 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); CloseHandle(handle);
return true; return true;
#else #else
return !::truncate(path.c_str(), length); if (::truncate(path.c_str(), length) != 0)
{
fs::error = errno;
return false;
}
return true;
#endif #endif
} }
@ -629,10 +672,10 @@ void fs::file::xnull() const
void fs::file::xfail() 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)) 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) if (mode & fs::excl)
{ {
errno = EINVAL; fs::error = EINVAL;
return false; 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 // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) switch (DWORD error = GetLastError())
{ {
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_FILE_EXISTS: errno = EEXIST; break; case ERROR_FILE_EXISTS: fs::error = EEXIST; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); 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 // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) 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); 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) if (fd == -1)
{ {
// TODO: errno // TODO: errno
fs::error = errno;
return false; return false;
} }
@ -1086,8 +1130,8 @@ bool fs::dir::open(const std::string& path)
// TODO: convert Win32 error code to errno // TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError()) switch (DWORD error = GetLastError())
{ {
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
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." HERE, error); default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
} }
@ -1162,6 +1206,7 @@ bool fs::dir::open(const std::string& path)
if (!ptr) if (!ptr)
{ {
// TODO: errno // TODO: errno
fs::error = errno;
return false; return false;
} }

View File

@ -6,9 +6,13 @@
#include <type_traits> #include <type_traits>
#include "types.h" #include "types.h"
#include "BitSet.h"
namespace fs namespace fs
{ {
// Error code returned
extern thread_local uint error;
// File open mode flags // File open mode flags
enum struct open_mode : u32 enum struct open_mode : u32
{ {
@ -20,14 +24,14 @@ namespace fs
excl, excl,
}; };
constexpr mset<open_mode> read = open_mode::read; // Enable reading constexpr bitset_t<open_mode> read = open_mode::read; // Enable reading
constexpr mset<open_mode> write = open_mode::write; // Enable writing constexpr bitset_t<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 bitset_t<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 bitset_t<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 bitset_t<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> 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 // File seek mode
enum class seek_mode : u32 enum class seek_mode : u32
@ -92,7 +96,7 @@ namespace fs
virtual bool remove(const std::string& path) = 0; virtual bool remove(const std::string& path) = 0;
virtual bool trunc(const std::string& path, u64 length) = 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; virtual std::unique_ptr<dir_base> open_dir(const std::string& path) = 0;
}; };
@ -150,13 +154,13 @@ namespace fs
file() = default; file() = default;
// Open file with specified mode // 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(path, mode);
} }
// Open file with specified 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 // Open memory for read
explicit file(const void* ptr, std::size_t size); explicit file(const void* ptr, std::size_t size);

View File

@ -1,8 +1,53 @@
#include "Log.h" #include "Log.h"
#include "File.h"
#include "StrFmt.h"
#include <cstdarg> #include <cstdarg>
#include <string>
// Thread-specific log prefix provider
thread_local std::string(*g_tls_log_prefix)() = nullptr;
namespace _log 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() static file_listener& get_logger()
{ {
// Use magic static // Use magic static
@ -10,8 +55,6 @@ namespace _log
return logger; return logger;
} }
file_writer g_tty_file("TTY.log");
channel GENERAL(nullptr, level::notice); channel GENERAL(nullptr, level::notice);
channel LOADER("LDR", level::notice); channel LOADER("LDR", level::notice);
channel MEMORY("MEM", level::notice); channel MEMORY("MEM", level::notice);
@ -20,15 +63,13 @@ namespace _log
channel PPU("PPU", level::notice); channel PPU("PPU", level::notice);
channel SPU("SPU", level::notice); channel SPU("SPU", level::notice);
channel ARMv7("ARMv7"); 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...) void _log::channel::broadcast(const _log::channel& ch, _log::level sev, const char* fmt...)
{ {
va_list args; va_list args;
va_start(args, fmt); 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); 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)) 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 (...) catch (...)
@ -78,10 +119,10 @@ void _log::file_listener::log(const _log::channel& ch, _log::level sev, const st
// TODO: print time? // TODO: print time?
if (auto func = g_tls_make_prefix) if (auto prefix = g_tls_log_prefix)
{ {
msg += '{'; msg += '{';
msg += func(ch, sev, text); msg += prefix();
msg += "} "; msg += "} ";
} }

View File

@ -2,8 +2,6 @@
#include "types.h" #include "types.h"
#include "Atomic.h" #include "Atomic.h"
#include "File.h"
#include "StrFmt.h"
namespace _log namespace _log
{ {
@ -19,10 +17,6 @@ namespace _log
trace, // lowest level (usually disabled) trace, // lowest level (usually disabled)
}; };
struct channel;
struct listener;
// Log channel
struct channel struct channel
{ {
// Channel prefix (added to every log message) // Channel prefix (added to every log message)
@ -33,23 +27,20 @@ namespace _log
// Constant initialization: name and initial log level // Constant initialization: name and initial log level
constexpr channel(const char* name, level enabled = level::trace) constexpr channel(const char* name, level enabled = level::trace)
: name{ name } : name(name)
, enabled{ enabled } , enabled(enabled)
{ {
} }
// Log without formatting // Formatting function
void log(level sev, const std::string& text) const
{
if (sev <= enabled)
broadcast(*this, sev, "%s", text.c_str());
}
// Log with formatting
template<typename... Args> template<typename... Args>
void format(level sev, const char* fmt, const Args&... args) const void format(level sev, const char* fmt, const Args&... args) const
{ {
#ifdef _MSC_VER
if (sev <= enabled) if (sev <= enabled)
#else
if (__builtin_expect(sev <= enabled, 0))
#endif
broadcast(*this, sev, fmt, ::unveil<Args>::get(args)...); 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...); static void broadcast(const channel& ch, level sev, const char* fmt...);
}; };
// Log listener (destination) /* Small set of predefined channels */
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:
extern channel GENERAL; extern channel GENERAL;
extern channel LOADER; extern channel LOADER;
@ -127,14 +76,12 @@ namespace _log
extern channel PPU; extern channel PPU;
extern channel SPU; extern channel SPU;
extern channel ARMv7; extern channel ARMv7;
extern thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&);
} }
template<> template<>
struct bijective<_log::level, const char*> 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::always, "Nothing" },
{ _log::level::fatal, "Fatal" }, { _log::level::fatal, "Fatal" },

View File

@ -75,5 +75,6 @@ constexpr std::uint32_t size32(const T(&)[Size])
#define Expects ASSERT #define Expects ASSERT
#define Ensures 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 #define STR_CASE(value) case value: return #value

View File

@ -88,114 +88,6 @@ inline std::uint64_t cntlz64(std::uint64_t arg)
#endif #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 // Helper function, used by ""_u16, ""_u32, ""_u64
constexpr std::uint8_t to_u8(char c) constexpr std::uint8_t to_u8(char c)
{ {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
#include "StrFmt.h" #include "StrFmt.h"
#include "BEType.h" #include "BEType.h"
#include "StrUtil.h"
#include <cassert> #include <cassert>
#include <array> #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]); 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) std::string fmt::unsafe_vformat(const char* fmt, va_list _args) noexcept
{
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
{ {
// Fixed stack buffer for the first attempt // Fixed stack buffer for the first attempt
std::array<char, 4096> fixed_buf; 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_list args;
va_start(args, fmt); va_start(args, fmt);
auto result = fmt::_vformat(fmt, args); auto result = unsafe_vformat(fmt, args);
va_end(args); va_end(args);
return result; return result;
} }
fmt::exception_base::exception_base(const char* fmt...) 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); 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); return source.substr(begin, source.find_last_not_of(values) + 1);
} }
std::string fmt::escape(const std::string& source, std::initializer_list<char> more) std::string fmt::to_upper(const std::string& string)
{
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 result; std::string result;
result.resize(string.size());
for (auto it = source.begin(); it != source.end();) std::transform(string.begin(), string.end(), result.begin(), ::toupper);
{
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;
}
}
return result; return result;
} }

View File

@ -2,114 +2,21 @@
#include <cstdarg> #include <cstdarg>
#include <string> #include <string>
#include <vector> #include <exception>
#include <functional>
#include "Platform.h" #include "Platform.h"
#include "types.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 namespace fmt
{ {
std::string replace_first(const std::string& src, const std::string& from, const std::string& to); std::string unsafe_format(const char* fmt...) noexcept;
std::string replace_all(const std::string &src, const std::string& from, const std::string& to); std::string unsafe_vformat(const char*, va_list) noexcept;
template<size_t list_size> // Formatting function
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)
template<typename... Args> 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 // Helper class
@ -143,86 +50,4 @@ namespace fmt
if (static_cast<From>(result) != value) throw fmt::exception(format_str, value, args...); if (static_cast<From>(result) != value) throw fmt::exception(format_str, value, args...);
return result; return result;
} }
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
std::string trim(const std::string& source, const std::string& values = " \t");
template<typename T>
std::string merge(const T& source, const std::string& separator)
{
if (!source.size())
{
return{};
}
std::string result;
auto it = source.begin();
auto end = source.end();
for (--end; it != end; ++it)
{
result += *it + separator;
}
return result + source.back();
}
template<typename T>
std::string merge(std::initializer_list<T> sources, const std::string& separator)
{
if (!sources.size())
{
return{};
}
std::string result;
bool first = true;
for (auto &v : sources)
{
if (first)
{
result = fmt::merge(v, separator);
first = false;
}
else
{
result += separator + fmt::merge(v, separator);
}
}
return result;
}
template<typename IT>
std::string to_lower(IT _begin, IT _end)
{
std::string result; result.resize(_end - _begin);
std::transform(_begin, _end, result.begin(), ::tolower);
return result;
}
template<typename T>
std::string to_lower(const T& string)
{
return to_lower(std::begin(string), std::end(string));
}
template<typename IT>
std::string to_upper(IT _begin, IT _end)
{
std::string result; result.resize(_end - _begin);
std::transform(_begin, _end, result.begin(), ::toupper);
return result;
}
template<typename T>
std::string to_upper(const T& string)
{
return to_upper(std::begin(string), std::end(string));
}
std::string escape(const std::string& source, std::initializer_list<char> more = {});
std::string unescape(const std::string& source);
bool match(const std::string &source, const std::string &mask);
} }

133
Utilities/StrUtil.h Normal file
View File

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

View File

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

1037
Utilities/geometry.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -57,6 +57,35 @@ arm_static_module::arm_static_module(const char* name)
arm_module_manager::register_module(this); 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() static void arm_initialize_modules()
{ {
const std::initializer_list<const arm_static_module*> registered const std::initializer_list<const arm_static_module*> registered

View File

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

View File

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

View File

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

View File

@ -8,6 +8,8 @@
LOG_CHANNEL(sceLibc); LOG_CHANNEL(sceLibc);
extern fs::file g_tty;
// TODO // TODO
vm::ptr<void> g_dso; 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; 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; continue;
} }
case 'x': case 'x':
@ -111,7 +113,7 @@ std::string arm_fmt(ARMv7Thread& cpu, vm::cptr<char> fmt, u32 g_count)
result += cf == 'x' ? "0x" : "0X"; 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) if (hex.length() >= width)
{ {
@ -211,7 +213,10 @@ namespace sce_libc_func
const std::string& result = arm_fmt(cpu, fmt, va_args.count); const std::string& result = arm_fmt(cpu, fmt, va_args.count);
sceLibc.trace("*** -> '%s'", result); 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) void sprintf(ARMv7Thread& cpu, vm::ptr<char> str, vm::cptr<char> fmt, arm_va_args_t va_args)

View File

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

View File

@ -108,7 +108,7 @@ bool cpu_thread::check_status()
const auto state_ = state.load(); 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; return true;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "Utilities/BitField.h"
namespace vm { using namespace ps3; } namespace vm { using namespace ps3; }
// Return Codes // Return Codes
@ -374,23 +376,6 @@ struct alignas(128) CellSyncLFQueue
vm::bptr<void, u64> m_eaSignal; // 0x70 vm::bptr<void, u64> m_eaSignal; // 0x70
be_t<u32> m_v2; // 0x78 be_t<u32> m_v2; // 0x78
be_t<u32> m_eq_id; // 0x7C 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); CHECK_SIZE_ALIGN(CellSyncLFQueue, 128, 128);

View File

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

View File

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

View File

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

View File

@ -24,7 +24,7 @@ cfg::map_entry<u8> g_cfg_video_out_aspect_ratio(cfg::root.video, "Aspect ratio",
{ "16x9", CELL_VIDEO_OUT_ASPECT_16_9 }, { "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_1080, { 1920, 1080 } },
{ CELL_VIDEO_OUT_RESOLUTION_720, { 1280, 720 } }, { 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->resolutionId = g_cfg_video_out_resolution.get();
config->format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8; config->format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8;
config->aspect = g_cfg_video_out_aspect_ratio.get(); 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; return CELL_OK;

View File

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

View File

@ -10,6 +10,8 @@ LOG_CHANNEL(sysPrxForUser);
extern u64 get_system_time(); extern u64 get_system_time();
extern fs::file g_tty;
vm::gvar<s32> sys_prx_version; // ??? vm::gvar<s32> sys_prx_version; // ???
#define TLS_SYS 0x30 #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); 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; return CELL_OK;
} }

View File

@ -3,6 +3,8 @@
extern _log::channel sysPrxForUser; extern _log::channel sysPrxForUser;
extern fs::file g_tty;
// TODO // TODO
static std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count) 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; 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; continue;
} }
case 'x': 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"; 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) 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; 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; 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); 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; return CELL_OK;
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -3,6 +3,7 @@
#include "PPUThread.h" #include "PPUThread.h"
#include "PPUInterpreter.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 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 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); } 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; } inline u64 dup32(const u32 x) { return x | static_cast<u64>(x) << 32; }
#if defined(__GNUG__) #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)); __asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b));
return result; 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)); __asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b));
return result; return result;
} }
@ -30,6 +31,95 @@ inline std::int64_t MULH64(std::int64_t a, std::int64_t b)
#define MULH64 __mulh #define MULH64 __mulh
#endif #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 u64 get_timebased_time();
extern void ppu_execute_syscall(PPUThread& ppu, u64 code); extern void ppu_execute_syscall(PPUThread& ppu, u64 code);
extern void ppu_execute_function(PPUThread& ppu, u32 index); extern void ppu_execute_function(PPUThread& ppu, u32 index);

View File

@ -80,6 +80,35 @@ ppu_static_module::ppu_static_module(const char* name)
ppu_module_manager::register_module(this); 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. // Initialize static modules.
static void ppu_initialize_modules() static void ppu_initialize_modules()
{ {

View File

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

View File

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

View File

@ -2184,7 +2184,7 @@ void spu_recompiler::BR(spu_opcode_t op)
c->mov(*addr, target | 0x2000000); c->mov(*addr, target | 0x2000000);
//c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self //c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self
//c->je(labels[target / 4]); //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->jmp(*end);
c->unuse(*addr); c->unuse(*addr);
return; return;

View File

@ -7,6 +7,26 @@
#include <fenv.h> #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) void spu_interpreter::UNK(SPUThread& spu, spu_opcode_t op)
{ {
throw EXCEPTION("Unknown/Illegal instruction (0x%08x)", op.opcode); throw EXCEPTION("Unknown/Illegal instruction (0x%08x)", op.opcode);

View File

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

View File

@ -84,7 +84,8 @@ public:
const u64 name; const u64 name;
const u64 ipc_key; const u64 ipc_key;
const s32 size; 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) lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size)
: protocol(protocol) : protocol(protocol)

View File

@ -7,6 +7,9 @@
#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/ErrorCodes.h"
#include "sys_fs.h" #include "sys_fs.h"
#include "Utilities/StrUtil.h"
#include <cerrno>
LOG_CHANNEL(sys_fs); LOG_CHANNEL(sys_fs);
s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6) 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; return CELL_FS_EISDIR;
} }
mset<fs::open_mode> open_mode{}; bitset_t<fs::open_mode> open_mode{};
switch (flags & CELL_FS_O_ACCMODE) 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()))) if (!fs::remove_dir(vfs::get(path.get_ptr())))
{ {
switch (auto error = errno) switch (auto error = fs::error)
{ {
case ENOENT: return CELL_FS_ENOENT; case ENOENT: return CELL_FS_ENOENT;
default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error); 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()))) if (!fs::remove_file(vfs::get(path.get_ptr())))
{ {
switch (auto error = errno) switch (auto error = fs::error)
{ {
case ENOENT: return CELL_FS_ENOENT; case ENOENT: return CELL_FS_ENOENT;
default: sys_fs.error("sys_fs_unlink(): unknown error %d", error); 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)) 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; case ENOENT: return CELL_FS_ENOENT;
default: sys_fs.error("sys_fs_truncate(): unknown error %d", error); 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)) if (!file->file.trunc(size))
{ {
switch (auto error = errno) switch (auto error = fs::error)
{ {
case 0: case 0:
default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error); default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,6 +8,8 @@
LOG_CHANNEL(sys_tty); 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) 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); 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; return CELL_OK;
} }
_log::g_tty_file.log({ buf.get_ptr(), len }); if (g_tty)
{
g_tty.write(buf.get_ptr(), len);
}
*pwritelen = len; *pwritelen = len;

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

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

View File

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

View File

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

View File

@ -680,7 +680,7 @@ void GLGSRender::flip(int buffer)
coordi aspect_ratio; coordi aspect_ratio;
if (1) //enable 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; sizei new_size = csize;
const double aq = (double)buffer_width / buffer_height; const double aq = (double)buffer_width / buffer_height;
@ -702,7 +702,7 @@ void GLGSRender::flip(int buffer)
} }
else 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); gl::screen.clear(gl::buffers::color_depth_stencil);

View File

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

View File

@ -7,7 +7,7 @@
// temporarily (u8 value is really CellVideoOutResolutionId, but HLE declarations shouldn't be available for the rest of emu, even indirectly) // 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 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() draw_context_t GSFrameBase::new_context()
{ {
@ -20,8 +20,9 @@ draw_context_t GSFrameBase::new_context()
} }
GSRender::GSRender(frame_type type) 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() GSRender::~GSRender()

View File

@ -37,7 +37,8 @@ public:
virtual void set_current(draw_context_t ctx) = 0; virtual void set_current(draw_context_t ctx) = 0;
virtual void flip(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; virtual void* handle() const = 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@ struct EmuCallbacks
std::function<std::shared_ptr<class KeyboardHandlerBase>()> get_kb_handler; std::function<std::shared_ptr<class KeyboardHandlerBase>()> get_kb_handler;
std::function<std::shared_ptr<class MouseHandlerBase>()> get_mouse_handler; std::function<std::shared_ptr<class MouseHandlerBase>()> get_mouse_handler;
std::function<std::shared_ptr<class PadHandlerBase>()> get_pad_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 GSRender>()> get_gs_render;
std::function<std::shared_ptr<class AudioThread>()> get_audio; std::function<std::shared_ptr<class AudioThread>()> get_audio;
std::function<std::shared_ptr<class MsgDialogBase>()> get_msg_dialog; std::function<std::shared_ptr<class MsgDialogBase>()> get_msg_dialog;

View File

@ -4,6 +4,8 @@
#include "VFS.h" #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_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_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/"); cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/");

View File

@ -169,7 +169,7 @@ void LogFrame::OnTimer(wxTimerEvent& event)
const auto start = std::chrono::high_resolution_clock::now(); const auto start = std::chrono::high_resolution_clock::now();
// Check TTY logs // 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); const wxString& text = get_utf8(m_tty_file, size);

View File

@ -7,8 +7,8 @@
extern cfg::bool_entry g_cfg_rsx_debug_output; extern cfg::bool_entry g_cfg_rsx_debug_output;
GLGSFrame::GLGSFrame(size2i size) GLGSFrame::GLGSFrame(int w, int h)
: GSFrame("OpenGL", size) : GSFrame("OpenGL", w, h)
{ {
const int context_attrs[] = const int context_attrs[] =
{ {
@ -26,7 +26,7 @@ GLGSFrame::GLGSFrame(size2i size)
0 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); m_canvas->Bind(wxEVT_LEFT_DCLICK, &GSFrame::OnLeftDclick, this);
} }

View File

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

View File

@ -12,12 +12,12 @@ BEGIN_EVENT_TABLE(GSFrame, wxFrame)
EVT_SIZE(GSFrame::OnSize) EVT_SIZE(GSFrame::OnSize)
END_EVENT_TABLE() 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 + "]") : wxFrame(nullptr, wxID_ANY, "GSFrame[" + title + "]")
{ {
SetIcon(wxGetApp().m_MainFrame->GetIcon()); SetIcon(wxGetApp().m_MainFrame->GetIcon());
SetClientSize(size.width, size.height); SetClientSize(w, h);
wxGetApp().Bind(wxEVT_KEY_DOWN, &GSFrame::OnKeyDown, this); wxGetApp().Bind(wxEVT_KEY_DOWN, &GSFrame::OnKeyDown, this);
Bind(wxEVT_CLOSE_WINDOW, &GSFrame::OnClose, this); Bind(wxEVT_CLOSE_WINDOW, &GSFrame::OnClose, this);
Bind(wxEVT_LEFT_DCLICK, &GSFrame::OnLeftDclick, 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 GetClientSize().GetWidth();
return{ size.GetWidth(), size.GetHeight() }; }
int GSFrame::client_height()
{
return GetClientSize().GetHeight();
} }
void GSFrame::flip(draw_context_t) void GSFrame::flip(draw_context_t)

View File

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

View File

@ -453,7 +453,7 @@ void InterpreterDisAsmFrame::DoStep(wxCommandEvent& WXUNUSED(event))
{ {
if (cpu) 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; state += cpu_state::dbg_step;
return state.test_and_reset(cpu_state::dbg_pause); return state.test_and_reset(cpu_state::dbg_pause);

View File

@ -157,7 +157,7 @@ enum class elf_error
template<> template<>
struct bijective<elf_error, const char*> 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, "" }, { elf_error::ok, "" },

View File

@ -16,7 +16,7 @@ bool TRPLoader::Install(const std::string& dest, bool show)
const std::string& local_path = vfs::get(dest); 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; return false;
} }

View File

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

View File

@ -851,6 +851,9 @@
<ClCompile Include="Emu\Memory\wait_engine.cpp"> <ClCompile Include="Emu\Memory\wait_engine.cpp">
<Filter>Emu\Memory</Filter> <Filter>Emu\Memory</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\IdManager.cpp">
<Filter>Emu</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Crypto\aes.h"> <ClInclude Include="Crypto\aes.h">
@ -1606,5 +1609,14 @@
<ClInclude Include="Emu\Cell\lv2\IPC.h"> <ClInclude Include="Emu\Cell\lv2\IPC.h">
<Filter>Emu\Cell\lv2</Filter> <Filter>Emu\Cell\lv2</Filter>
</ClInclude> </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> </ItemGroup>
</Project> </Project>

View File

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

View File

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