Compare commits

..

1 Commits

Author SHA1 Message Date
Sorab
923c17f1ae Add Game Icon for Discord RPC
Connected to Yuzu Compatibility Page
2023-02-05 12:40:57 +11:00
49 changed files with 485 additions and 615 deletions

View File

@@ -10,7 +10,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dis
fi
# Default clang-format points to default 3.5 version one
CLANG_FORMAT=${CLANG_FORMAT:-clang-format-15}
CLANG_FORMAT=${CLANG_FORMAT:-clang-format-12}
$CLANG_FORMAT --version
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then

View File

@@ -2,12 +2,15 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Download all pull requests as patches that match a specific label
# Usage: python apply-patches-by-label.py <Label to Match>
# Usage: python download-patches-by-label.py <Label to Match> <Root Path Folder to DL to>
import json, requests, subprocess, sys, traceback
import requests, sys, json, urllib3.request, shutil, subprocess, os, traceback
tagline = sys.argv[2]
http = urllib3.PoolManager()
dl_list = {}
def check_individual(labels):
for label in labels:
if (label["name"] == sys.argv[1]):
@@ -15,9 +18,8 @@ def check_individual(labels):
return False
def do_page(page):
url = f"https://api.github.com/repos/yuzu-emu/yuzu/pulls?page={page}"
url = 'https://api.github.com/repos/yuzu-emu/yuzu/pulls?page=%s' % page
response = requests.get(url)
response.raise_for_status()
if (response.ok):
j = json.loads(response.content)
if j == []:
@@ -25,13 +27,13 @@ def do_page(page):
for pr in j:
if (check_individual(pr["labels"])):
pn = pr["number"]
print(f"Matched PR# {pn}")
print(subprocess.check_output(["git", "fetch", "https://github.com/yuzu-emu/yuzu.git", f"pull/{pn}/head:pr-{pn}", "-f", "--no-recurse-submodules"]))
print(subprocess.check_output(["git", "merge", "--squash", f"pr-{pn}"]))
print(subprocess.check_output(["git", "commit", f"-m\"Merge {tagline} PR {pn}\""]))
print("Matched PR# %s" % pn)
print(subprocess.check_output(["git", "fetch", "https://github.com/yuzu-emu/yuzu.git", "pull/%s/head:pr-%s" % (pn, pn), "-f", "--no-recurse-submodules"]))
print(subprocess.check_output(["git", "merge", "--squash", "pr-%s" % pn]))
print(subprocess.check_output(["git", "commit", "-m\"Merge %s PR %s\"" % (tagline, pn)]))
try:
for i in range(1,10):
for i in range(1,30):
do_page(i)
except:
traceback.print_exc(file=sys.stdout)

View File

@@ -12,8 +12,7 @@
namespace Common {
template <typename VaType, size_t AddressSpaceBits>
concept AddressSpaceValid = std::is_unsigned_v<VaType> && sizeof(VaType) * 8 >=
AddressSpaceBits;
concept AddressSpaceValid = std::is_unsigned_v<VaType> && sizeof(VaType) * 8 >= AddressSpaceBits;
struct EmptyStruct {};
@@ -22,7 +21,7 @@ struct EmptyStruct {};
*/
template <typename VaType, VaType UnmappedVa, typename PaType, PaType UnmappedPa,
bool PaContigSplit, size_t AddressSpaceBits, typename ExtraBlockInfo = EmptyStruct>
requires AddressSpaceValid<VaType, AddressSpaceBits>
requires AddressSpaceValid<VaType, AddressSpaceBits>
class FlatAddressSpaceMap {
public:
/// The maximum VA that this AS can technically reach
@@ -110,7 +109,7 @@ private:
* initial, fast linear pass and a subsequent slower pass that iterates until it finds a free block
*/
template <typename VaType, VaType UnmappedVa, size_t AddressSpaceBits>
requires AddressSpaceValid<VaType, AddressSpaceBits>
requires AddressSpaceValid<VaType, AddressSpaceBits>
class FlatAllocator
: public FlatAddressSpaceMap<VaType, UnmappedVa, bool, false, false, AddressSpaceBits> {
private:

View File

@@ -10,7 +10,7 @@
namespace Common {
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr T AlignUp(T value, size_t size) {
auto mod{static_cast<T>(value % size)};
value -= mod;
@@ -18,31 +18,31 @@ template <typename T>
}
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) {
return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2);
}
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr T AlignDown(T value, size_t size) {
return static_cast<T>(value - value % size);
}
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool Is4KBAligned(T value) {
return (value & 0xFFF) == 0;
}
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool IsWordAligned(T value) {
return (value & 0b11) == 0;
}
template <typename T>
requires std::is_integral_v<T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) {
using U = typename std::make_unsigned_t<T>;
const U mask = static_cast<U>(alignment - 1);
@@ -50,7 +50,7 @@ template <typename T>
}
template <typename T, typename U>
requires std::is_integral_v<T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr T DivideUp(T x, U y) {
return (x + (y - 1)) / y;
}
@@ -73,11 +73,11 @@ public:
constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
[[nodiscard]] T* allocate(size_type n) {
return static_cast<T*>(::operator new(n * sizeof(T), std::align_val_t{Align}));
return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align}));
}
void deallocate(T* p, size_type n) {
::operator delete(p, n * sizeof(T), std::align_val_t{Align});
::operator delete (p, n * sizeof(T), std::align_val_t{Align});
}
template <typename T2>

View File

@@ -75,7 +75,7 @@ extern "C" void AnnotateHappensAfter(const char*, int, void*);
#if defined(AE_VCPP) || defined(AE_ICC)
#define AE_FORCEINLINE __forceinline
#elif defined(AE_GCC)
// #define AE_FORCEINLINE __attribute__((always_inline))
//#define AE_FORCEINLINE __attribute__((always_inline))
#define AE_FORCEINLINE inline
#else
#define AE_FORCEINLINE inline

View File

@@ -45,19 +45,19 @@ template <typename T>
}
template <typename T>
requires std::is_unsigned_v<T>
requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool IsPow2(T value) {
return std::has_single_bit(value);
}
template <typename T>
requires std::is_integral_v<T>
requires std::is_integral_v<T>
[[nodiscard]] T NextPow2(T value) {
return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U)));
}
template <size_t bit_index, typename T>
requires std::is_integral_v<T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr bool Bit(const T value) {
static_assert(bit_index < BitSize<T>(), "bit_index must be smaller than size of T");
return ((value >> bit_index) & T(1)) == T(1);

View File

@@ -16,9 +16,9 @@ concept IsContiguousContainer = std::contiguous_iterator<typename T::iterator>;
// is available on all supported platforms.
template <typename Derived, typename Base>
concept DerivedFrom = requires {
std::is_base_of_v<Base, Derived>;
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
};
std::is_base_of_v<Base, Derived>;
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
};
// TODO: Replace with std::convertible_to when libc++ implements it.
template <typename From, typename To>

View File

@@ -10,14 +10,14 @@ namespace Common {
/// Ceiled integer division.
template <typename N, typename D>
requires std::is_integral_v<N> && std::is_unsigned_v<D>
requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeil(N number, D divisor) {
return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor);
}
/// Ceiled integer division with logarithmic divisor in base 2
template <typename N, typename D>
requires std::is_integral_v<N> && std::is_unsigned_v<D>
requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) {
return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
}

View File

