diff options
Diffstat (limited to 'src')
57 files changed, 781 insertions, 492 deletions
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 827ab0ac7..ec71524a3 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -4,8 +4,6 @@ add_library(audio_core STATIC audio_renderer.cpp audio_renderer.h buffer.h - cubeb_sink.cpp - cubeb_sink.h codec.cpp codec.h null_sink.h @@ -15,6 +13,8 @@ add_library(audio_core STATIC sink_details.cpp sink_details.h sink_stream.h + + $<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h> ) create_target_directory_groups(audio_core) diff --git a/src/common/file_util.h b/src/common/file_util.h index 28697d527..430dac41c 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -8,6 +8,7 @@ #include <cstdio> #include <fstream> #include <functional> +#include <limits> #include <string> #include <string_view> #include <type_traits> @@ -210,8 +211,9 @@ public: static_assert(std::is_trivially_copyable<T>(), "Given array does not consist of trivially copyable objects"); - if (!IsOpen()) - return -1; + if (!IsOpen()) { + return std::numeric_limits<size_t>::max(); + } return std::fread(data, sizeof(T), length, m_file); } @@ -220,8 +222,10 @@ public: size_t WriteArray(const T* data, size_t length) { static_assert(std::is_trivially_copyable<T>(), "Given array does not consist of trivially copyable objects"); - if (!IsOpen()) - return -1; + if (!IsOpen()) { + return std::numeric_limits<size_t>::max(); + } + return std::fwrite(data, sizeof(T), length, m_file); } diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 816414e8d..355abd682 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -200,6 +200,7 @@ void FileBackend::Write(const Entry& entry) { SUB(Service, SPL) \ SUB(Service, SSL) \ SUB(Service, Time) \ + SUB(Service, USB) \ SUB(Service, VI) \ SUB(Service, WLAN) \ CLS(HW) \ diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 7ab5277ea..a889ebefa 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -87,6 +87,7 @@ enum class Class : ClassType { Service_SPL, ///< The SPL service Service_SSL, ///< The SSL service Service_Time, ///< The time service + Service_USB, ///< The USB (Universal Serial Bus) service Service_VI, ///< The VI (Video interface) service Service_WLAN, ///< The WLAN (Wireless local area network) service HW, ///< Low-level hardware emulation diff --git a/src/common/vector_math.h b/src/common/vector_math.h index cca43bd4c..5c94fcda3 100644 --- a/src/common/vector_math.h +++ b/src/common/vector_math.h @@ -43,139 +43,135 @@ template <typename T> class Vec4; template <typename T> -static inline Vec2<T> MakeVec(const T& x, const T& y); -template <typename T> -static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z); -template <typename T> -static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w); - -template <typename T> class Vec2 { public: T x{}; T y{}; - Vec2() = default; - Vec2(const T& _x, const T& _y) : x(_x), y(_y) {} + constexpr Vec2() = default; + constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {} template <typename T2> - Vec2<T2> Cast() const { - return Vec2<T2>((T2)x, (T2)y); + constexpr Vec2<T2> Cast() const { + return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y)); } - static Vec2 AssignToAll(const T& f) { - return Vec2<T>(f, f); + static constexpr Vec2 AssignToAll(const T& f) { + return Vec2{f, f}; } - Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const { - return MakeVec(x + other.x, y + other.y); + constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const { + return {x + other.x, y + other.y}; } - void operator+=(const Vec2& other) { + constexpr Vec2& operator+=(const Vec2& other) { x += other.x; y += other.y; + return *this; } - Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const { - return MakeVec(x - other.x, y - other.y); + constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const { + return {x - other.x, y - other.y}; } - void operator-=(const Vec2& other) { + constexpr Vec2& operator-=(const Vec2& other) { x -= other.x; y -= other.y; + return *this; } template <typename U = T> - Vec2<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const { - return MakeVec(-x, -y); + constexpr Vec2<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const { + return {-x, -y}; } - Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const { - return MakeVec(x * other.x, y * other.y); + constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const { + return {x * other.x, y * other.y}; } + template <typename V> - Vec2<decltype(T{} * V{})> operator*(const V& f) const { - return MakeVec(x * f, y * f); + constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const { + return {x * f, y * f}; } + template <typename V> - void operator*=(const V& f) { + constexpr Vec2& operator*=(const V& f) { *this = *this * f; + return *this; } + template <typename V> - Vec2<decltype(T{} / V{})> operator/(const V& f) const { - return MakeVec(x / f, y / f); + constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const { + return {x / f, y / f}; } + template <typename V> - void operator/=(const V& f) { + constexpr Vec2& operator/=(const V& f) { *this = *this / f; + return *this; } - T Length2() const { + constexpr T Length2() const { return x * x + y * y; } // Only implemented for T=float float Length() const; - void SetLength(const float l); - Vec2 WithLength(const float l) const; - float Distance2To(Vec2& other); - Vec2 Normalized() const; float Normalize(); // returns the previous length, which is often useful - T& operator[](int i) // allow vector[1] = 3 (vector.y=3) - { + constexpr T& operator[](std::size_t i) { return *((&x) + i); } - T operator[](const int i) const { + constexpr const T& operator[](std::size_t i) const { return *((&x) + i); } - void SetZero() { + constexpr void SetZero() { x = 0; y = 0; } // Common aliases: UV (texel coordinates), ST (texture coordinates) - T& u() { + constexpr T& u() { return x; } - T& v() { + constexpr T& v() { return y; } - T& s() { + constexpr T& s() { return x; } - T& t() { + constexpr T& t() { return y; } - const T& u() const { + constexpr const T& u() const { return x; } - const T& v() const { + constexpr const T& v() const { return y; } - const T& s() const { + constexpr const T& s() const { return x; } - const T& t() const { + constexpr const T& t() const { return y; } // swizzlers - create a subvector of specific components - const Vec2 yx() const { + constexpr Vec2 yx() const { return Vec2(y, x); } - const Vec2 vu() const { + constexpr Vec2 vu() const { return Vec2(y, x); } - const Vec2 ts() const { + constexpr Vec2 ts() const { return Vec2(y, x); } }; template <typename T, typename V> -Vec2<T> operator*(const V& f, const Vec2<T>& vec) { +constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) { return Vec2<T>(f * vec.x, f * vec.y); } -typedef Vec2<float> Vec2f; +using Vec2f = Vec2<float>; template <> inline float Vec2<float>::Length() const { @@ -196,147 +192,151 @@ public: T y{}; T z{}; - Vec3() = default; - Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {} + constexpr Vec3() = default; + constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {} template <typename T2> - Vec3<T2> Cast() const { - return MakeVec<T2>((T2)x, (T2)y, (T2)z); + constexpr Vec3<T2> Cast() const { + return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z)); } - // Only implemented for T=int and T=float - static Vec3 FromRGB(unsigned int rgb); - unsigned int ToRGB() const; // alpha bits set to zero - - static Vec3 AssignToAll(const T& f) { - return MakeVec(f, f, f); + static constexpr Vec3 AssignToAll(const T& f) { + return Vec3(f, f, f); } - Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const { - return MakeVec(x + other.x, y + other.y, z + other.z); + constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const { + return {x + other.x, y + other.y, z + other.z}; } - void operator+=(const Vec3& other) { + + constexpr Vec3& operator+=(const Vec3& other) { x += other.x; y += other.y; z += other.z; + return *this; } - Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const { - return MakeVec(x - other.x, y - other.y, z - other.z); + + constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const { + return {x - other.x, y - other.y, z - other.z}; } - void operator-=(const Vec3& other) { + + constexpr Vec3& operator-=(const Vec3& other) { x -= other.x; y -= other.y; z -= other.z; + return *this; } template <typename U = T> - Vec3<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const { - return MakeVec(-x, -y, -z); + constexpr Vec3<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const { + return {-x, -y, -z}; } - Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const { - return MakeVec(x * other.x, y * other.y, z * other.z); + + constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const { + return {x * other.x, y * other.y, z * other.z}; } + template <typename V> - Vec3<decltype(T{} * V{})> operator*(const V& f) const { - return MakeVec(x * f, y * f, z * f); + constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const { + return {x * f, y * f, z * f}; } + template <typename V> - void operator*=(const V& f) { + constexpr Vec3& operator*=(const V& f) { *this = *this * f; + return *this; } template <typename V> - Vec3<decltype(T{} / V{})> operator/(const V& f) const { - return MakeVec(x / f, y / f, z / f); + constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const { + return {x / f, y / f, z / f}; } + template <typename V> - void operator/=(const V& f) { + constexpr Vec3& operator/=(const V& f) { *this = *this / f; + return *this; } - T Length2() const { + constexpr T Length2() const { return x * x + y * y + z * z; } // Only implemented for T=float float Length() const; - void SetLength(const float l); - Vec3 WithLength(const float l) const; - float Distance2To(Vec3& other); Vec3 Normalized() const; float Normalize(); // returns the previous length, which is often useful - T& operator[](int i) // allow vector[2] = 3 (vector.z=3) - { + constexpr T& operator[](std::size_t i) { return *((&x) + i); } - T operator[](const int i) const { + + constexpr const T& operator[](std::size_t i) const { return *((&x) + i); } - void SetZero() { + constexpr void SetZero() { x = 0; y = 0; z = 0; } // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates) - T& u() { + constexpr T& u() { return x; } - T& v() { + constexpr T& v() { return y; } - T& w() { + constexpr T& w() { return z; } - T& r() { + constexpr T& r() { return x; } - T& g() { + constexpr T& g() { return y; } - T& b() { + constexpr T& b() { return z; } - T& s() { + constexpr T& s() { return x; } - T& t() { + constexpr T& t() { return y; } - T& q() { + constexpr T& q() { return z; } - const T& u() const { + constexpr const T& u() const { return x; } - const T& v() const { + constexpr const T& v() const { return y; } - const T& w() const { + constexpr const T& w() const { return z; } - const T& r() const { + constexpr const T& r() const { return x; } - const T& g() const { + constexpr const T& g() const { return y; } - const T& b() const { + constexpr const T& b() const { return z; } - const T& s() const { + constexpr const T& s() const { return x; } - const T& t() const { + constexpr const T& t() const { return y; } - const T& q() const { + constexpr const T& q() const { return z; } @@ -345,7 +345,7 @@ 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) \ - const Vec2<T> name() const { \ + constexpr Vec2<T> name() const { \ return Vec2<T>(a, b); \ } #define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ @@ -366,7 +366,7 @@ public: }; template <typename T, typename V> -Vec3<T> operator*(const V& f, const Vec3<T>& vec) { +constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) { return Vec3<T>(f * vec.x, f * vec.y, f * vec.z); } @@ -387,7 +387,7 @@ inline float Vec3<float>::Normalize() { return length; } -typedef Vec3<float> Vec3f; +using Vec3f = Vec3<float>; template <typename T> class Vec4 { @@ -397,86 +397,88 @@ public: T z{}; T w{}; - Vec4() = default; - Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {} + constexpr Vec4() = default; + constexpr Vec4(const T& x_, const T& y_, const T& z_, const T& w_) + : x(x_), y(y_), z(z_), w(w_) {} template <typename T2> - Vec4<T2> Cast() const { - return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w); + constexpr Vec4<T2> Cast() const { + return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z), + static_cast<T2>(w)); } - // Only implemented for T=int and T=float - static Vec4 FromRGBA(unsigned int rgba); - unsigned int ToRGBA() const; - - static Vec4 AssignToAll(const T& f) { - return Vec4<T>(f, f, f, f); + static constexpr Vec4 AssignToAll(const T& f) { + return Vec4(f, f, f, f); } - Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const { - return MakeVec(x + other.x, y + other.y, z + other.z, w + other.w); + constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const { + return {x + other.x, y + other.y, z + other.z, w + other.w}; } - void operator+=(const Vec4& other) { + + constexpr Vec4& operator+=(const Vec4& other) { x += other.x; y += other.y; z += other.z; w += other.w; + return *this; } - Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const { - return MakeVec(x - other.x, y - other.y, z - other.z, w - other.w); + + constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const { + return {x - other.x, y - other.y, z - other.z, w - other.w}; } - void operator-=(const Vec4& other) { + + constexpr Vec4& operator-=(const Vec4& other) { x -= other.x; y -= other.y; z -= other.z; w -= other.w; + return *this; } template <typename U = T> - Vec4<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const { - return MakeVec(-x, -y, -z, -w); + constexpr Vec4<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const { + return {-x, -y, -z, -w}; } - Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const { - return MakeVec(x * other.x, y * other.y, z * other.z, w * other.w); + + constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const { + return {x * other.x, y * other.y, z * other.z, w * other.w}; } + template <typename V> - Vec4<decltype(T{} * V{})> operator*(const V& f) const { - return MakeVec(x * f, y * f, z * f, w * f); + constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const { + return {x * f, y * f, z * f, w * f}; } + template <typename V> - void operator*=(const V& f) { + constexpr Vec4& operator*=(const V& f) { *this = *this * f; + return *this; } + template <typename V> - Vec4<decltype(T{} / V{})> operator/(const V& f) const { - return MakeVec(x / f, y / f, z / f, w / f); + constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const { + return {x / f, y / f, z / f, w / f}; } + template <typename V> - void operator/=(const V& f) { + constexpr Vec4& operator/=(const V& f) { *this = *this / f; + return *this; } - T Length2() const { + constexpr T Length2() const { return x * x + y * y + z * z + w * w; } - // Only implemented for T=float - float Length() const; - void SetLength(const float l); - Vec4 WithLength(const float l) const; - float Distance2To(Vec4& other); - Vec4 Normalized() const; - float Normalize(); // returns the previous length, which is often useful - - T& operator[](int i) // allow vector[2] = 3 (vector.z=3) - { + constexpr T& operator[](std::size_t i) { return *((&x) + i); } - T operator[](const int i) const { + + constexpr const T& operator[](std::size_t i) const { return *((&x) + i); } - void SetZero() { + constexpr void SetZero() { x = 0; y = 0; z = 0; @@ -484,29 +486,29 @@ public: } // Common alias: RGBA (colors) - T& r() { + constexpr T& r() { return x; } - T& g() { + constexpr T& g() { return y; } - T& b() { + constexpr T& b() { return z; } - T& a() { + constexpr T& a() { return w; } - const T& r() const { + constexpr const T& r() const { return x; } - const T& g() const { + constexpr const T& g() const { return y; } - const T& b() const { + constexpr const T& b() const { return z; } - const T& a() const { + constexpr const T& a() const { return w; } @@ -518,7 +520,7 @@ public: // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and // permutations (xy<->yx) #define _DEFINE_SWIZZLER2(a, b, name) \ - const Vec2<T> name() const { \ + constexpr Vec2<T> name() const { \ return Vec2<T>(a, b); \ } #define DEFINE_SWIZZLER2_COMP1(a, a2) \ @@ -545,7 +547,7 @@ public: #undef _DEFINE_SWIZZLER2 #define _DEFINE_SWIZZLER3(a, b, c, name) \ - const Vec3<T> name() const { \ + constexpr Vec3<T> name() const { \ return Vec3<T>(a, b, c); \ } #define DEFINE_SWIZZLER3_COMP1(a, a2) \ @@ -579,51 +581,51 @@ public: }; template <typename T, typename V> -Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { - return MakeVec(f * vec.x, f * vec.y, f * vec.z, f * vec.w); +constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { + return {f * vec.x, f * vec.y, f * vec.z, f * vec.w}; } -typedef Vec4<float> Vec4f; +using Vec4f = Vec4<float>; template <typename T> -static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) { +constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) { return a.x * b.x + a.y * b.y; } template <typename T> -static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) { +constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) { return a.x * b.x + a.y * b.y + a.z * b.z; } template <typename T> -static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) { +constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } template <typename T> -static inline Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) { - return MakeVec(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); +constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) { + return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; } // linear interpolation via float: 0.0=begin, 1.0=end template <typename X> -static inline decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end, - const float t) { +constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end, + const float t) { return begin * (1.f - t) + end * t; } // linear interpolation via int: 0=begin, base=end template <typename X, int base> -static inline decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end, - const int t) { +constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end, + const int t) { return (begin * (base - t) + end * t) / base; } // bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second // interpolation. template <typename X> -inline auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s, - const float t) { +constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s, + const float t) { auto y0 = Lerp(x00, x01, s); auto y1 = Lerp(x10, x11, s); return Lerp(y0, y1, t); @@ -631,42 +633,42 @@ inline auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x1 // Utility vector factories template <typename T> -static inline Vec2<T> MakeVec(const T& x, const T& y) { +constexpr Vec2<T> MakeVec(const T& x, const T& y) { return Vec2<T>{x, y}; } template <typename T> -static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) { +constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) { return Vec3<T>{x, y, z}; } template <typename T> -static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) { +constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) { return MakeVec(x, y, zw[0], zw[1]); } template <typename T> -static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) { +constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) { return MakeVec(xy[0], xy[1], z); } template <typename T> -static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) { +constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) { return MakeVec(x, yz[0], yz[1]); } template <typename T> -static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) { +constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) { return Vec4<T>{x, y, z, w}; } template <typename T> -static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) { +constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) { return MakeVec(xy[0], xy[1], z, w); } template <typename T> -static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) { +constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) { return MakeVec(x, yz[0], yz[1], w); } @@ -674,17 +676,17 @@ static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) { // Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error // out soon enough due to misuse of the returned structure. template <typename T> -static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) { +constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) { return MakeVec(xy[0], xy[1], zw[0], zw[1]); } template <typename T> -static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) { +constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) { return MakeVec(xyz[0], xyz[1], xyz[2], w); } template <typename T> -static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) { +constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) { return MakeVec(x, yzw[0], yzw[1], yzw[2]); } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c11f017da..cceb1564b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -104,8 +104,6 @@ add_library(core STATIC hle/lock.cpp hle/lock.h hle/result.h - hle/romfs.cpp - hle/romfs.h hle/service/acc/acc.cpp hle/service/acc/acc.h hle/service/acc/acc_aa.cpp @@ -315,6 +313,8 @@ add_library(core STATIC hle/service/time/interface.h hle/service/time/time.cpp hle/service/time/time.h + hle/service/usb/usb.cpp + hle/service/usb/usb.h hle/service/vi/vi.cpp hle/service/vi/vi.h hle/service/vi/vi_m.cpp diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 8cd1f5e6a..d3007d981 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -76,12 +76,17 @@ bool IsValidNCA(const NCAHeader& header) { return header.magic == Common::MakeMagic('N', 'C', 'A', '3'); } -boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const { +u8 NCA::GetCryptoRevision() const { u8 master_key_id = header.crypto_type; if (header.crypto_type_2 > master_key_id) master_key_id = header.crypto_type_2; if (master_key_id > 0) --master_key_id; + return master_key_id; +} + +boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const { + const auto master_key_id = GetCryptoRevision(); if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index)) return boost::none; @@ -108,33 +113,58 @@ boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType ty return out; } -VirtualFile NCA::Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset) const { +boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() const { + const auto master_key_id = GetCryptoRevision(); + + u128 rights_id{}; + memcpy(rights_id.data(), header.rights_id.data(), 16); + if (rights_id == u128{}) + return boost::none; + + auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]); + if (titlekey == Core::Crypto::Key128{}) + return boost::none; + Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( + keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id), Core::Crypto::Mode::ECB); + cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(), Core::Crypto::Op::Decrypt); + + return titlekey; +} + +VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting_offset) const { if (!encrypted) return in; - switch (header.raw.header.crypto_type) { + switch (s_header.raw.header.crypto_type) { case NCASectionCryptoType::NONE: LOG_DEBUG(Crypto, "called with mode=NONE"); return in; case NCASectionCryptoType::CTR: LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset); { - const auto key = GetKeyAreaKey(NCASectionCryptoType::CTR); + boost::optional<Core::Crypto::Key128> key = boost::none; + if (std::find_if_not(header.rights_id.begin(), header.rights_id.end(), + [](char c) { return c == 0; }) == header.rights_id.end()) { + key = GetKeyAreaKey(NCASectionCryptoType::CTR); + } else { + key = GetTitlekey(); + } + if (key == boost::none) return nullptr; auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>( std::move(in), key.value(), starting_offset); std::vector<u8> iv(16); for (u8 i = 0; i < 8; ++i) - iv[i] = header.raw.section_ctr[0x8 - i - 1]; + iv[i] = s_header.raw.section_ctr[0x8 - i - 1]; out->SetIV(iv); return std::static_pointer_cast<VfsFile>(out); } case NCASectionCryptoType::XTS: - // TODO(DarkLordZach): Implement XTSEncryptionLayer and title key encryption. + // TODO(DarkLordZach): Implement XTSEncryptionLayer. default: LOG_ERROR(Crypto, "called with unhandled crypto type={:02X}", - static_cast<u8>(header.raw.header.crypto_type)); + static_cast<u8>(s_header.raw.header.crypto_type)); return nullptr; } } diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index a984a4d36..5cfd5031a 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -96,7 +96,9 @@ protected: bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; private: + u8 GetCryptoRevision() const; boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const; + boost::optional<Core::Crypto::Key128> GetTitlekey() const; VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset) const; std::vector<VirtualDir> dirs; diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 7933c105c..134e41ebc 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -14,8 +14,8 @@ namespace Kernel { -ClientPort::ClientPort() {} -ClientPort::~ClientPort() {} +ClientPort::ClientPort() = default; +ClientPort::~ClientPort() = default; ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { // Note: Threads do not wait for the server endpoint to call @@ -40,4 +40,12 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { return MakeResult(std::get<SharedPtr<ClientSession>>(sessions)); } +void ClientPort::ConnectionClosed() { + if (active_sessions == 0) { + return; + } + + --active_sessions; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index b42c94bde..b1269ea5c 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -37,14 +37,20 @@ public: */ ResultVal<SharedPtr<ClientSession>> Connect(); - SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. - u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have - u32 active_sessions; ///< Number of currently open sessions to this port - std::string name; ///< Name of client port (optional) + /** + * Signifies that a previously active connection has been closed, + * decreasing the total number of active connections to this port. + */ + void ConnectionClosed(); private: ClientPort(); ~ClientPort() override; + + SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. + u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have + u32 active_sessions = 0; ///< Number of currently open sessions to this port + std::string name; ///< Name of client port (optional) }; } // namespace Kernel diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 60370e9ec..93560152f 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -27,7 +27,7 @@ ServerSession::~ServerSession() { // Decrease the port's connection count. if (parent->port) - parent->port->active_sessions--; + parent->port->ConnectionClosed(); // TODO(Subv): Wake up all the ClientSession's waiting threads and set // the SendSyncRequest result to 0xC920181A. diff --git a/src/core/hle/romfs.cpp b/src/core/hle/romfs.cpp deleted file mode 100644 index 3157df71d..000000000 --- a/src/core/hle/romfs.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <cstring> -#include "common/swap.h" -#include "core/hle/romfs.h" - -namespace RomFS { - -struct Header { - u32_le header_length; - u32_le dir_hash_table_offset; - u32_le dir_hash_table_length; - u32_le dir_table_offset; - u32_le dir_table_length; - u32_le file_hash_table_offset; - u32_le file_hash_table_length; - u32_le file_table_offset; - u32_le file_table_length; - u32_le data_offset; -}; - -static_assert(sizeof(Header) == 0x28, "Header has incorrect size"); - -struct DirectoryMetadata { - u32_le parent_dir_offset; - u32_le next_dir_offset; - u32_le first_child_dir_offset; - u32_le first_file_offset; - u32_le same_hash_next_dir_offset; - u32_le name_length; // in bytes - // followed by directory name -}; - -static_assert(sizeof(DirectoryMetadata) == 0x18, "DirectoryMetadata has incorrect size"); - -struct FileMetadata { - u32_le parent_dir_offset; - u32_le next_file_offset; - u64_le data_offset; - u64_le data_length; - u32_le same_hash_next_file_offset; - u32_le name_length; // in bytes - // followed by file name -}; - -static_assert(sizeof(FileMetadata) == 0x20, "FileMetadata has incorrect size"); - -static bool MatchName(const u8* buffer, u32 name_length, const std::u16string& name) { - std::vector<char16_t> name_buffer(name_length / sizeof(char16_t)); - std::memcpy(name_buffer.data(), buffer, name_length); - return name == std::u16string(name_buffer.begin(), name_buffer.end()); -} - -const u8* GetFilePointer(const u8* romfs, const std::vector<std::u16string>& path) { - constexpr u32 INVALID_FIELD = 0xFFFFFFFF; - - // Split path into directory names and file name - std::vector<std::u16string> dir_names = path; - dir_names.pop_back(); - const std::u16string& file_name = path.back(); - - Header header; - std::memcpy(&header, romfs, sizeof(header)); - - // Find directories of each level - DirectoryMetadata dir; - const u8* current_dir = romfs + header.dir_table_offset; - std::memcpy(&dir, current_dir, sizeof(dir)); - for (const std::u16string& dir_name : dir_names) { - u32 child_dir_offset; - child_dir_offset = dir.first_child_dir_offset; - while (true) { - if (child_dir_offset == INVALID_FIELD) { - return nullptr; - } - const u8* current_child_dir = romfs + header.dir_table_offset + child_dir_offset; - std::memcpy(&dir, current_child_dir, sizeof(dir)); - if (MatchName(current_child_dir + sizeof(dir), dir.name_length, dir_name)) { - current_dir = current_child_dir; - break; - } - child_dir_offset = dir.next_dir_offset; - } - } - - // Find the file - FileMetadata file; - u32 file_offset = dir.first_file_offset; - while (file_offset != INVALID_FIELD) { - const u8* current_file = romfs + header.file_table_offset + file_offset; - std::memcpy(&file, current_file, sizeof(file)); - if (MatchName(current_file + sizeof(file), file.name_length, file_name)) { - return romfs + header.data_offset + file.data_offset; - } - file_offset = file.next_file_offset; - } - return nullptr; -} - -} // namespace RomFS diff --git a/src/core/hle/romfs.h b/src/core/hle/romfs.h deleted file mode 100644 index ee9f29760..000000000 --- a/src/core/hle/romfs.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <string> -#include <vector> -#include "common/common_types.h" - -namespace RomFS { - -/** - * Gets the pointer to a file in a RomFS image. - * @param romfs The pointer to the RomFS image - * @param path A vector containing the directory names and file name of the path to the file - * @return the pointer to the file - * @todo reimplement this with a full RomFS manager - */ -const u8* GetFilePointer(const u8* romfs, const std::vector<std::u16string>& path); - -} // namespace RomFS diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 6d15b46ed..e952b0518 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -119,6 +119,13 @@ private: } }; +void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_ACC, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(1); +} + void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_ACC, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index 0a01d954c..88cabaa01 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -14,6 +14,7 @@ public: public: explicit Interface(std::shared_ptr<Module> module, const char* name); + void GetUserCount(Kernel::HLERequestContext& ctx); void GetUserExistence(Kernel::HLERequestContext& ctx); void ListAllUsers(Kernel::HLERequestContext& ctx); void ListOpenUsers(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 9ffb40b22..8b2a71f37 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp @@ -8,7 +8,7 @@ namespace Service::Account { ACC_SU::ACC_SU(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:su") { static const FunctionInfo functions[] = { - {0, nullptr, "GetUserCount"}, + {0, &ACC_SU::GetUserCount, "GetUserCount"}, {1, &ACC_SU::GetUserExistence, "GetUserExistence"}, {2, &ACC_SU::ListAllUsers, "ListAllUsers"}, {3, &ACC_SU::ListOpenUsers, "ListOpenUsers"}, diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 44e21ac09..d84c8b2e1 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -8,7 +8,7 @@ namespace Service::Account { ACC_U0::ACC_U0(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u0") { static const FunctionInfo functions[] = { - {0, nullptr, "GetUserCount"}, + {0, &ACC_U0::GetUserCount, "GetUserCount"}, {1, &ACC_U0::GetUserExistence, "GetUserExistence"}, {2, &ACC_U0::ListAllUsers, "ListAllUsers"}, {3, &ACC_U0::ListOpenUsers, "ListOpenUsers"}, diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index d101d4e0d..0ceaf06b5 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp @@ -8,7 +8,7 @@ namespace Service::Account { ACC_U1::ACC_U1(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u1") { static const FunctionInfo functions[] = { - {0, nullptr, "GetUserCount"}, + {0, &ACC_U1::GetUserCount, "GetUserCount"}, {1, &ACC_U1::GetUserExistence, "GetUserExistence"}, {2, &ACC_U1::ListAllUsers, "ListAllUsers"}, {3, &ACC_U1::ListOpenUsers, "ListOpenUsers"}, diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index 7a185c6c8..4109cb7f7 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp @@ -13,6 +13,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) { auto module_ = std::make_shared<Module>(); std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager); std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager); + std::make_shared<APM_Sys>()->InstallAsService(service_manager); } } // namespace Service::APM diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index ce943d829..4cd8132f5 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp @@ -74,6 +74,31 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<ISession>(); + + LOG_DEBUG(Service_APM, "called"); +} + +APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RequestPerformanceMode"}, + {1, &APM_Sys::GetPerformanceEvent, "GetPerformanceEvent"}, + {2, nullptr, "GetThrottlingState"}, + {3, nullptr, "GetLastThrottlingState"}, + {4, nullptr, "ClearLastThrottlingState"}, + {5, nullptr, "LoadAndApplySettings"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISession>(); + + LOG_DEBUG(Service_APM, "called"); } } // namespace Service::APM diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h index fa68c7d93..d14264ad7 100644 --- a/src/core/hle/service/apm/interface.h +++ b/src/core/hle/service/apm/interface.h @@ -19,4 +19,12 @@ private: std::shared_ptr<Module> apm; }; +class APM_Sys final : public ServiceFramework<APM_Sys> { +public: + explicit APM_Sys(); + +private: + void GetPerformanceEvent(Kernel::HLERequestContext& ctx); +}; + } // namespace Service::APM diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index ed53f96c5..dcdfa0e19 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -337,6 +337,7 @@ public: "AcquireNpadStyleSetUpdateEventHandle"}, {107, nullptr, "DisconnectNpad"}, {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, + {109, nullptr, "ActivateNpadWithRevision"}, {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, @@ -456,7 +457,7 @@ private: } void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. rb.Push(true); diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 2b74e6a33..8bc49935a 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -7,8 +7,8 @@ #include "core/core.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" #include "core/hle/service/nvdrv/devices/nvmap.h" +#include "video_core/gpu.h" #include "video_core/renderer_base.h" -#include "video_core/video_core.h" namespace Service::Nvidia::Devices { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 4b601781f..be2b79256 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -2,14 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <cinttypes> +#include <cstring> #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" #include "core/hle/service/nvdrv/devices/nvmap.h" +#include "video_core/memory_manager.h" +#include "video_core/rasterizer_interface.h" #include "video_core/renderer_base.h" -#include "video_core/video_core.h" namespace Service::Nvidia::Devices { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 671b092e1..5685eb2be 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -2,6 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cstdlib> +#include <cstring> + #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 090261a60..6b496e9fe 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -5,8 +5,6 @@ #pragma once #include <array> -#include <cstdlib> -#include <cstring> #include <vector> #include "common/common_types.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 010072a5b..ae421247d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <cinttypes> +#include <cstring> #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 5a1123ad2..116dabedb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -2,12 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <cinttypes> -#include <map> +#include <cstring> #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" +#include "core/memory.h" +#include "video_core/gpu.h" +#include "video_core/memory_manager.h" namespace Service::Nvidia::Devices { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index aa8df2e6e..650ed8fbc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -6,6 +6,7 @@ #include <memory> #include <vector> +#include "common/bit_field.h" #include "common/common_types.h" #include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index b51c73ee8..364619e67 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cstring> + #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 0192aecdd..6ad74421b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -4,11 +4,9 @@ #pragma once -#include <array> -#include <cstdlib> -#include <cstring> #include <vector> #include "common/common_types.h" +#include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" namespace Service::Nvidia::Devices { diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 724eeb139..e9305bfb3 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #include <algorithm> -#include <cinttypes> +#include <cstring> #include "common/assert.h" #include "common/logging/log.h" diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 959b5ba29..1c3529bb6 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -5,7 +5,6 @@ #pragma once #include <memory> -#include <string> #include "core/hle/kernel/event.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/service.h" diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 1555ea806..427f4b574 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -16,19 +16,18 @@ #include "core/hle/service/nvdrv/interface.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/nvmemp.h" +#include "core/hle/service/nvflinger/nvflinger.h" namespace Service::Nvidia { -std::weak_ptr<Module> nvdrv; - -void InstallInterfaces(SM::ServiceManager& service_manager) { +void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger) { auto module_ = std::make_shared<Module>(); std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager); std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager); std::make_shared<NVDRV>(module_, "nvdrv:t")->InstallAsService(service_manager); std::make_shared<NVMEMP>()->InstallAsService(service_manager); - nvdrv = module_; + nvflinger.SetNVDrvInstance(module_); } Module::Module() { @@ -54,7 +53,7 @@ u32 Module::Open(const std::string& device_name) { return fd; } -u32 Module::Ioctl(u32 fd, u32_le command, const std::vector<u8>& input, std::vector<u8>& output) { +u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output) { auto itr = open_files.find(fd); ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 184f3c9fc..99eb1128a 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -10,6 +10,10 @@ #include "common/common_types.h" #include "core/hle/service/service.h" +namespace Service::NVFlinger { +class NVFlinger; +} + namespace Service::Nvidia { namespace Devices { @@ -56,8 +60,6 @@ private: }; /// Registers all NVDRV services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); - -extern std::weak_ptr<Module> nvdrv; +void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger); } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp index 9ca6e5512..0e8e21bad 100644 --- a/src/core/hle/service/nvdrv/nvmemp.cpp +++ b/src/core/hle/service/nvdrv/nvmemp.cpp @@ -4,8 +4,6 @@ #include "common/assert.h" #include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/nvmemp.h" namespace Service::Nvidia { diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 0bf51062c..a26a5f812 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -3,8 +3,11 @@ // Refer to the license.txt file included. #include <algorithm> +#include <boost/optional.hpp> #include "common/alignment.h" +#include "common/assert.h" +#include "common/logging/log.h" #include "common/microprofile.h" #include "common/scope_exit.h" #include "core/core.h" @@ -31,7 +34,7 @@ NVFlinger::NVFlinger() { // Schedule the screen composition events composition_event = - CoreTiming::RegisterEvent("ScreenCompositioin", [this](u64 userdata, int cycles_late) { + CoreTiming::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) { Compose(); CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event); }); @@ -43,7 +46,11 @@ NVFlinger::~NVFlinger() { CoreTiming::UnscheduleEvent(composition_event, 0); } -u64 NVFlinger::OpenDisplay(const std::string& name) { +void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { + nvdrv = std::move(instance); +} + +u64 NVFlinger::OpenDisplay(std::string_view name) { LOG_WARNING(Service, "Opening display {}", name); // TODO(Subv): Currently we only support the Default display. @@ -138,9 +145,6 @@ void NVFlinger::Compose() { auto& igbp_buffer = buffer->igbp_buffer; // Now send the buffer to the GPU for drawing. - auto nvdrv = Nvidia::nvdrv.lock(); - ASSERT(nvdrv); - // TODO(Subv): Support more than just disp0. The display device selection is probably based // on which display we're drawing (Default, Internal, External, etc) auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 2c908297b..f7112949f 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -5,13 +5,21 @@ #pragma once #include <memory> -#include <boost/optional.hpp> +#include <string> +#include <string_view> +#include <vector> + +#include "common/common_types.h" #include "core/hle/kernel/event.h" namespace CoreTiming { struct EventType; } +namespace Service::Nvidia { +class Module; +} + namespace Service::NVFlinger { class BufferQueue; @@ -40,8 +48,11 @@ public: NVFlinger(); ~NVFlinger(); + /// Sets the NVDrv module instance to use to send buffers to the GPU. + void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance); + /// Opens the specified display and returns the id. - u64 OpenDisplay(const std::string& name); + u64 OpenDisplay(std::string_view name); /// Creates a layer on the specified display and returns the layer id. u64 CreateLayer(u64 display_id); @@ -66,6 +77,8 @@ private: /// Returns the layer identified by the specified id in the desired display. Layer& GetLayer(u64 display_id, u64 layer_id); + std::shared_ptr<Nvidia::Module> nvdrv; + std::vector<Display> displays; std::vector<std::shared_ptr<BufferQueue>> buffer_queues; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 31ea79773..6f286ea74 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -63,6 +63,7 @@ #include "core/hle/service/spl/module.h" #include "core/hle/service/ssl/ssl.h" #include "core/hle/service/time/time.h" +#include "core/hle/service/usb/usb.h" #include "core/hle/service/vi/vi.h" #include "core/hle/service/wlan/wlan.h" @@ -237,7 +238,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) { NIFM::InstallInterfaces(*sm); NIM::InstallInterfaces(*sm); NS::InstallInterfaces(*sm); - Nvidia::InstallInterfaces(*sm); + Nvidia::InstallInterfaces(*sm, *nv_flinger); PCIe::InstallInterfaces(*sm); PCTL::InstallInterfaces(*sm); PCV::InstallInterfaces(*sm); @@ -249,6 +250,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) { SPL::InstallInterfaces(*sm); SSL::InstallInterfaces(*sm); Time::InstallInterfaces(*sm); + USB::InstallInterfaces(*sm); VI::InstallInterfaces(*sm, nv_flinger); WLAN::InstallInterfaces(*sm); diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 37b58bb77..2172c681b 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -80,8 +80,8 @@ public: {5, nullptr, "GetTimeZoneRuleVersion"}, {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, - {200, nullptr, "ToPosixTime"}, - {201, nullptr, "ToPosixTimeWithMyRule"}, + {201, nullptr, "ToPosixTime"}, + {202, nullptr, "ToPosixTimeWithMyRule"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp new file mode 100644 index 000000000..e7fb5a419 --- /dev/null +++ b/src/core/hle/service/usb/usb.cpp @@ -0,0 +1,238 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/usb/usb.h" + +namespace Service::USB { + +class IDsInterface final : public ServiceFramework<IDsInterface> { +public: + explicit IDsInterface() : ServiceFramework{"IDsInterface"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetDsEndpoint"}, + {1, nullptr, "GetSetupEvent"}, + {2, nullptr, "Unknown"}, + {3, nullptr, "EnableInterface"}, + {4, nullptr, "DisableInterface"}, + {5, nullptr, "CtrlInPostBufferAsync"}, + {6, nullptr, "CtrlOutPostBufferAsync"}, + {7, nullptr, "GetCtrlInCompletionEvent"}, + {8, nullptr, "GetCtrlInReportData"}, + {9, nullptr, "GetCtrlOutCompletionEvent"}, + {10, nullptr, "GetCtrlOutReportData"}, + {11, nullptr, "StallCtrl"}, + {12, nullptr, "AppendConfigurationData"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class USB_DS final : public ServiceFramework<USB_DS> { +public: + explicit USB_DS() : ServiceFramework{"usb:ds"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "BindDevice"}, + {1, nullptr, "BindClientProcess"}, + {2, nullptr, "GetDsInterface"}, + {3, nullptr, "GetStateChangeEvent"}, + {4, nullptr, "GetState"}, + {5, nullptr, "ClearDeviceData"}, + {6, nullptr, "AddUsbStringDescriptor"}, + {7, nullptr, "DeleteUsbStringDescriptor"}, + {8, nullptr, "SetUsbDeviceDescriptor"}, + {9, nullptr, "SetBinaryObjectStore"}, + {10, nullptr, "Enable"}, + {11, nullptr, "Disable"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IClientEpSession final : public ServiceFramework<IClientEpSession> { +public: + explicit IClientEpSession() : ServiceFramework{"IClientEpSession"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "Unknown3"}, + {3, nullptr, "Unknown4"}, + {4, nullptr, "PostBufferAsync"}, + {5, nullptr, "Unknown5"}, + {6, nullptr, "Unknown6"}, + {7, nullptr, "Unknown7"}, + {8, nullptr, "Unknown8"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IClientIfSession final : public ServiceFramework<IClientIfSession> { +public: + explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "Unknown3"}, + {3, nullptr, "Unknown4"}, + {4, nullptr, "Unknown5"}, + {5, nullptr, "CtrlXferAsync"}, + {6, nullptr, "Unknown6"}, + {7, nullptr, "GetCtrlXferReport"}, + {8, nullptr, "Unknown7"}, + {9, nullptr, "GetClientEpSession"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class USB_HS final : public ServiceFramework<USB_HS> { +public: + explicit USB_HS() : ServiceFramework{"usb:hs"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "BindClientProcess"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, + {6, nullptr, "GetInterfaceStateChangeEvent"}, + {7, nullptr, "GetClientIfSession"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IPdSession final : public ServiceFramework<IPdSession> { +public: + explicit IPdSession() : ServiceFramework{"IPdSession"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "BindNoticeEvent"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "GetStatus"}, + {3, nullptr, "GetNotice"}, + {4, nullptr, "Unknown2"}, + {5, nullptr, "Unknown3"}, + {6, nullptr, "ReplyPowerRequest"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class USB_PD final : public ServiceFramework<USB_PD> { +public: + explicit USB_PD() : ServiceFramework{"usb:pd"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &USB_PD::GetPdSession, "GetPdSession"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void GetPdSession(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IPdSession>(); + + LOG_DEBUG(Service_USB, "called"); + } +}; + +class IPdCradleSession final : public ServiceFramework<IPdCradleSession> { +public: + explicit IPdCradleSession() : ServiceFramework{"IPdCradleSession"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "VdmUserWrite"}, + {1, nullptr, "VdmUserRead"}, + {2, nullptr, "Vdm20Init"}, + {3, nullptr, "GetFwType"}, + {4, nullptr, "GetFwRevision"}, + {5, nullptr, "GetManufacturerId"}, + {6, nullptr, "GetDeviceId"}, + {7, nullptr, "Unknown1"}, + {8, nullptr, "Unknown2"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class USB_PD_C final : public ServiceFramework<USB_PD_C> { +public: + explicit USB_PD_C() : ServiceFramework{"usb:pd:c"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &USB_PD_C::GetPdCradleSession, "GetPdCradleSession"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void GetPdCradleSession(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IPdCradleSession>(); + + LOG_DEBUG(Service_USB, "called"); + } +}; + +class USB_PM final : public ServiceFramework<USB_PM> { +public: + explicit USB_PM() : ServiceFramework{"usb:pm"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "Unknown3"}, + {3, nullptr, "Unknown4"}, + {4, nullptr, "Unknown5"}, + {5, nullptr, "Unknown6"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<USB_DS>()->InstallAsService(sm); + std::make_shared<USB_HS>()->InstallAsService(sm); + std::make_shared<USB_PD>()->InstallAsService(sm); + std::make_shared<USB_PD_C>()->InstallAsService(sm); + std::make_shared<USB_PM>()->InstallAsService(sm); +} + +} // namespace Service::USB diff --git a/src/core/hle/service/usb/usb.h b/src/core/hle/service/usb/usb.h new file mode 100644 index 000000000..970a11fe8 --- /dev/null +++ b/src/core/hle/service/usb/usb.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::USB { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::USB diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 4a028250b..915d525b0 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -84,7 +84,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( if (dir == nullptr) { if (file == nullptr) return ResultStatus::ErrorInvalidFormat; - const FileSys::VirtualDir dir = file->GetContainingDirectory(); + dir = file->GetContainingDirectory(); } const FileSys::VirtualFile npdm = dir->GetFile("main.npdm"); diff --git a/src/tests/common/param_package.cpp b/src/tests/common/param_package.cpp index 19d372236..4c0f9654f 100644 --- a/src/tests/common/param_package.cpp +++ b/src/tests/common/param_package.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <catch.hpp> +#include <catch2/catch.hpp> #include <math.h> #include "common/param_package.h" diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index fcaa30990..2242c14cf 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include <catch.hpp> +#include <catch2/catch.hpp> #include <array> #include <bitset> diff --git a/src/tests/glad.cpp b/src/tests/glad.cpp index b0b016440..1797c0e3d 100644 --- a/src/tests/glad.cpp +++ b/src/tests/glad.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <catch.hpp> +#include <catch2/catch.hpp> #include <glad/glad.h> // This is not an actual test, but a work-around for issue #2183. diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp index 73978676f..275b430d9 100644 --- a/src/tests/tests.cpp +++ b/src/tests/tests.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #define CATCH_CONFIG_MAIN -#include <catch.hpp> +#include <catch2/catch.hpp> // Catch provides the main function since we've given it the // CATCH_CONFIG_MAIN preprocessor directive. diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 31ea3adad..dc485e811 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -29,10 +29,10 @@ enum class BufferMethods { }; void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) { - LOG_WARNING(HW_GPU, - "Processing method {:08X} on subchannel {} value " - "{:08X} remaining params {}", - method, subchannel, value, remaining_params); + LOG_TRACE(HW_GPU, + "Processing method {:08X} on subchannel {} value " + "{:08X} remaining params {}", + method, subchannel, value, remaining_params); if (method == static_cast<u32>(BufferMethods::BindObject)) { // Bind the current subchannel to the desired engine id. diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 39fcf22b4..0c6652c7a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -204,8 +204,9 @@ struct SurfaceParams { static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) { switch (format) { + // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the + // gamma. case Tegra::RenderTargetFormat::RGBA8_SRGB: - return PixelFormat::SRGBA8; case Tegra::RenderTargetFormat::RGBA8_UNORM: return PixelFormat::ABGR8; case Tegra::RenderTargetFormat::BGRA8_UNORM: diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index d04aa4e31..daa4cc0d9 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -6,9 +6,12 @@ #include "ui_configure.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_dialog.h" +#include "yuzu/hotkeys.h" -ConfigureDialog::ConfigureDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ConfigureDialog) { +ConfigureDialog::ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry) + : QDialog(parent), ui(new Ui::ConfigureDialog) { ui->setupUi(this); + ui->generalTab->PopulateHotkeyList(registry); this->setConfiguration(); } diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index 21fa1f501..bbbdacc29 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -7,6 +7,8 @@ #include <memory> #include <QDialog> +class HotkeyRegistry; + namespace Ui { class ConfigureDialog; } @@ -15,7 +17,7 @@ class ConfigureDialog : public QDialog { Q_OBJECT public: - explicit ConfigureDialog(QWidget* parent); + explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry); ~ConfigureDialog(); void applyConfiguration(); diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 04afc8724..d8caee1e8 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -35,6 +35,10 @@ void ConfigureGeneral::setConfiguration() { ui->use_docked_mode->setChecked(Settings::values.use_docked_mode); } +void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) { + ui->widget->Populate(registry); +} + void ConfigureGeneral::applyConfiguration() { UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked(); UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h index 447552d8c..4770034cc 100644 --- a/src/yuzu/configuration/configure_general.h +++ b/src/yuzu/configuration/configure_general.h @@ -7,6 +7,8 @@ #include <memory> #include <QWidget> +class HotkeyRegistry; + namespace Ui { class ConfigureGeneral; } @@ -18,11 +20,11 @@ public: explicit ConfigureGeneral(QWidget* parent = nullptr); ~ConfigureGeneral(); + void PopulateHotkeyList(const HotkeyRegistry& registry); void applyConfiguration(); private: void setConfiguration(); -private: std::unique_ptr<Ui::ConfigureGeneral> ui; }; diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index 61acb38ee..dce399774 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -10,58 +10,53 @@ #include "yuzu/hotkeys.h" #include "yuzu/ui_settings.h" -struct Hotkey { - Hotkey() : shortcut(nullptr), context(Qt::WindowShortcut) {} +HotkeyRegistry::HotkeyRegistry() = default; +HotkeyRegistry::~HotkeyRegistry() = default; - QKeySequence keyseq; - QShortcut* shortcut; - Qt::ShortcutContext context; -}; - -typedef std::map<QString, Hotkey> HotkeyMap; -typedef std::map<QString, HotkeyMap> HotkeyGroupMap; - -HotkeyGroupMap hotkey_groups; - -void SaveHotkeys() { - UISettings::values.shortcuts.clear(); - for (auto group : hotkey_groups) { - for (auto hotkey : group.second) { - UISettings::values.shortcuts.emplace_back( - UISettings::Shortcut(group.first + "/" + hotkey.first, - UISettings::ContextualShortcut(hotkey.second.keyseq.toString(), - hotkey.second.context))); - } - } -} - -void LoadHotkeys() { +void HotkeyRegistry::LoadHotkeys() { // Make sure NOT to use a reference here because it would become invalid once we call // beginGroup() for (auto shortcut : UISettings::values.shortcuts) { - QStringList cat = shortcut.first.split("/"); + const QStringList cat = shortcut.first.split('/'); Q_ASSERT(cat.size() >= 2); // RegisterHotkey assigns default keybindings, so use old values as default parameters Hotkey& hk = hotkey_groups[cat[0]][cat[1]]; if (!shortcut.second.first.isEmpty()) { hk.keyseq = QKeySequence::fromString(shortcut.second.first); - hk.context = (Qt::ShortcutContext)shortcut.second.second; + hk.context = static_cast<Qt::ShortcutContext>(shortcut.second.second); } if (hk.shortcut) hk.shortcut->setKey(hk.keyseq); } } -void RegisterHotkey(const QString& group, const QString& action, const QKeySequence& default_keyseq, - Qt::ShortcutContext default_context) { - if (hotkey_groups[group].find(action) == hotkey_groups[group].end()) { - hotkey_groups[group][action].keyseq = default_keyseq; - hotkey_groups[group][action].context = default_context; +void HotkeyRegistry::SaveHotkeys() { + UISettings::values.shortcuts.clear(); + for (const auto& group : hotkey_groups) { + for (const auto& hotkey : group.second) { + UISettings::values.shortcuts.emplace_back( + UISettings::Shortcut(group.first + '/' + hotkey.first, + UISettings::ContextualShortcut(hotkey.second.keyseq.toString(), + hotkey.second.context))); + } } } -QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget) { +void HotkeyRegistry::RegisterHotkey(const QString& group, const QString& action, + const QKeySequence& default_keyseq, + Qt::ShortcutContext default_context) { + auto& hotkey_group = hotkey_groups[group]; + if (hotkey_group.find(action) != hotkey_group.end()) { + return; + } + + auto& hotkey_action = hotkey_groups[group][action]; + hotkey_action.keyseq = default_keyseq; + hotkey_action.context = default_context; +} + +QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) { Hotkey& hk = hotkey_groups[group][action]; if (!hk.shortcut) @@ -72,10 +67,12 @@ QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widge GHotkeysDialog::GHotkeysDialog(QWidget* parent) : QWidget(parent) { ui.setupUi(this); +} - for (auto group : hotkey_groups) { +void GHotkeysDialog::Populate(const HotkeyRegistry& registry) { + for (const auto& group : registry.hotkey_groups) { QTreeWidgetItem* toplevel_item = new QTreeWidgetItem(QStringList(group.first)); - for (auto hotkey : group.second) { + for (const auto& hotkey : group.second) { QStringList columns; columns << hotkey.first << hotkey.second.keyseq.toString(); QTreeWidgetItem* item = new QTreeWidgetItem(columns); diff --git a/src/yuzu/hotkeys.h b/src/yuzu/hotkeys.h index a4ccc193b..f38e6c002 100644 --- a/src/yuzu/hotkeys.h +++ b/src/yuzu/hotkeys.h @@ -4,6 +4,7 @@ #pragma once +#include <map> #include "ui_hotkeys.h" class QDialog; @@ -11,47 +12,69 @@ class QKeySequence; class QSettings; class QShortcut; -/** - * Register a hotkey. - * - * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger") - * @param action Name of the action (e.g. "Start Emulation", "Load Image") - * @param default_keyseq Default key sequence to assign if the hotkey wasn't present in the settings - * file before - * @param default_context Default context to assign if the hotkey wasn't present in the settings - * file before - * @warning Both the group and action strings will be displayed in the hotkey settings dialog - */ -void RegisterHotkey(const QString& group, const QString& action, - const QKeySequence& default_keyseq = QKeySequence(), - Qt::ShortcutContext default_context = Qt::WindowShortcut); - -/** - * Returns a QShortcut object whose activated() signal can be connected to other QObjects' slots. - * - * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger"). - * @param action Name of the action (e.g. "Start Emulation", "Load Image"). - * @param widget Parent widget of the returned QShortcut. - * @warning If multiple QWidgets' call this function for the same action, the returned QShortcut - * will be the same. Thus, you shouldn't rely on the caller really being the QShortcut's parent. - */ -QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); - -/** - * Saves all registered hotkeys to the settings file. - * - * @note Each hotkey group will be stored a settings group; For each hotkey inside that group, a - * settings group will be created to store the key sequence and the hotkey context. - */ -void SaveHotkeys(); - -/** - * Loads hotkeys from the settings file. - * - * @note Yet unregistered hotkeys which are present in the settings will automatically be - * registered. - */ -void LoadHotkeys(); +class HotkeyRegistry final { +public: + friend class GHotkeysDialog; + + explicit HotkeyRegistry(); + ~HotkeyRegistry(); + + /** + * Loads hotkeys from the settings file. + * + * @note Yet unregistered hotkeys which are present in the settings will automatically be + * registered. + */ + void LoadHotkeys(); + + /** + * Saves all registered hotkeys to the settings file. + * + * @note Each hotkey group will be stored a settings group; For each hotkey inside that group, a + * settings group will be created to store the key sequence and the hotkey context. + */ + void SaveHotkeys(); + + /** + * Returns a QShortcut object whose activated() signal can be connected to other QObjects' + * slots. + * + * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger"). + * @param action Name of the action (e.g. "Start Emulation", "Load Image"). + * @param widget Parent widget of the returned QShortcut. + * @warning If multiple QWidgets' call this function for the same action, the returned QShortcut + * will be the same. Thus, you shouldn't rely on the caller really being the + * QShortcut's parent. + */ + QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); + + /** + * Register a hotkey. + * + * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger") + * @param action Name of the action (e.g. "Start Emulation", "Load Image") + * @param default_keyseq Default key sequence to assign if the hotkey wasn't present in the + * settings file before + * @param default_context Default context to assign if the hotkey wasn't present in the settings + * file before + * @warning Both the group and action strings will be displayed in the hotkey settings dialog + */ + void RegisterHotkey(const QString& group, const QString& action, + const QKeySequence& default_keyseq = {}, + Qt::ShortcutContext default_context = Qt::WindowShortcut); + +private: + struct Hotkey { + QKeySequence keyseq; + QShortcut* shortcut = nullptr; + Qt::ShortcutContext context = Qt::WindowShortcut; + }; + + using HotkeyMap = std::map<QString, Hotkey>; + using HotkeyGroupMap = std::map<QString, HotkeyMap>; + + HotkeyGroupMap hotkey_groups; +}; class GHotkeysDialog : public QWidget { Q_OBJECT @@ -59,6 +82,8 @@ class GHotkeysDialog : public QWidget { public: explicit GHotkeysDialog(QWidget* parent = nullptr); + void Populate(const HotkeyRegistry& registry); + private: Ui::hotkeys ui; }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 3cba6f403..a6241e63e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -208,43 +208,46 @@ void GMainWindow::InitializeRecentFileMenuActions() { } void GMainWindow::InitializeHotkeys() { - RegisterHotkey("Main Window", "Load File", QKeySequence::Open); - RegisterHotkey("Main Window", "Start Emulation"); - RegisterHotkey("Main Window", "Continue/Pause", QKeySequence(Qt::Key_F4)); - RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen); - RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape), - Qt::ApplicationShortcut); - RegisterHotkey("Main Window", "Toggle Speed Limit", QKeySequence("CTRL+Z"), - Qt::ApplicationShortcut); - LoadHotkeys(); - - connect(GetHotkey("Main Window", "Load File", this), &QShortcut::activated, this, - &GMainWindow::OnMenuLoadFile); - connect(GetHotkey("Main Window", "Start Emulation", this), &QShortcut::activated, this, - &GMainWindow::OnStartGame); - connect(GetHotkey("Main Window", "Continue/Pause", this), &QShortcut::activated, this, [&] { - if (emulation_running) { - if (emu_thread->IsRunning()) { - OnPauseGame(); - } else { - OnStartGame(); - } - } - }); - connect(GetHotkey("Main Window", "Fullscreen", render_window), &QShortcut::activated, - ui.action_Fullscreen, &QAction::trigger); - connect(GetHotkey("Main Window", "Fullscreen", render_window), &QShortcut::activatedAmbiguously, - ui.action_Fullscreen, &QAction::trigger); - connect(GetHotkey("Main Window", "Exit Fullscreen", this), &QShortcut::activated, this, [&] { - if (emulation_running) { - ui.action_Fullscreen->setChecked(false); - ToggleFullscreen(); - } - }); - connect(GetHotkey("Main Window", "Toggle Speed Limit", this), &QShortcut::activated, this, [&] { - Settings::values.toggle_framelimit = !Settings::values.toggle_framelimit; - UpdateStatusBar(); - }); + hotkey_registry.RegisterHotkey("Main Window", "Load File", QKeySequence::Open); + hotkey_registry.RegisterHotkey("Main Window", "Start Emulation"); + hotkey_registry.RegisterHotkey("Main Window", "Continue/Pause", QKeySequence(Qt::Key_F4)); + hotkey_registry.RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen); + hotkey_registry.RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape), + Qt::ApplicationShortcut); + hotkey_registry.RegisterHotkey("Main Window", "Toggle Speed Limit", QKeySequence("CTRL+Z"), + Qt::ApplicationShortcut); + hotkey_registry.LoadHotkeys(); + + connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, + this, &GMainWindow::OnMenuLoadFile); + connect(hotkey_registry.GetHotkey("Main Window", "Start Emulation", this), + &QShortcut::activated, this, &GMainWindow::OnStartGame); + connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause", this), &QShortcut::activated, + this, [&] { + if (emulation_running) { + if (emu_thread->IsRunning()) { + OnPauseGame(); + } else { + OnStartGame(); + } + } + }); + connect(hotkey_registry.GetHotkey("Main Window", "Fullscreen", render_window), + &QShortcut::activated, ui.action_Fullscreen, &QAction::trigger); + connect(hotkey_registry.GetHotkey("Main Window", "Fullscreen", render_window), + &QShortcut::activatedAmbiguously, ui.action_Fullscreen, &QAction::trigger); + connect(hotkey_registry.GetHotkey("Main Window", "Exit Fullscreen", this), + &QShortcut::activated, this, [&] { + if (emulation_running) { + ui.action_Fullscreen->setChecked(false); + ToggleFullscreen(); + } + }); + connect(hotkey_registry.GetHotkey("Main Window", "Toggle Speed Limit", this), + &QShortcut::activated, this, [&] { + Settings::values.toggle_framelimit = !Settings::values.toggle_framelimit; + UpdateStatusBar(); + }); } void GMainWindow::SetDefaultUIGeometry() { @@ -323,7 +326,8 @@ void GMainWindow::ConnectMenuEvents() { connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); // Fullscreen - ui.action_Fullscreen->setShortcut(GetHotkey("Main Window", "Fullscreen", this)->key()); + ui.action_Fullscreen->setShortcut( + hotkey_registry.GetHotkey("Main Window", "Fullscreen", this)->key()); connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); // Help @@ -757,7 +761,7 @@ void GMainWindow::ToggleWindowMode() { } void GMainWindow::OnConfigure() { - ConfigureDialog configureDialog(this); + ConfigureDialog configureDialog(this, hotkey_registry); auto old_theme = UISettings::values.theme; auto result = configureDialog.exec(); if (result == QDialog::Accepted) { @@ -897,7 +901,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) { UISettings::values.first_start = false; game_list->SaveInterfaceLayout(); - SaveHotkeys(); + hotkey_registry.SaveHotkeys(); // Shutdown session if the emu thread is active... if (emu_thread != nullptr) diff --git a/src/yuzu/main.h b/src/yuzu/main.h index a60d831b9..6e335b8f8 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -9,6 +9,7 @@ #include <QTimer> #include "core/core.h" #include "ui_main.h" +#include "yuzu/hotkeys.h" class Config; class EmuThread; @@ -172,6 +173,8 @@ private: // stores default icon theme search paths for the platform QStringList default_theme_paths; + HotkeyRegistry hotkey_registry; + protected: void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override; |