@@ -64,7 +64,7 @@ struct no_init_t {
* Additionally, this requires E to be trivially destructible
*/
template <typename T, typename E, bool = std::is_trivially_destructible_v<T>>
requires std::is_trivially_destructible_v<E>
requires std::is_trivially_destructible_v<E>
struct expected_storage_base {
constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
@@ -111,7 +111,7 @@ struct expected_storage_base {
* Additionally, this requires E to be trivially destructible
*/
template <typename T, typename E>
requires std::is_trivially_destructible_v<E>
requires std::is_trivially_destructible_v<E>
struct expected_storage_base<T, E, true> {
constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
@@ -251,7 +251,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
* Additionally, this requires E to be trivially copy constructible
*/
template <typename T, typename E, bool = std::is_trivially_copy_constructible_v<T>>
requires std::is_trivially_copy_constructible_v<E>
requires std::is_trivially_copy_constructible_v<E>
struct expected_copy_base : expected_operations_base<T, E> {
using expected_operations_base<T, E>::expected_operations_base;
};
@@ -261,7 +261,7 @@ struct expected_copy_base : expected_operations_base<T, E> {
* Additionally, this requires E to be trivially copy constructible
*/
template <typename T, typename E>
requires std::is_trivially_copy_constructible_v<E>
requires std::is_trivially_copy_constructible_v<E>
struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
using expected_operations_base<T, E>::expected_operations_base;
@@ -289,7 +289,7 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
* Additionally, this requires E to be trivially move constructible
*/
template <typename T, typename E, bool = std::is_trivially_move_constructible_v<T>>
requires std::is_trivially_move_constructible_v<E>
requires std::is_trivially_move_constructible_v<E>
struct expected_move_base : expected_copy_base<T, E> {
using expected_copy_base<T, E>::expected_copy_base;
};
@@ -299,7 +299,7 @@ struct expected_move_base : expected_copy_base<T, E> {
* Additionally, this requires E to be trivially move constructible
*/
template <typename T, typename E>
requires std::is_trivially_move_constructible_v<E>
requires std::is_trivially_move_constructible_v<E>
struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
using expected_copy_base<T, E>::expected_copy_base;
@@ -330,9 +330,9 @@ template <typename T, typename E,
bool = std::conjunction_v<std::is_trivially_copy_assignable<T>,
std::is_trivially_copy_constructible<T>,
std::is_trivially_destructible<T>>>
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
std::is_trivially_copy_constructible<E>,
std::is_trivially_destructible<E>>
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
std::is_trivially_copy_constructible<E>,
std::is_trivially_destructible<E>>
struct expected_copy_assign_base : expected_move_base<T, E> {
using expected_move_base<T, E>::expected_move_base;
};
@@ -342,9 +342,9 @@ struct expected_copy_assign_base : expected_move_base<T, E> {
* Additionally, this requires E to be trivially copy assignable
*/
template <typename T, typename E>
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
std::is_trivially_copy_constructible<E>,
std::is_trivially_destructible<E>>
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
std::is_trivially_copy_constructible<E>,
std::is_trivially_destructible<E>>
struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
using expected_move_base<T, E>::expected_move_base;
@@ -371,9 +371,9 @@ template <typename T, typename E,
bool = std::conjunction_v<std::is_trivially_move_assignable<T>,
std::is_trivially_move_constructible<T>,
std::is_trivially_destructible<T>>>
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
std::is_trivially_move_constructible<E>,
std::is_trivially_destructible<E>>
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
std::is_trivially_move_constructible<E>,
std::is_trivially_destructible<E>>
struct expected_move_assign_base : expected_copy_assign_base<T, E> {
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
};
@@ -383,9 +383,9 @@ struct expected_move_assign_base : expected_copy_assign_base<T, E> {
* Additionally, this requires E to be trivially move assignable
*/
template <typename T, typename E>
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
std::is_trivially_move_constructible<E>,
std::is_trivially_destructible<E>>
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
std::is_trivially_move_constructible<E>,
std::is_trivially_destructible<E>>
struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E> {
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
@@ -412,7 +412,7 @@ struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E>
*/
template <typename T, typename E, bool EnableCopy = std::is_copy_constructible_v<T>,
bool EnableMove = std::is_move_constructible_v<T>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
@@ -422,7 +422,7 @@ struct expected_delete_ctor_base {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base<T, E, true, false> {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
@@ -432,7 +432,7 @@ struct expected_delete_ctor_base<T, E, true, false> {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base<T, E, false, true> {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
@@ -442,7 +442,7 @@ struct expected_delete_ctor_base<T, E, false, true> {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base<T, E, false, false> {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
@@ -460,8 +460,8 @@ template <
typename T, typename E,
bool EnableCopy = std::conjunction_v<std::is_copy_constructible<T>, std::is_copy_assignable<T>>,
bool EnableMove = std::conjunction_v<std::is_move_constructible<T>, std::is_move_assignable<T>>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -471,8 +471,8 @@ struct expected_delete_assign_base {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base<T, E, true, false> {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -482,8 +482,8 @@ struct expected_delete_assign_base<T, E, true, false> {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base<T, E, false, true> {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -493,8 +493,8 @@ struct expected_delete_assign_base<T, E, false, true> {
};
template <typename T, typename E>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base<T, E, false, false> {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;

View File

@@ -242,21 +242,19 @@ public:
template <typename T>
concept HasRedBlackKeyType = requires {
{
std::is_same<typename T::RedBlackKeyType, void>::value
} -> std::convertible_to<bool>;
};
{ std::is_same<typename T::RedBlackKeyType, void>::value } -> std::convertible_to<bool>;
};
namespace impl {
template <typename T, typename Default>
consteval auto* GetRedBlackKeyType() {
if constexpr (HasRedBlackKeyType<T>) {
return static_cast<typename T::RedBlackKeyType*>(nullptr);
} else {
return static_cast<Default*>(nullptr);
template <typename T, typename Default>
consteval auto* GetRedBlackKeyType() {
if constexpr (HasRedBlackKeyType<T>) {
return static_cast<typename T::RedBlackKeyType*>(nullptr);
} else {
return static_cast<Default*>(nullptr);
}
}
}
} // namespace impl

View File

@@ -9,19 +9,17 @@
namespace Common {
template <class T>
requires(!std::is_array_v<T>)
std::unique_ptr<T> make_unique_for_overwrite() {
requires(!std::is_array_v<T>) std::unique_ptr<T> make_unique_for_overwrite() {
return std::unique_ptr<T>(new T);
}
template <class T>
requires std::is_unbounded_array_v<T>
std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) {
requires std::is_unbounded_array_v<T> std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) {
return std::unique_ptr<T>(new std::remove_extent_t<T>[n]);
}
template <class T, class... Args>
requires std::is_bounded_array_v<T>
requires std::is_bounded_array_v<T>
void make_unique_for_overwrite(Args&&...) = delete;
} // namespace Common

View File

@@ -18,9 +18,9 @@ namespace ranges {
template <typename T>
concept range = requires(T& t) {
begin(t);
end(t);
};
begin(t);
end(t);
};
template <typename T>
concept input_range = range<T>;
@@ -421,7 +421,7 @@ struct generate_fn {
}
template <typename R, std::copy_constructible F>
requires std::invocable<F&> && ranges::output_range<R>
requires std::invocable<F&> && ranges::output_range<R>
constexpr ranges::iterator_t<R> operator()(R&& r, F gen) const {
return operator()(ranges::begin(r), ranges::end(r), std::move(gen));
}

View File

@@ -41,18 +41,17 @@ bool StoppableTimedWait(std::stop_token token, const std::chrono::duration<Rep,
#include <chrono>
#include <condition_variable>
#include <functional>
#include <map>
#include <list>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>
#include <type_traits>
#include <utility>
namespace std {
namespace polyfill {
using stop_state_callback = size_t;
using stop_state_callbacks = list<function<void()>>;
class stop_state {
public:
@@ -60,69 +59,61 @@ public:
~stop_state() = default;
bool request_stop() {
unique_lock lk{m_lock};
stop_state_callbacks callbacks;
if (m_stop_requested) {
// Already set, nothing to do.
return false;
{
scoped_lock lk{m_lock};
if (m_stop_requested.load()) {
// Already set, nothing to do
return false;
}
// Set as requested
m_stop_requested = true;
// Copy callback list
callbacks = m_callbacks;
}
// Mark stop requested.
m_stop_requested = true;
while (!m_callbacks.empty()) {
// Get an iterator to the first element.
const auto it = m_callbacks.begin();
// Move the callback function out of the map.
function<void()> f;
swap(it->second, f);
// Erase the now-empty map element.
m_callbacks.erase(it);
// Run the callback.
if (f) {
f();
}
for (auto callback : callbacks) {
callback();
}
return true;
}
bool stop_requested() const {
unique_lock lk{m_lock};
return m_stop_requested;
return m_stop_requested.load();
}
stop_state_callback insert_callback(function<void()> f) {
unique_lock lk{m_lock};
stop_state_callbacks::const_iterator insert_callback(function<void()> f) {
stop_state_callbacks::const_iterator ret{};
bool should_run{};
if (m_stop_requested) {
// Stop already requested. Don't insert anything,
// just run the callback synchronously.
if (f) {
f();
}
return 0;
{
scoped_lock lk{m_lock};
should_run = m_stop_requested.load();
m_callbacks.push_front(f);
ret = m_callbacks.begin();
}
if (should_run) {
f();
}
// Insert the callback.
stop_state_callback ret = ++m_next_callback;
m_callbacks.emplace(ret, move(f));
return ret;
}
void remove_callback(stop_state_callback cb) {
unique_lock lk{m_lock};
m_callbacks.erase(cb);
void remove_callback(stop_state_callbacks::const_iterator it) {
scoped_lock lk{m_lock};
m_callbacks.erase(it);
}
private:
mutable recursive_mutex m_lock;
map<stop_state_callback, function<void()>> m_callbacks;
stop_state_callback m_next_callback{0};
bool m_stop_requested{false};
mutex m_lock;
atomic<bool> m_stop_requested;
stop_state_callbacks m_callbacks;
};
} // namespace polyfill
@@ -213,7 +204,7 @@ public:
using callback_type = Callback;
template <typename C>
requires constructible_from<Callback, C>
requires constructible_from<Callback, C>
explicit stop_callback(const stop_token& st,
C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
: m_stop_state(st.m_stop_state) {
@@ -222,7 +213,7 @@ public:
}
}
template <typename C>
requires constructible_from<Callback, C>
requires constructible_from<Callback, C>
explicit stop_callback(stop_token&& st,
C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
: m_stop_state(move(st.m_stop_state)) {
@@ -232,7 +223,7 @@ public:
}
~stop_callback() {
if (m_stop_state && m_callback) {
m_stop_state->remove_callback(m_callback);
m_stop_state->remove_callback(*m_callback);
}
}
@@ -243,7 +234,7 @@ public:
private:
shared_ptr<polyfill::stop_state> m_stop_state;
polyfill::stop_state_callback m_callback;
optional<polyfill::stop_state_callbacks::const_iterator> m_callback;
};
template <typename Callback>

View File

@@ -131,8 +131,7 @@ public:
* @param default_val Intial value of the setting, and default value of the setting
* @param name Label for the setting
*/
explicit Setting(const Type& default_val, const std::string& name)
requires(!ranged)
explicit Setting(const Type& default_val, const std::string& name) requires(!ranged)
: value{default_val}, default_value{default_val}, label{name} {}
virtual ~Setting() = default;
@@ -145,8 +144,7 @@ public:
* @param name Label for the setting
*/
explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
const std::string& name)
requires(ranged)
const std::string& name) requires(ranged)
: value{default_val},
default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
@@ -234,8 +232,7 @@ public:
* @param default_val Intial value of the setting, and default value of the setting
* @param name Label for the setting
*/
explicit SwitchableSetting(const Type& default_val, const std::string& name)
requires(!ranged)
explicit SwitchableSetting(const Type& default_val, const std::string& name) requires(!ranged)
: Setting<Type>{default_val, name} {}
virtual ~SwitchableSetting() = default;
@@ -248,8 +245,7 @@ public:
* @param name Label for the setting
*/
explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
const std::string& name)
requires(ranged)
const std::string& name) requires(ranged)
: Setting<Type, true>{default_val, min_val, max_val, name} {}
/**

View File

@@ -103,12 +103,12 @@ concept IsRBEntry = CheckRBEntry<T>::value;
template <typename T>
concept HasRBEntry = requires(T& t, const T& ct) {
{ t.GetRBEntry() } -> std::same_as<RBEntry<T>&>;
{ ct.GetRBEntry() } -> std::same_as<const RBEntry<T>&>;
};
{ t.GetRBEntry() } -> std::same_as<RBEntry<T>&>;
{ ct.GetRBEntry() } -> std::same_as<const RBEntry<T>&>;
};
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
class RBHead {
private:
T* m_rbh_root = nullptr;
@@ -130,90 +130,90 @@ public:
};
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr RBEntry<T>& RB_ENTRY(T* t) {
return t->GetRBEntry();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr const RBEntry<T>& RB_ENTRY(const T* t) {
return t->GetRBEntry();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr T* RB_LEFT(T* t) {
return RB_ENTRY(t).Left();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr const T* RB_LEFT(const T* t) {
return RB_ENTRY(t).Left();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr T* RB_RIGHT(T* t) {
return RB_ENTRY(t).Right();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr const T* RB_RIGHT(const T* t) {
return RB_ENTRY(t).Right();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr T* RB_PARENT(T* t) {
return RB_ENTRY(t).Parent();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr const T* RB_PARENT(const T* t) {
return RB_ENTRY(t).Parent();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET_LEFT(T* t, T* e) {
RB_ENTRY(t).SetLeft(e);
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET_RIGHT(T* t, T* e) {
RB_ENTRY(t).SetRight(e);
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET_PARENT(T* t, T* e) {
RB_ENTRY(t).SetParent(e);
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr bool RB_IS_BLACK(const T* t) {
return RB_ENTRY(t).IsBlack();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr bool RB_IS_RED(const T* t) {
return RB_ENTRY(t).IsRed();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
[[nodiscard]] constexpr RBColor RB_COLOR(const T* t) {
return RB_ENTRY(t).Color();
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET_COLOR(T* t, RBColor c) {
RB_ENTRY(t).SetColor(c);
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET(T* elm, T* parent) {
auto& rb_entry = RB_ENTRY(elm);
rb_entry.SetParent(parent);
@@ -223,14 +223,14 @@ constexpr void RB_SET(T* elm, T* parent) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_SET_BLACKRED(T* black, T* red) {
RB_SET_COLOR(black, RBColor::RB_BLACK);
RB_SET_COLOR(red, RBColor::RB_RED);
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_ROTATE_LEFT(RBHead<T>& head, T* elm, T*& tmp) {
tmp = RB_RIGHT(elm);
if (RB_SET_RIGHT(elm, RB_LEFT(tmp)); RB_RIGHT(elm) != nullptr) {
@@ -252,7 +252,7 @@ constexpr void RB_ROTATE_LEFT(RBHead<T>& head, T* elm, T*& tmp) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_ROTATE_RIGHT(RBHead<T>& head, T* elm, T*& tmp) {
tmp = RB_LEFT(elm);
if (RB_SET_LEFT(elm, RB_RIGHT(tmp)); RB_LEFT(elm) != nullptr) {
@@ -274,7 +274,7 @@ constexpr void RB_ROTATE_RIGHT(RBHead<T>& head, T* elm, T*& tmp) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_REMOVE_COLOR(RBHead<T>& head, T* parent, T* elm) {
T* tmp;
while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head.Root()) {
@@ -358,7 +358,7 @@ constexpr void RB_REMOVE_COLOR(RBHead<T>& head, T* parent, T* elm) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_REMOVE(RBHead<T>& head, T* elm) {
T* child = nullptr;
T* parent = nullptr;
@@ -451,7 +451,7 @@ constexpr T* RB_REMOVE(RBHead<T>& head, T* elm) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr void RB_INSERT_COLOR(RBHead<T>& head, T* elm) {
T *parent = nullptr, *tmp = nullptr;
while ((parent = RB_PARENT(elm)) != nullptr && RB_IS_RED(parent)) {
@@ -499,7 +499,7 @@ constexpr void RB_INSERT_COLOR(RBHead<T>& head, T* elm) {
}
template <typename T, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_INSERT(RBHead<T>& head, T* elm, Compare cmp) {
T* parent = nullptr;
T* tmp = head.Root();
@@ -534,7 +534,7 @@ constexpr T* RB_INSERT(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_FIND(RBHead<T>& head, T* elm, Compare cmp) {
T* tmp = head.Root();
@@ -553,7 +553,7 @@ constexpr T* RB_FIND(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_NFIND(RBHead<T>& head, T* elm, Compare cmp) {
T* tmp = head.Root();
T* res = nullptr;
@@ -574,7 +574,7 @@ constexpr T* RB_NFIND(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename U, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_FIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
T* tmp = head.Root();
@@ -593,7 +593,7 @@ constexpr T* RB_FIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
}
template <typename T, typename U, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_NFIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
T* tmp = head.Root();
T* res = nullptr;
@@ -614,7 +614,7 @@ constexpr T* RB_NFIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
}
template <typename T, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_FIND_EXISTING(RBHead<T>& head, T* elm, Compare cmp) {
T* tmp = head.Root();
@@ -631,7 +631,7 @@ constexpr T* RB_FIND_EXISTING(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename U, typename Compare>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_FIND_EXISTING_KEY(RBHead<T>& head, const U& key, Compare cmp) {
T* tmp = head.Root();
@@ -648,7 +648,7 @@ constexpr T* RB_FIND_EXISTING_KEY(RBHead<T>& head, const U& key, Compare cmp) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_NEXT(T* elm) {
if (RB_RIGHT(elm)) {
elm = RB_RIGHT(elm);
@@ -669,7 +669,7 @@ constexpr T* RB_NEXT(T* elm) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_PREV(T* elm) {
if (RB_LEFT(elm)) {
elm = RB_LEFT(elm);
@@ -690,7 +690,7 @@ constexpr T* RB_PREV(T* elm) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_MIN(RBHead<T>& head) {
T* tmp = head.Root();
T* parent = nullptr;
@@ -704,7 +704,7 @@ constexpr T* RB_MIN(RBHead<T>& head) {
}
template <typename T>
requires HasRBEntry<T>
requires HasRBEntry<T>
constexpr T* RB_MAX(RBHead<T>& head) {
T* tmp = head.Root();
T* parent = nullptr;

View File

@@ -348,7 +348,9 @@ public:
// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
// component names (x<->r) and permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
[[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); }
[[nodiscard]] constexpr Vec2<T> name() const { \
return Vec2<T>(a, b); \
}
#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
_DEFINE_SWIZZLER2(a, b, a##b); \
_DEFINE_SWIZZLER2(a, b, a2##b2); \
@@ -541,7 +543,9 @@ public:
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
// permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
[[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); }
[[nodiscard]] constexpr Vec2<T> name() const { \
return Vec2<T>(a, b); \
}
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
_DEFINE_SWIZZLER2(a, a, a##a); \
_DEFINE_SWIZZLER2(a, a, a2##a2)
@@ -566,7 +570,9 @@ public:
#undef _DEFINE_SWIZZLER2
#define _DEFINE_SWIZZLER3(a, b, c, name) \
[[nodiscard]] constexpr Vec3<T> name() const { return Vec3<T>(a, b, c); }
[[nodiscard]] constexpr Vec3<T> name() const { \
return Vec3<T>(a, b, c); \
}
#define DEFINE_SWIZZLER3_COMP1(a, a2) \
_DEFINE_SWIZZLER3(a, a, a, a##a##a); \
_DEFINE_SWIZZLER3(a, a, a, a2##a2##a2)
@@ -635,8 +641,8 @@ template <typename T>
// linear interpolation via float: 0.0=begin, 1.0=end
template <typename X>
[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
const float t) {
[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{})
Lerp(const X& begin, const X& end, const float t) {
return begin * (1.f - t) + end * t;
}

View File

@@ -24,7 +24,9 @@ private:
friend class ::Kernel::KClassTokenGenerator; \
static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \
static constexpr inline const char* const TypeName = #CLASS; \
static constexpr inline ClassTokenType ClassToken() { return ::Kernel::ClassToken<CLASS>; } \
static constexpr inline ClassTokenType ClassToken() { \
return ::Kernel::ClassToken<CLASS>; \
} \
\
public: \
YUZU_NON_COPYABLE(CLASS); \
@@ -35,9 +37,15 @@ public:
constexpr ClassTokenType Token = ClassToken(); \
return TypeObj(TypeName, Token); \
} \
static constexpr const char* GetStaticTypeName() { return TypeName; } \
virtual TypeObj GetTypeObj() ATTRIBUTE { return GetStaticTypeObj(); } \
virtual const char* GetTypeName() ATTRIBUTE { return GetStaticTypeName(); } \
static constexpr const char* GetStaticTypeName() { \
return TypeName; \
} \
virtual TypeObj GetTypeObj() ATTRIBUTE { \
return GetStaticTypeObj(); \
} \
virtual const char* GetTypeName() ATTRIBUTE { \
return GetStaticTypeName(); \
} \
\
private: \
constexpr bool operator!=(const TypeObj& rhs)
@@ -237,8 +245,8 @@ public:
}
template <typename U>
requires(std::derived_from<T, U> || std::derived_from<U, T>)
constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
requires(std::derived_from<T, U> ||
std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
if constexpr (std::derived_from<U, T>) {
// Upcast.
m_obj = rhs.m_obj;

View File

@@ -17,41 +17,35 @@ namespace Kernel {
class KThread;
template <typename T>
concept KPriorityQueueAffinityMask = !
std::is_reference_v<T>&& requires(T& t) {
{ t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
{ t.SetAffinityMask(0) };
concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) {
{ t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
{t.SetAffinityMask(0)};
{ t.GetAffinity(0) } -> std::same_as<bool>;
{ t.SetAffinity(0, false) };
{ t.SetAll() };
};
{ t.GetAffinity(0) } -> std::same_as<bool>;
{t.SetAffinity(0, false)};
{t.SetAll()};
};
template <typename T>
concept KPriorityQueueMember = !
std::is_reference_v<T>&& requires(T& t) {
{ typename T::QueueEntry() };
{ (typename T::QueueEntry()).Initialize() };
{ (typename T::QueueEntry()).SetPrev(std::addressof(t)) };
{ (typename T::QueueEntry()).SetNext(std::addressof(t)) };
{ (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>;
{ (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>;
{
t.GetPriorityQueueEntry(0)
} -> std::same_as<typename T::QueueEntry&>;
concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
{typename T::QueueEntry()};
{(typename T::QueueEntry()).Initialize()};
{(typename T::QueueEntry()).SetPrev(std::addressof(t))};
{(typename T::QueueEntry()).SetNext(std::addressof(t))};
{ (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>;
{ (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>;
{ t.GetPriorityQueueEntry(0) } -> std::same_as<typename T::QueueEntry&>;
{ t.GetAffinityMask() };
{
std::remove_cvref_t<decltype(t.GetAffinityMask())>()
} -> KPriorityQueueAffinityMask;
{t.GetAffinityMask()};
{ std::remove_cvref_t<decltype(t.GetAffinityMask())>() } -> KPriorityQueueAffinityMask;
{ t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
{ t.GetPriority() } -> Common::ConvertibleTo<s32>;
{ t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
};
{ t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
{ t.GetPriority() } -> Common::ConvertibleTo<s32>;
{ t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
};
template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
requires KPriorityQueueMember<Member>
requires KPriorityQueueMember<Member>
class KPriorityQueue {
public:
using AffinityMaskType = std::remove_cv_t<

View File

@@ -9,14 +9,13 @@
namespace Kernel {
template <typename T>
concept KLockable = !
std::is_reference_v<T>&& requires(T& t) {
{ t.Lock() } -> std::same_as<void>;
{ t.Unlock() } -> std::same_as<void>;
};
concept KLockable = !std::is_reference_v<T> && requires(T & t) {
{ t.Lock() } -> std::same_as<void>;
{ t.Unlock() } -> std::same_as<void>;
};
template <typename T>
requires KLockable<T>
requires KLockable<T>
class [[nodiscard]] KScopedLock {
public:
explicit KScopedLock(T* l) : lock_ptr(l) {

View File

@@ -677,7 +677,7 @@ private:
union SyncObjectBuffer {
std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{};
std::array<Handle,
Svc::ArgumentHandleCountMax * (sizeof(KSynchronizationObject*) / sizeof(Handle))>
Svc::ArgumentHandleCountMax*(sizeof(KSynchronizationObject*) / sizeof(Handle))>
handles;
constexpr SyncObjectBuffer() {}
};
@@ -698,8 +698,10 @@ private:
};
template <typename T>
requires(std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
static constexpr int Compare(const T& lhs, const KThread& rhs) {
requires(
std::same_as<T, KThread> ||
std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs,
const KThread& rhs) {
const u64 l_key = lhs.GetConditionVariableKey();
const u64 r_key = rhs.GetConditionVariableKey();

View File

@@ -70,8 +70,10 @@ public:
}
template <typename T>
requires(std::same_as<T, KThreadLocalPage> || std::same_as<T, RedBlackKeyType>)
static constexpr int Compare(const T& lhs, const KThreadLocalPage& rhs) {
requires(std::same_as<T, KThreadLocalPage> ||
std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs,
const KThreadLocalPage&
rhs) {
const VAddr lval = GetRedBlackKey(lhs);
const VAddr rval = GetRedBlackKey(rhs);

View File

@@ -13,34 +13,34 @@ CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
std::vector<u8> buffer;
DriverResult result{DriverResult::Success};
JoystickLeftSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
result = ReadSPI(CalAddr::USER_LEFT_MAGIC, sizeof(u16), buffer);
if (result == DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
if (has_user_calibration) {
result = ReadSPI(CalAddr::USER_LEFT_DATA, 9, buffer);
} else {
result = ReadSPI(CalAddr::FACT_LEFT_DATA, 9, buffer);
}
}
if (result == DriverResult::Success) {
calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min);
calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max);
calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max);
calibration.x.max = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
calibration.y.max = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
calibration.x.center = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
calibration.y.center = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
calibration.x.min = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
calibration.y.min = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
}
// Nintendo fix for drifting stick
// result = ReadSPI(0x60, 0x86 ,buffer, 16);
// calibration.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
// Set a valid default calibration if data is missing
ValidateCalibration(calibration);
@@ -49,34 +49,34 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
std::vector<u8> buffer;
DriverResult result{DriverResult::Success};
JoystickRightSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
result = ReadSPI(CalAddr::USER_RIGHT_MAGIC, sizeof(u16), buffer);
if (result == DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
if (has_user_calibration) {
result = ReadSPI(CalAddr::USER_RIGHT_DATA, 9, buffer);
} else {
result = ReadSPI(CalAddr::FACT_RIGHT_DATA, 9, buffer);
}
}
if (result == DriverResult::Success) {
calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min);
calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max);
calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max);
calibration.x.center = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
calibration.y.center = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
calibration.x.min = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
calibration.y.min = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
calibration.x.max = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
calibration.y.max = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
}
// Nintendo fix for drifting stick
// buffer = ReadSPI(0x60, 0x98 , 16);
// joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
// Set a valid default calibration if data is missing
ValidateCalibration(calibration);
@@ -85,41 +85,39 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
ScopedSetBlocking sb(this);
std::vector<u8> buffer;
DriverResult result{DriverResult::Success};
ImuSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
result = ReadSPI(CalAddr::USER_IMU_MAGIC, sizeof(u16), buffer);
if (result == DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
if (has_user_calibration) {
result = ReadSPI(CalAddr::USER_IMU_DATA, sizeof(IMUCalibration), buffer);
} else {
result = ReadSPI(CalAddr::FACT_IMU_DATA, sizeof(IMUCalibration), buffer);
}
}
if (result == DriverResult::Success) {
calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0];
calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1];
calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2];
IMUCalibration device_calibration{};
memcpy(&device_calibration, buffer.data(), sizeof(IMUCalibration));
calibration.accelerometer[0].offset = device_calibration.accelerometer_offset[0];
calibration.accelerometer[1].offset = device_calibration.accelerometer_offset[1];
calibration.accelerometer[2].offset = device_calibration.accelerometer_offset[2];
calibration.accelerometer[0].scale = spi_calibration.accelerometer_scale[0];
calibration.accelerometer[1].scale = spi_calibration.accelerometer_scale[1];
calibration.accelerometer[2].scale = spi_calibration.accelerometer_scale[2];
calibration.accelerometer[0].scale = device_calibration.accelerometer_scale[0];
calibration.accelerometer[1].scale = device_calibration.accelerometer_scale[1];
calibration.accelerometer[2].scale = device_calibration.accelerometer_scale[2];
calibration.gyro[0].offset = spi_calibration.gyroscope_offset[0];
calibration.gyro[1].offset = spi_calibration.gyroscope_offset[1];
calibration.gyro[2].offset = spi_calibration.gyroscope_offset[2];
calibration.gyro[0].offset = device_calibration.gyroscope_offset[0];
calibration.gyro[1].offset = device_calibration.gyroscope_offset[1];
calibration.gyro[2].offset = device_calibration.gyroscope_offset[2];
calibration.gyro[0].scale = spi_calibration.gyroscope_scale[0];
calibration.gyro[1].scale = spi_calibration.gyroscope_scale[1];
calibration.gyro[2].scale = spi_calibration.gyroscope_scale[2];
calibration.gyro[0].scale = device_calibration.gyroscope_scale[0];
calibration.gyro[1].scale = device_calibration.gyroscope_scale[1];
calibration.gyro[2].scale = device_calibration.gyroscope_scale[2];
}
ValidateCalibration(calibration);
@@ -129,12 +127,10 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
s16 current_value) {
constexpr s16 DefaultRingRange{800};
// TODO: Get default calibration form ring itself
if (ring_data_max == 0 && ring_data_min == 0) {
ring_data_max = current_value + DefaultRingRange;
ring_data_min = current_value - DefaultRingRange;
ring_data_max = current_value + 800;
ring_data_min = current_value - 800;
ring_data_default = current_value;
}
ring_data_max = std::max(ring_data_max, current_value);
@@ -147,72 +143,42 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
return DriverResult::Success;
}
DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
bool& has_user_calibration) {
MagicSpiCalibration spi_magic{};
const DriverResult result{ReadSPI(address, spi_magic)};
has_user_calibration = false;
if (result == DriverResult::Success) {
has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
spi_magic.second == CalibrationMagic::USR_MAGIC_1;
}
return result;
}
u16 CalibrationProtocol::GetXAxisCalibrationValue(std::span<u8> block) const {
return static_cast<u16>(((block[1] & 0x0F) << 8) | block[0]);
}
u16 CalibrationProtocol::GetYAxisCalibrationValue(std::span<u8> block) const {
return static_cast<u16>((block[2] << 4) | (block[1] >> 4));
}
void CalibrationProtocol::ValidateCalibration(JoyStickCalibration& calibration) {
constexpr u16 DefaultStickCenter{0x800};
constexpr u16 DefaultStickRange{0x6cc};
constexpr u16 DefaultStickCenter{2048};
constexpr u16 DefaultStickRange{1740};
calibration.x.center = ValidateValue(calibration.x.center, DefaultStickCenter);
calibration.x.max = ValidateValue(calibration.x.max, DefaultStickRange);
calibration.x.min = ValidateValue(calibration.x.min, DefaultStickRange);
if (calibration.x.center == 0xFFF || calibration.x.center == 0) {
calibration.x.center = DefaultStickCenter;
}
if (calibration.x.max == 0xFFF || calibration.x.max == 0) {
calibration.x.max = DefaultStickRange;
}
if (calibration.x.min == 0xFFF || calibration.x.min == 0) {
calibration.x.min = DefaultStickRange;
}
calibration.y.center = ValidateValue(calibration.y.center, DefaultStickCenter);
calibration.y.max = ValidateValue(calibration.y.max, DefaultStickRange);
calibration.y.min = ValidateValue(calibration.y.min, DefaultStickRange);
if (calibration.y.center == 0xFFF || calibration.y.center == 0) {
calibration.y.center = DefaultStickCenter;
}
if (calibration.y.max == 0xFFF || calibration.y.max == 0) {
calibration.y.max = DefaultStickRange;
}
if (calibration.y.min == 0xFFF || calibration.y.min == 0) {
calibration.y.min = DefaultStickRange;
}
}
void CalibrationProtocol::ValidateCalibration(MotionCalibration& calibration) {
constexpr s16 DefaultAccelerometerScale{0x4000};
constexpr s16 DefaultGyroScale{0x3be7};
constexpr s16 DefaultOffset{0};
for (auto& sensor : calibration.accelerometer) {
sensor.scale = ValidateValue(sensor.scale, DefaultAccelerometerScale);
sensor.offset = ValidateValue(sensor.offset, DefaultOffset);
if (sensor.scale == 0) {
sensor.scale = 0x4000;
}
}
for (auto& sensor : calibration.gyro) {
sensor.scale = ValidateValue(sensor.scale, DefaultGyroScale);
sensor.offset = ValidateValue(sensor.offset, DefaultOffset);
if (sensor.scale == 0) {
sensor.scale = 0x3be7;
}
}
}
u16 CalibrationProtocol::ValidateValue(u16 value, u16 default_value) const {
if (value == 0) {
return default_value;
}
if (value == 0xFFF) {
return default_value;
}
return value;
}
s16 CalibrationProtocol::ValidateValue(s16 value, s16 default_value) const {
if (value == 0) {
return default_value;
}
if (value == 0xFFF) {
return default_value;
}
return value;
}
} // namespace InputCommon::Joycon

View File

@@ -53,27 +53,9 @@ public:
DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
private:
/// Returns true if the specified address corresponds to the magic value of user calibration
DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
/// Converts a raw calibration block to an u16 value containing the x axis value
u16 GetXAxisCalibrationValue(std::span<u8> block) const;
/// Converts a raw calibration block to an u16 value containing the y axis value
u16 GetYAxisCalibrationValue(std::span<u8> block) const;
/// Ensures that all joystick calibration values are set
void ValidateCalibration(JoyStickCalibration& calibration);
/// Ensures that all motion calibration values are set
void ValidateCalibration(MotionCalibration& calibration);
/// Returns the default value if the value is either zero or 0xFFF
u16 ValidateValue(u16 value, u16 default_value) const;
/// Returns the default value if the value is either zero or 0xFFF
s16 ValidateValue(s16 value, s16 default_value) const;
s16 ring_data_max = 0;
s16 ring_data_default = 0;
s16 ring_data_min = 0;

View File

@@ -22,8 +22,8 @@ void JoyconCommonProtocol::SetNonBlocking() {
}
DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
std::array<u8, 1> buffer{};
const auto result = ReadRawSPI(SpiAddress::DEVICE_TYPE, buffer);
std::vector<u8> buffer;
const auto result = ReadSPI(CalAddr::DEVICE_TYPE, 1, buffer);
controller_type = ControllerType::None;
if (result == DriverResult::Success) {
@@ -148,13 +148,11 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
return SendData(local_buffer);
}
DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) {
constexpr std::size_t HeaderSize = 20;
DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output) {
constexpr std::size_t MaxTries = 10;
const auto size = output.size();
std::size_t tries = 0;
std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, static_cast<u8>(size)};
std::vector<u8> local_buffer{};
std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, size};
std::vector<u8> local_buffer(size + 20);
buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF);
buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8);
@@ -169,12 +167,8 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out
}
} while (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]);
if (local_buffer.size() < size + HeaderSize) {
return DriverResult::WrongReply;
}
// Remove header from output
memcpy(output.data(), local_buffer.data() + HeaderSize, size);
output = std::vector<u8>(local_buffer.begin() + 20, local_buffer.begin() + 20 + size);
return DriverResult::Success;
}

View File

@@ -97,29 +97,10 @@ public:
/**
* Reads the SPI memory stored on the joycon
* @param Initial address location
* @param size in bytes to be read
* @returns output buffer containing the responce
*/
DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
/**
* Reads the SPI memory stored on the joycon
* @param Initial address location
* @returns output object containing the responce
*/
template <typename Output>
requires std::is_trivially_copyable_v<Output>
DriverResult ReadSPI(SpiAddress addr, Output& output) {
std::array<u8, sizeof(Output)> buffer;
output = {};
const auto result = ReadRawSPI(addr, buffer);
if (result != DriverResult::Success) {
return result;
}
std::memcpy(&output, buffer.data(), sizeof(Output));
return DriverResult::Success;
}
DriverResult ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output);
/**
* Enables MCU chip on the joycon

View File

@@ -71,8 +71,8 @@ DriverResult GenericProtocol::GetBattery(u32& battery_level) {
DriverResult GenericProtocol::GetColor(Color& color) {
ScopedSetBlocking sb(this);
std::array<u8, 12> buffer{};
const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
std::vector<u8> buffer;
const auto result = ReadSPI(CalAddr::COLOR_DATA, 12, buffer);
color = {};
if (result == DriverResult::Success) {
@@ -87,8 +87,8 @@ DriverResult GenericProtocol::GetColor(Color& color) {
DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
ScopedSetBlocking sb(this);
std::array<u8, 16> buffer{};
const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
std::vector<u8> buffer;
const auto result = ReadSPI(CalAddr::SERIAL_NUMBER, 16, buffer);
serial_number = {};
if (result == DriverResult::Success) {

View File

@@ -159,12 +159,13 @@ enum class UsbSubCommand : u8 {
SEND_UART = 0x92,
};
enum class CalibrationMagic : u8 {
enum class CalMagic : u8 {
USR_MAGIC_0 = 0xB2,
USR_MAGIC_1 = 0xA1,
USRR_MAGI_SIZE = 2,
};
enum class SpiAddress {
enum class CalAddr {
SERIAL_NUMBER = 0X6000,
DEVICE_TYPE = 0X6012,
COLOR_EXIST = 0X601B,
@@ -395,35 +396,10 @@ struct MotionData {
u64 delta_timestamp{};
};
// Output from SPI read command containing user calibration magic
struct MagicSpiCalibration {
CalibrationMagic first;
CalibrationMagic second;
};
static_assert(sizeof(MagicSpiCalibration) == 0x2, "MagicSpiCalibration is an invalid size");
// Output from SPI read command containing left joystick calibration
struct JoystickLeftSpiCalibration {
std::array<u8, 3> max;
std::array<u8, 3> center;
std::array<u8, 3> min;
};
static_assert(sizeof(JoystickLeftSpiCalibration) == 0x9,
"JoystickLeftSpiCalibration is an invalid size");
// Output from SPI read command containing right joystick calibration
struct JoystickRightSpiCalibration {
std::array<u8, 3> center;
std::array<u8, 3> min;
std::array<u8, 3> max;
};
static_assert(sizeof(JoystickRightSpiCalibration) == 0x9,
"JoystickRightSpiCalibration is an invalid size");
struct JoyStickAxisCalibration {
u16 max;
u16 min;
u16 center;
u16 max{1};
u16 min{1};
u16 center{0};
};
struct JoyStickCalibration {
@@ -431,14 +407,6 @@ struct JoyStickCalibration {
JoyStickAxisCalibration y;
};
struct ImuSpiCalibration {
std::array<s16, 3> accelerometer_offset;
std::array<s16, 3> accelerometer_scale;
std::array<s16, 3> gyroscope_offset;
std::array<s16, 3> gyroscope_scale;
};
static_assert(sizeof(ImuSpiCalibration) == 0x18, "ImuSpiCalibration is an invalid size");
struct RingCalibration {
s16 default_value;
s16 max_value;
@@ -520,6 +488,14 @@ struct InputReportNfcIr {
static_assert(sizeof(InputReportNfcIr) == 0x29, "InputReportNfcIr is an invalid size");
#pragma pack(pop)
struct IMUCalibration {
std::array<s16, 3> accelerometer_offset;
std::array<s16, 3> accelerometer_scale;
std::array<s16, 3> gyroscope_offset;
std::array<s16, 3> gyroscope_scale;
};
static_assert(sizeof(IMUCalibration) == 0x18, "IMUCalibration is an invalid size");
struct NFCReadBlock {
u8 start;
u8 end;

View File

@@ -279,8 +279,6 @@ void SetupOptions(const IR::Program& program, const Profile& profile,
header += "OPTION NV_internal;"
"OPTION NV_shader_storage_buffer;"
"OPTION NV_gpu_program_fp64;";
// TODO: Enable only when MS is used
header += "OPTION NV_texture_multisample;";
if (info.uses_int64_bit_atomics) {
header += "OPTION NV_shader_atomic_int64;";
}

View File

@@ -59,7 +59,7 @@ std::string Image(EmitContext& ctx, IR::TextureInstInfo info,
}
}
std::string_view TextureType(IR::TextureInstInfo info, bool is_ms = false) {
std::string_view TextureType(IR::TextureInstInfo info) {
if (info.is_depth) {
switch (info.type) {
case TextureType::Color1D:
@@ -88,9 +88,9 @@ std::string_view TextureType(IR::TextureInstInfo info, bool is_ms = false) {
return "ARRAY1D";
case TextureType::Color2D:
case TextureType::Color2DRect:
return is_ms ? "2DMS" : "2D";
return "2D";
case TextureType::ColorArray2D:
return is_ms ? "ARRAY2DMS" : "ARRAY2D";
return "ARRAY2D";
case TextureType::Color3D:
return "3D";
case TextureType::ColorCube:
@@ -510,16 +510,15 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
const auto sparse_inst{PrepareSparse(inst)};
const bool is_multisample{ms.type != Type::Void};
const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""};
const std::string_view type{TextureType(info, is_multisample)};
const std::string_view type{TextureType(info)};
const std::string texture{Texture(ctx, info, index)};
const std::string offset_vec{Offset(ctx, offset)};
const auto [coord_vec, coord_alloc]{Coord(ctx, coord)};
const Register ret{ctx.reg_alloc.Define(inst)};
if (info.type == TextureType::Buffer) {
ctx.Add("TXF.F{} {},{},{},{}{};", sparse_mod, ret, coord_vec, texture, type, offset_vec);
} else if (is_multisample) {
} else if (ms.type != Type::Void) {
ctx.Add("MOV.S {}.w,{};"
"TXFMS.F{} {},{},{},{}{};",
coord_vec, ms, sparse_mod, ret, coord_vec, texture, type, offset_vec);
@@ -532,7 +531,7 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
}
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
ScalarS32 lod, [[maybe_unused]] const IR::Value& skip_mips) {
ScalarS32 lod) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
const std::string texture{Texture(ctx, info, index)};
const std::string_view type{TextureType(info)};

View File

@@ -581,7 +581,7 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde
void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms);
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
ScalarS32 lod, const IR::Value& skip_mips);
ScalarS32 lod);
void EmitImageQueryLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord);
void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
const IR::Value& coord, const IR::Value& derivatives,

View File

@@ -414,7 +414,7 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde
void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
std::string_view coords, std::string_view offset, std::string_view lod,
std::string_view ms) {
[[maybe_unused]] std::string_view ms) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
if (info.has_bias) {
throw NotImplementedException("EmitImageFetch Bias texture samples");
@@ -431,24 +431,19 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
ctx.AddU1("{}=true;", *sparse_inst);
}
if (!sparse_inst || !supports_sparse) {
const auto int_coords{CoordsCastToInt(coords, info)};
if (!ms.empty()) {
ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, ms);
} else if (!offset.empty()) {
ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture, int_coords, lod,
CoordsCastToInt(offset, info));
if (!offset.empty()) {
ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture,
CoordsCastToInt(coords, info), lod, CoordsCastToInt(offset, info));
} else {
if (info.type == TextureType::Buffer) {
ctx.Add("{}=texelFetch({},int({}));", texel, texture, coords);
} else {
ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, lod);
ctx.Add("{}=texelFetch({},{},int({}));", texel, texture,
CoordsCastToInt(coords, info), lod);
}
}
return;
}
if (!ms.empty()) {
throw NotImplementedException("EmitImageFetch Sparse MSAA samples");
}
if (!offset.empty()) {
ctx.AddU1("{}=sparseTexelsResidentARB(sparseTexelFetchOffsetARB({},{},int({}),{},{}));",
*sparse_inst, texture, CastToIntVec(coords, info), lod,
@@ -460,27 +455,27 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
}
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
std::string_view lod, const IR::Value& skip_mips_val) {
std::string_view lod) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
const auto texture{Texture(ctx, info, index)};
const bool skip_mips{skip_mips_val.U1()};
const auto mips{
[&] { return skip_mips ? "0u" : fmt::format("uint(textureQueryLevels({}))", texture); }};
switch (info.type) {
case TextureType::Color1D:
return ctx.AddU32x4("{}=uvec4(uint(textureSize({},int({}))),0u,0u,{});", inst, texture, lod,
mips());
return ctx.AddU32x4(
"{}=uvec4(uint(textureSize({},int({}))),0u,0u,uint(textureQueryLevels({})));", inst,
texture, lod, texture);
case TextureType::ColorArray1D:
case TextureType::Color2D:
case TextureType::ColorCube:
case TextureType::Color2DRect:
return ctx.AddU32x4("{}=uvec4(uvec2(textureSize({},int({}))),0u,{});", inst, texture, lod,
mips());
return ctx.AddU32x4(
"{}=uvec4(uvec2(textureSize({},int({}))),0u,uint(textureQueryLevels({})));", inst,
texture, lod, texture);
case TextureType::ColorArray2D:
case TextureType::Color3D:
case TextureType::ColorArrayCube:
return ctx.AddU32x4("{}=uvec4(uvec3(textureSize({},int({}))),{});", inst, texture, lod,
mips());
return ctx.AddU32x4(
"{}=uvec4(uvec3(textureSize({},int({}))),uint(textureQueryLevels({})));", inst, texture,
lod, texture);
case TextureType::Buffer:
throw NotImplementedException("EmitImageQueryDimensions Texture buffers");
}

View File

@@ -654,7 +654,7 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
std::string_view coords, std::string_view offset, std::string_view lod,
std::string_view ms);
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
std::string_view lod, const IR::Value& skip_mips);
std::string_view lod);
void EmitImageQueryLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
std::string_view coords);
void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,

View File

@@ -61,28 +61,24 @@ std::string OutputDecorator(Stage stage, u32 size) {
}
}
std::string_view DepthSamplerType(TextureType type) {
switch (type) {
case TextureType::Color1D:
return "sampler1DShadow";
case TextureType::ColorArray1D:
return "sampler1DArrayShadow";
case TextureType::Color2D:
return "sampler2DShadow";
case TextureType::ColorArray2D:
return "sampler2DArrayShadow";
case TextureType::ColorCube:
return "samplerCubeShadow";
case TextureType::ColorArrayCube:
return "samplerCubeArrayShadow";
default:
throw NotImplementedException("Texture type: {}", type);
}
}
std::string_view ColorSamplerType(TextureType type, bool is_multisample = false) {
if (is_multisample) {
ASSERT(type == TextureType::Color2D || type == TextureType::ColorArray2D);
std::string_view SamplerType(TextureType type, bool is_depth) {
if (is_depth) {
switch (type) {
case TextureType::Color1D:
return "sampler1DShadow";
case TextureType::ColorArray1D:
return "sampler1DArrayShadow";
case TextureType::Color2D:
return "sampler2DShadow";
case TextureType::ColorArray2D:
return "sampler2DArrayShadow";
case TextureType::ColorCube:
return "samplerCubeShadow";
case TextureType::ColorArrayCube:
return "samplerCubeArrayShadow";
default:
throw NotImplementedException("Texture type: {}", type);
}
}
switch (type) {
case TextureType::Color1D:
@@ -91,9 +87,9 @@ std::string_view ColorSamplerType(TextureType type, bool is_multisample = false)
return "sampler1DArray";
case TextureType::Color2D:
case TextureType::Color2DRect:
return is_multisample ? "sampler2DMS" : "sampler2D";
return "sampler2D";
case TextureType::ColorArray2D:
return is_multisample ? "sampler2DMSArray" : "sampler2DArray";
return "sampler2DArray";
case TextureType::Color3D:
return "sampler3D";
case TextureType::ColorCube:
@@ -681,7 +677,7 @@ void EmitContext::SetupTextures(Bindings& bindings) {
texture_buffers.reserve(info.texture_buffer_descriptors.size());
for (const auto& desc : info.texture_buffer_descriptors) {
texture_buffers.push_back({bindings.texture, desc.count});
const auto sampler_type{ColorSamplerType(TextureType::Buffer)};
const auto sampler_type{SamplerType(TextureType::Buffer, false)};
const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture,
sampler_type, bindings.texture, array_decorator);
@@ -690,8 +686,7 @@ void EmitContext::SetupTextures(Bindings& bindings) {
textures.reserve(info.texture_descriptors.size());
for (const auto& desc : info.texture_descriptors) {
textures.push_back({bindings.texture, desc.count});
const auto sampler_type{desc.is_depth ? DepthSamplerType(desc.type)
: ColorSamplerType(desc.type, desc.is_multisample)};
const auto sampler_type{SamplerType(desc.type, desc.is_depth)};
const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture,
sampler_type, bindings.texture, array_decorator);

View File

@@ -445,13 +445,11 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
}
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
const IR::Value& skip_mips_val) {
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod) {
const auto info{inst->Flags<IR::TextureInstInfo>()};
const Id image{TextureImage(ctx, info, index)};
const Id zero{ctx.u32_zero_value};
const bool skip_mips{skip_mips_val.U1()};
const auto mips{[&] { return skip_mips ? zero : ctx.OpImageQueryLevels(ctx.U32[1], image); }};
const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }};
switch (info.type) {
case TextureType::Color1D:
return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[1], image, lod),

View File

@@ -539,8 +539,7 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
const IR::Value& offset, const IR::Value& offset2, Id dref);
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
Id lod, Id ms);
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
const IR::Value& skip_mips);
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod);
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id derivates, Id offset, Id lod_clamp);

View File

@@ -1846,16 +1846,15 @@ Value IREmitter::ImageFetch(const Value& handle, const Value& coords, const Valu
return Inst(op, Flags{info}, handle, coords, offset, lod, multisampling);
}
Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod,
const IR::U1& skip_mips) {
Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageQueryDimensions
: Opcode::BindlessImageQueryDimensions};
return Inst(op, handle, lod, skip_mips);
return Inst(op, handle, lod);
}
Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod,
const IR::U1& skip_mips, TextureInstInfo info) {
return Inst(Opcode::ImageQueryDimensions, Flags{info}, handle, lod, skip_mips);
TextureInstInfo info) {
return Inst(Opcode::ImageQueryDimensions, Flags{info}, handle, lod);
}
Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, TextureInstInfo info) {

View File

@@ -320,10 +320,9 @@ public:
[[nodiscard]] F32 ImageSampleDrefExplicitLod(const Value& handle, const Value& coords,
const F32& dref, const F32& lod,
const Value& offset, TextureInstInfo info);
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod);
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod,
const IR::U1& skip_mips);
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod,
const IR::U1& skip_mips, TextureInstInfo info);
TextureInstInfo info);
[[nodiscard]] Value ImageQueryLod(const Value& handle, const Value& coords,
TextureInstInfo info);
@@ -409,8 +408,7 @@ private:
}
template <typename T>
requires(sizeof(T) <= sizeof(u32) && std::is_trivially_copyable_v<T>)
struct Flags {
requires(sizeof(T) <= sizeof(u32) && std::is_trivially_copyable_v<T>) struct Flags {
Flags() = default;
Flags(T proxy_) : proxy{proxy_} {}

View File

@@ -482,7 +482,7 @@ OPCODE(BindlessImageSampleDrefExplicitLod, F32, U32,
OPCODE(BindlessImageGather, F32x4, U32, Opaque, Opaque, Opaque, )
OPCODE(BindlessImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, )
OPCODE(BindlessImageFetch, F32x4, U32, Opaque, Opaque, U32, Opaque, )
OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, U1, )
OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, )
OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, )
OPCODE(BindlessImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
OPCODE(BindlessImageRead, U32x4, U32, Opaque, )
@@ -495,7 +495,7 @@ OPCODE(BoundImageSampleDrefExplicitLod, F32, U32,
OPCODE(BoundImageGather, F32x4, U32, Opaque, Opaque, Opaque, )
OPCODE(BoundImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, )
OPCODE(BoundImageFetch, F32x4, U32, Opaque, Opaque, U32, Opaque, )
OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, U1, )
OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, )
OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, )
OPCODE(BoundImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
OPCODE(BoundImageRead, U32x4, U32, Opaque, )
@@ -508,7 +508,7 @@ OPCODE(ImageSampleDrefExplicitLod, F32, Opaq
OPCODE(ImageGather, F32x4, Opaque, Opaque, Opaque, Opaque, )
OPCODE(ImageGatherDref, F32x4, Opaque, Opaque, Opaque, Opaque, F32, )
OPCODE(ImageFetch, F32x4, Opaque, Opaque, Opaque, U32, Opaque, )
OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, U1, )
OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, )
OPCODE(ImageQueryLod, F32x4, Opaque, Opaque, )
OPCODE(ImageGradient, F32x4, Opaque, Opaque, Opaque, Opaque, Opaque, )
OPCODE(ImageRead, U32x4, Opaque, Opaque, )

View File

@@ -101,8 +101,9 @@ public:
TypedValue() = default;
template <IR::Type other_type>
requires((other_type & type_) != IR::Type::Void)
explicit(false) TypedValue(const TypedValue<other_type>& value) : Value(value) {}
requires((other_type & type_) != IR::Type::Void) explicit(false)
TypedValue(const TypedValue<other_type>& value)
: Value(value) {}
explicit TypedValue(const Value& value) : Value(value) {
if ((value.Type() & type_) == IR::Type::Void) {
@@ -193,16 +194,16 @@ public:
void ReplaceOpcode(IR::Opcode opcode);
template <typename FlagsType>
requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
[[nodiscard]] FlagsType Flags() const noexcept {
requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
[[nodiscard]] FlagsType Flags() const noexcept {
FlagsType ret;
std::memcpy(reinterpret_cast<char*>(&ret), &flags, sizeof(ret));
return ret;
}
template <typename FlagsType>
requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
void SetFlags(FlagsType value) noexcept {
requires(sizeof(FlagsType) <= sizeof(u32) &&
std::is_trivially_copyable_v<FlagsType>) void SetFlags(FlagsType value) noexcept {
std::memcpy(&flags, &value, sizeof(value));
}

View File

@@ -15,13 +15,11 @@ enum class Mode : u64 {
SamplePos = 5,
};
IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, Mode mode, IR::Reg src_reg, u64 mask) {
IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, Mode mode, IR::Reg src_reg) {
switch (mode) {
case Mode::Dimension: {
const bool needs_num_mips{((mask >> 3) & 1) != 0};
const IR::U1 skip_mips{v.ir.Imm1(!needs_num_mips)};
const IR::U32 lod{v.X(src_reg)};
return v.ir.ImageQueryDimension(handle, lod, skip_mips);
return v.ir.ImageQueryDimension(handle, lod);
}
case Mode::TextureType:
case Mode::SamplePos:
@@ -48,7 +46,7 @@ void Impl(TranslatorVisitor& v, u64 insn, std::optional<u32> cbuf_offset) {
handle = v.X(src_reg);
++src_reg;
}
const IR::Value query{Query(v, handle, txq.mode, src_reg, txq.mask)};
const IR::Value query{Query(v, handle, txq.mode, src_reg)};
IR::Reg dest_reg{txq.dest_reg};
for (int element = 0; element < 4; ++element) {
if (((txq.mask >> element) & 1) == 0) {

View File

@@ -355,21 +355,21 @@ TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
};
}
u32 GetTextureHandle(Environment& env, const ConstBufferAddr& cbuf) {
TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
const u32 secondary_index{cbuf.has_secondary ? cbuf.secondary_index : cbuf.index};
const u32 secondary_offset{cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset};
const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset) << cbuf.shift_left};
const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset)
<< cbuf.secondary_shift_left};
return lhs_raw | rhs_raw;
}
TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
return env.ReadTextureType(GetTextureHandle(env, cbuf));
return env.ReadTextureType(lhs_raw | rhs_raw);
}
TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) {
return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf));
const u32 secondary_index{cbuf.has_secondary ? cbuf.secondary_index : cbuf.index};
const u32 secondary_offset{cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset};
const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset)};
const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset)};
return env.ReadTexturePixelFormat(lhs_raw | rhs_raw);
}
class Descriptors {
@@ -386,10 +386,8 @@ public:
return Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) {
return desc.cbuf_index == existing.cbuf_index &&
desc.cbuf_offset == existing.cbuf_offset &&
desc.shift_left == existing.shift_left &&
desc.secondary_cbuf_index == existing.secondary_cbuf_index &&
desc.secondary_cbuf_offset == existing.secondary_cbuf_offset &&
desc.secondary_shift_left == existing.secondary_shift_left &&
desc.count == existing.count && desc.size_shift == existing.size_shift &&
desc.has_secondary == existing.has_secondary;
});
@@ -407,20 +405,15 @@ public:
}
u32 Add(const TextureDescriptor& desc) {
const u32 index{Add(texture_descriptors, desc, [&desc](const auto& existing) {
return Add(texture_descriptors, desc, [&desc](const auto& existing) {
return desc.type == existing.type && desc.is_depth == existing.is_depth &&
desc.has_secondary == existing.has_secondary &&
desc.cbuf_index == existing.cbuf_index &&
desc.cbuf_offset == existing.cbuf_offset &&
desc.shift_left == existing.shift_left &&
desc.secondary_cbuf_index == existing.secondary_cbuf_index &&
desc.secondary_cbuf_offset == existing.secondary_cbuf_offset &&
desc.secondary_shift_left == existing.secondary_shift_left &&
desc.count == existing.count && desc.size_shift == existing.size_shift;
})};
// TODO: Read this from TIC
texture_descriptors[index].is_multisample |= desc.is_multisample;
return index;
});
}
u32 Add(const ImageDescriptor& desc) {
@@ -459,8 +452,7 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
const IR::Value coord(inst.Arg(1));
const IR::Value handle(ir.Imm32(0));
const IR::U32 lod{ir.Imm32(0)};
const IR::U1 skip_mips{ir.Imm1(true)};
const IR::Value texture_size = ir.ImageQueryDimension(handle, lod, skip_mips, info);
const IR::Value texture_size = ir.ImageQueryDimension(handle, lod, info);
inst.SetArg(
1, ir.CompositeConstruct(
ir.FPMul(IR::F32(ir.CompositeExtract(coord, 0)),

View File

@@ -10,7 +10,7 @@
namespace Shader {
template <typename T>
requires std::is_destructible_v<T>
requires std::is_destructible_v<T>
class ObjectPool {
public:
explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} {
@@ -18,7 +18,7 @@ public:
}
template <typename... Args>
requires std::is_constructible_v<T, Args...>
requires std::is_constructible_v<T, Args...>
[[nodiscard]] T* Create(Args&&... args) {
return std::construct_at(Memory(), std::forward<Args>(args)...);
}

View File

@@ -19,7 +19,9 @@ public:
explicit DescriptorTable(Tegra::MemoryManager& gpu_memory_) : gpu_memory{gpu_memory_} {}
[[nodiscard]] bool Synchronize(GPUVAddr gpu_addr, u32 limit) {
[[likely]] if (current_gpu_addr == gpu_addr && current_limit == limit) { return false; }
[[likely]] if (current_gpu_addr == gpu_addr && current_limit == limit) {
return false;
}
Refresh(gpu_addr, limit);
return true;
}

View File

@@ -100,10 +100,6 @@ ImageInfo::ImageInfo(const TICEntry& config) noexcept {
ASSERT_MSG(false, "Invalid texture_type={}", static_cast<int>(config.texture_type.Value()));
break;
}
if (num_samples > 1) {
size.width *= NumSamplesX(config.msaa_mode);
size.height *= NumSamplesY(config.msaa_mode);
}
if (type != ImageType::Linear) {
// FIXME: Call this without passing *this
layer_stride = CalculateLayerStride(*this);

View File

@@ -51,48 +51,4 @@ namespace VideoCommon {
return 1;
}
[[nodiscard]] inline int NumSamplesX(Tegra::Texture::MsaaMode msaa_mode) {
using Tegra::Texture::MsaaMode;
switch (msaa_mode) {
case MsaaMode::Msaa1x1:
return 1;
case MsaaMode::Msaa2x1:
case MsaaMode::Msaa2x1_D3D:
case MsaaMode::Msaa2x2:
case MsaaMode::Msaa2x2_VC4:
case MsaaMode::Msaa2x2_VC12:
return 2;
case MsaaMode::Msaa4x2:
case MsaaMode::Msaa4x2_D3D:
case MsaaMode::Msaa4x2_VC8:
case MsaaMode::Msaa4x2_VC24:
case MsaaMode::Msaa4x4:
return 4;
}
ASSERT_MSG(false, "Invalid MSAA mode={}", static_cast<int>(msaa_mode));
return 1;
}
[[nodiscard]] inline int NumSamplesY(Tegra::Texture::MsaaMode msaa_mode) {
using Tegra::Texture::MsaaMode;
switch (msaa_mode) {
case MsaaMode::Msaa1x1:
case MsaaMode::Msaa2x1:
case MsaaMode::Msaa2x1_D3D:
return 1;
case MsaaMode::Msaa2x2:
case MsaaMode::Msaa2x2_VC4:
case MsaaMode::Msaa2x2_VC12:
case MsaaMode::Msaa4x2:
case MsaaMode::Msaa4x2_D3D:
case MsaaMode::Msaa4x2_VC8:
case MsaaMode::Msaa4x2_VC24:
return 2;
case MsaaMode::Msaa4x4:
return 4;
}
ASSERT_MSG(false, "Invalid MSAA mode={}", static_cast<int>(msaa_mode));
return 1;
}
} // namespace VideoCommon

View File

@@ -29,7 +29,7 @@ struct SlotId {
};
template <class T>
requires std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<T>
requires std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<T>
class SlotVector {
public:
class Iterator {

View File

@@ -353,7 +353,7 @@ if (USE_DISCORD_PRESENCE)
discord_impl.cpp
discord_impl.h
)
target_link_libraries(yuzu PRIVATE DiscordRPC::discord-rpc)
target_link_libraries(yuzu PRIVATE DiscordRPC::discord-rpc httplib::httplib)
target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE)
endif()

View File

@@ -58,16 +58,13 @@ std::vector<std::string> InputProfiles::GetInputProfileNames() {
std::vector<std::string> profile_names;
profile_names.reserve(map_profiles.size());
auto it = map_profiles.cbegin();
while (it != map_profiles.cend()) {
const auto& [profile_name, config] = *it;
for (const auto& [profile_name, config] : map_profiles) {
if (!ProfileExistsInFilesystem(profile_name)) {
it = map_profiles.erase(it);
DeleteProfile(profile_name);
continue;
}
profile_names.push_back(profile_name);
++it;
}
std::stable_sort(profile_names.begin(), profile_names.end());

View File

@@ -4,7 +4,10 @@
#include <chrono>
#include <string>
#include <discord_rpc.h>
#include <fmt/format.h>
#include <httplib.h>
#include "common/common_types.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/loader/loader.h"
#include "yuzu/discord_impl.h"
@@ -14,7 +17,6 @@ namespace DiscordRPC {
DiscordImpl::DiscordImpl(Core::System& system_) : system{system_} {
DiscordEventHandlers handlers{};
// The number is the client ID for yuzu, it's used for images and the
// application name
Discord_Initialize("712465656758665259", &handlers, 1, nullptr);
@@ -29,23 +31,74 @@ void DiscordImpl::Pause() {
Discord_ClearPresence();
}
static std::string GetGameString(const std::string& title) {
// Convert to lowercase
std::string icon_name = Common::ToLower(title);
// Replace spaces with dashes
std::replace(icon_name.begin(), icon_name.end(), ' ', '-');
// Remove non-alphanumeric characters but keep dashes
std::erase_if(icon_name, [](char c) { return !std::isalnum(c) && c != '-'; });
// Remove dashes from the start and end of the string
icon_name.erase(icon_name.begin(), std::find_if(icon_name.begin(), icon_name.end(),
[](int ch) { return ch != '-'; }));
icon_name.erase(
std::find_if(icon_name.rbegin(), icon_name.rend(), [](int ch) { return ch != '-'; }).base(),
icon_name.end());
// Remove double dashes
icon_name.erase(std::unique(icon_name.begin(), icon_name.end(),
[](char a, char b) { return a == '-' && b == '-'; }),
icon_name.end());
return icon_name;
}
void DiscordImpl::Update() {
s64 start_time = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
const std::string default_text = "yuzu is an emulator for the Nintendo Switch";
const std::string default_image = "yuzu_logo";
std::string game_cover_url = "https://yuzu-emu.org";
std::string title;
DiscordRichPresence presence{};
if (system.IsPoweredOn()) {
system.GetAppLoader().ReadTitle(title);
}
DiscordRichPresence presence{};
presence.largeImageKey = "yuzu_logo";
presence.largeImageText = "yuzu is an emulator for the Nintendo Switch";
if (system.IsPoweredOn()) {
// Used to format Icon URL for yuzu website game compatibility page
std::string icon_name = GetGameString(title);
// New Check for game cover
httplib::Client cli(game_cover_url);
if (auto res = cli.Head(fmt::format("/images/game/boxart/{}.png", icon_name).c_str())) {
if (res->status == 200) {
game_cover_url += fmt::format("/images/game/boxart/{}.png", icon_name);
} else {
game_cover_url = "yuzu_logo";
}
} else {
game_cover_url = "yuzu_logo";
}
presence.largeImageKey = game_cover_url.c_str();
presence.largeImageText = title.c_str();
presence.smallImageKey = default_image.c_str();
presence.smallImageText = default_text.c_str();
presence.state = title.c_str();
presence.details = "Currently in game";
} else {
presence.details = "Not in game";
presence.largeImageKey = default_image.c_str();
presence.largeImageText = default_text.c_str();
presence.details = "Currently not in game";
}
presence.startTimestamp = start_time;
Discord_UpdatePresence(&presence);
}