diff options
49 files changed, 739 insertions, 242 deletions
| diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake index e4a9796c8..aaf80b77b 100644 --- a/CMakeModules/CopyYuzuQt5Deps.cmake +++ b/CMakeModules/CopyYuzuQt5Deps.cmake @@ -4,8 +4,10 @@ function(copy_yuzu_Qt5_deps target_dir)      set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")      set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")      set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") +    set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/")      set(PLATFORMS ${DLL_DEST}platforms/)      set(STYLES ${DLL_DEST}styles/) +    set(IMAGEFORMATS ${DLL_DEST}imageformats/)      windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}          icudt*.dll          icuin*.dll @@ -17,4 +19,5 @@ function(copy_yuzu_Qt5_deps target_dir)      )      windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)      windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*) +    windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*)  endfunction(copy_yuzu_Qt5_deps) diff --git a/appveyor.yml b/appveyor.yml index 17d1b5fee..a6f12b267 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -117,6 +117,7 @@ after_build:            mkdir $RELEASE_DIST            mkdir $RELEASE_DIST/platforms            mkdir $RELEASE_DIST/styles +          mkdir $RELEASE_DIST/imageformats            # copy the compiled binaries and other release files to the release folder            Get-ChildItem "$CMAKE_BINARY_DIR" -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST @@ -140,6 +141,9 @@ after_build:            # copy the qt windows vista style dll to platforms            Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/styles/qwindowsvistastyle.dll" -force -destination "$RELEASE_DIST/styles" +          # copy the qt jpeg imageformat dll to platforms +          Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/imageformats/qjpeg.dll" -force -destination "$RELEASE_DIST/imageformats" +            7z a -tzip $MINGW_BUILD_ZIP $RELEASE_DIST\*            7z a $MINGW_SEVENZIP $RELEASE_DIST          } diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index db21f3d50..b6eb36f20 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -32,7 +32,7 @@ add_subdirectory(inih)  # lz4  set(LZ4_BUNDLED_MODE ON) -add_subdirectory(lz4/contrib/cmake_unofficial) +add_subdirectory(lz4/contrib/cmake_unofficial EXCLUDE_FROM_ALL)  target_include_directories(lz4_static INTERFACE ./lz4/lib)  # mbedtls diff --git a/src/common/alignment.h b/src/common/alignment.h index b77da4a92..b9dd38746 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h @@ -9,13 +9,13 @@ namespace Common {  template <typename T>  constexpr T AlignUp(T value, size_t size) { -    static_assert(std::is_unsigned<T>::value, "T must be an unsigned value."); +    static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");      return static_cast<T>(value + (size - value % size) % size);  }  template <typename T>  constexpr T AlignDown(T value, size_t size) { -    static_assert(std::is_unsigned<T>::value, "T must be an unsigned value."); +    static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");      return static_cast<T>(value - value % size);  } diff --git a/src/common/bit_set.h b/src/common/bit_set.h index 84e3cbe58..5a197d8c1 100644 --- a/src/common/bit_set.h +++ b/src/common/bit_set.h @@ -96,7 +96,7 @@ static inline int LeastSignificantSetBit(u64 val) {  template <typename IntTy>  class BitSet { -    static_assert(!std::is_signed<IntTy>::value, "BitSet should not be used with signed types"); +    static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");  public:      // A reference to a particular bit, returned from operator[]. diff --git a/src/common/file_util.h b/src/common/file_util.h index 430dac41c..d0987fb57 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -208,7 +208,7 @@ public:      template <typename T>      size_t ReadArray(T* data, size_t length) const { -        static_assert(std::is_trivially_copyable<T>(), +        static_assert(std::is_trivially_copyable_v<T>,                        "Given array does not consist of trivially copyable objects");          if (!IsOpen()) { @@ -220,7 +220,7 @@ public:      template <typename T>      size_t WriteArray(const T* data, size_t length) { -        static_assert(std::is_trivially_copyable<T>(), +        static_assert(std::is_trivially_copyable_v<T>,                        "Given array does not consist of trivially copyable objects");          if (!IsOpen()) {              return std::numeric_limits<size_t>::max(); @@ -231,19 +231,19 @@ public:      template <typename T>      size_t ReadBytes(T* data, size_t length) const { -        static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable"); +        static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");          return ReadArray(reinterpret_cast<char*>(data), length);      }      template <typename T>      size_t WriteBytes(const T* data, size_t length) { -        static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable"); +        static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");          return WriteArray(reinterpret_cast<const char*>(data), length);      }      template <typename T>      size_t WriteObject(const T& object) { -        static_assert(!std::is_pointer<T>::value, "Given object is a pointer"); +        static_assert(!std::is_pointer_v<T>, "WriteObject arguments must not be a pointer");          return WriteArray(&object, 1);      } diff --git a/src/common/hash.h b/src/common/hash.h index 73c326980..2c761e545 100644 --- a/src/common/hash.h +++ b/src/common/hash.h @@ -28,7 +28,7 @@ static inline u64 ComputeHash64(const void* data, size_t len) {   */  template <typename T>  static inline u64 ComputeStructHash64(const T& data) { -    static_assert(std::is_trivially_copyable<T>(), +    static_assert(std::is_trivially_copyable_v<T>,                    "Type passed to ComputeStructHash64 must be trivially copyable");      return ComputeHash64(&data, sizeof(data));  } @@ -38,7 +38,7 @@ template <typename T>  struct HashableStruct {      // In addition to being trivially copyable, T must also have a trivial default constructor,      // because any member initialization would be overridden by memset -    static_assert(std::is_trivial<T>(), "Type passed to HashableStruct must be trivial"); +    static_assert(std::is_trivial_v<T>, "Type passed to HashableStruct must be trivial");      /*       * We use a union because "implicitly-defined copy/move constructor for a union X copies the       * object representation of X." and "implicitly-defined copy assignment operator for a union X 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/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h index 0f52f704b..ec76e0a47 100644 --- a/src/common/x64/xbyak_util.h +++ b/src/common/x64/xbyak_util.h @@ -34,7 +34,7 @@ inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {  template <typename T>  inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) { -    static_assert(std::is_pointer<T>(), "Argument must be a (function) pointer."); +    static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer.");      size_t addr = reinterpret_cast<size_t>(f);      if (IsWithin2G(code, addr)) {          code.call(f); diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 395eea8ae..e897d9913 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -5,6 +5,7 @@  #include <array>  #include <string>  #include <core/loader/loader.h> +#include "common/logging/log.h"  #include "core/file_sys/card_image.h"  #include "core/file_sys/partition_filesystem.h"  #include "core/file_sys/vfs_offset.h" diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 3529166ac..d3007d981 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -170,6 +170,10 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting  }  NCA::NCA(VirtualFile file_) : file(std::move(file_)) { +    if (file == nullptr) { +        status = Loader::ResultStatus::ErrorInvalidFormat; +        return; +    }      if (sizeof(NCAHeader) != file->ReadObject(&header))          LOG_ERROR(Loader, "File reader errored out during header read."); diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index a8879d9a8..5cfd5031a 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -12,6 +12,7 @@  #include "common/common_funcs.h"  #include "common/common_types.h"  #include "common/swap.h" +#include "control_metadata.h"  #include "core/crypto/key_manager.h"  #include "core/file_sys/partition_filesystem.h"  #include "core/loader/loader.h" diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index cc3b745f7..6582cc240 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -62,6 +62,13 @@ enum class Language : u8 {      Chinese = 14,  }; +static constexpr std::array<const char*, 15> LANGUAGE_NAMES = { +    "AmericanEnglish", "BritishEnglish", "Japanese", +    "French",          "German",         "LatinAmericanSpanish", +    "Spanish",         "Italian",        "Dutch", +    "CanadianFrench",  "Portugese",      "Russian", +    "Korean",          "Taiwanese",      "Chinese"}; +  // A class representing the format used by NX metadata files, typically named Control.nacp.  // These store application name, dev name, title id, and other miscellaneous data.  class NACP { diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 9404d6b8c..762763463 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -136,7 +136,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger          {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},          {17, nullptr, "SetControllerFirmwareUpdateSection"},          {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, -        {19, nullptr, "SetScreenShotImageOrientation"}, +        {19, &ISelfController::SetScreenShotImageOrientation, "SetScreenShotImageOrientation"},          {20, nullptr, "SetDesirableKeyboardLayout"},          {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},          {41, nullptr, "IsSystemBufferSharingEnabled"}, @@ -254,6 +254,13 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext&      LOG_WARNING(Service_AM, "(STUBBED) called");  } +void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); + +    LOG_WARNING(Service_AM, "(STUBBED) called"); +} +  void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {      // TODO(Subv): Find out how AM determines the display to use, for now just create the layer      // in the Default display. diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 8f4f98346..862f338ac 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -83,6 +83,7 @@ private:      void LockExit(Kernel::HLERequestContext& ctx);      void UnlockExit(Kernel::HLERequestContext& ctx);      void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx); +    void SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx);      void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);      void SetScreenShotPermission(Kernel::HLERequestContext& ctx);      void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 116dabedb..4cdf7f613 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -147,7 +147,7 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp      }      params.fence_out.id = 0;      params.fence_out.value = 0; -    std::memcpy(output.data(), ¶ms, output.size()); +    std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo));      return 0;  } diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index e8b30921a..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() { 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/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 570aa8493..a26a5f812 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -46,6 +46,10 @@ NVFlinger::~NVFlinger() {      CoreTiming::UnscheduleEvent(composition_event, 0);  } +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); @@ -141,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 5374df175..f7112949f 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -16,6 +16,10 @@ namespace CoreTiming {  struct EventType;  } +namespace Service::Nvidia { +class Module; +} +  namespace Service::NVFlinger {  class BufferQueue; @@ -44,6 +48,9 @@ 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(std::string_view name); @@ -70,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 889cdd41a..6f286ea74 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -238,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); diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 9a8cdd0ff..915d525b0 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -7,6 +7,7 @@  #include "common/file_util.h"  #include "common/logging/log.h"  #include "core/file_sys/content_archive.h" +#include "core/file_sys/control_metadata.h"  #include "core/gdbstub/gdbstub.h"  #include "core/hle/kernel/process.h"  #include "core/hle/kernel/resource_limit.h" @@ -17,8 +18,50 @@  namespace Loader { -AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file) -    : AppLoader(std::move(file)) {} +AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_) +    : AppLoader(std::move(file_)) { +    const auto dir = file->GetContainingDirectory(); + +    // Icon +    FileSys::VirtualFile icon_file = nullptr; +    for (const auto& language : FileSys::LANGUAGE_NAMES) { +        icon_file = dir->GetFile("icon_" + std::string(language) + ".dat"); +        if (icon_file != nullptr) { +            icon_data = icon_file->ReadAllBytes(); +            break; +        } +    } + +    if (icon_data.empty()) { +        // Any png, jpeg, or bmp file +        const auto& files = dir->GetFiles(); +        const auto icon_iter = +            std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { +                return file->GetExtension() == "png" || file->GetExtension() == "jpg" || +                       file->GetExtension() == "bmp" || file->GetExtension() == "jpeg"; +            }); +        if (icon_iter != files.end()) +            icon_data = (*icon_iter)->ReadAllBytes(); +    } + +    // Metadata +    FileSys::VirtualFile nacp_file = dir->GetFile("control.nacp"); +    if (nacp_file == nullptr) { +        const auto& files = dir->GetFiles(); +        const auto nacp_iter = +            std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { +                return file->GetExtension() == "nacp"; +            }); +        if (nacp_iter != files.end()) +            nacp_file = *nacp_iter; +    } + +    if (nacp_file != nullptr) { +        FileSys::NACP nacp(nacp_file); +        title_id = nacp.GetTitleId(); +        name = nacp.GetApplicationName(); +    } +}  AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(      FileSys::VirtualDir directory) @@ -105,4 +148,25 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile      return ResultStatus::Success;  } +ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) { +    if (icon_data.empty()) +        return ResultStatus::ErrorNotUsed; +    buffer = icon_data; +    return ResultStatus::Success; +} + +ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) { +    if (name.empty()) +        return ResultStatus::ErrorNotUsed; +    out_program_id = title_id; +    return ResultStatus::Success; +} + +ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) { +    if (name.empty()) +        return ResultStatus::ErrorNotUsed; +    title = name; +    return ResultStatus::Success; +} +  } // namespace Loader diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 7d5433563..b20804f75 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -39,11 +39,18 @@ public:      ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;      ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; +    ResultStatus ReadIcon(std::vector<u8>& buffer) override; +    ResultStatus ReadProgramId(u64& out_program_id) override; +    ResultStatus ReadTitle(std::string& title) override;  private:      FileSys::ProgramMetadata metadata;      FileSys::VirtualFile romfs;      FileSys::VirtualDir dir; + +    std::vector<u8> icon_data; +    std::string name; +    u64 title_id{};  };  } // namespace Loader diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 57e6c0365..0781fb8c1 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -68,7 +68,7 @@ FileType GuessFromFilename(const std::string& name) {      return FileType::Unknown;  } -const char* GetFileTypeString(FileType type) { +std::string GetFileTypeString(FileType type) {      switch (type) {      case FileType::ELF:          return "ELF"; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index e69ab85ef..7bd0adedb 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -61,7 +61,7 @@ FileType GuessFromFilename(const std::string& name);  /**   * Convert a FileType into a string which can be displayed to the user.   */ -const char* GetFileTypeString(FileType type); +std::string GetFileTypeString(FileType type);  /// Return type for functions in Loader namespace  enum class ResultStatus { diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index dbc67c0b5..46f5cd393 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -77,8 +77,8 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {  }  ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { -    if (nca == nullptr) -        return ResultStatus::ErrorNotLoaded; +    if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) +        return ResultStatus::ErrorInvalidFormat;      out_program_id = nca->GetTitleId();      return ResultStatus::Success;  } diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 0fd2d0417..7f7d8ea0b 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -33,7 +33,6 @@ public:      ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;      ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; -      ResultStatus ReadProgramId(u64& out_program_id) override;      ~AppLoader_NCA(); @@ -41,6 +40,7 @@ public:  private:      FileSys::ProgramMetadata metadata; +    FileSys::NCAHeader header;      std::unique_ptr<FileSys::NCA> nca;      std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader;  }; diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index eb4dee2c2..d3fe24419 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -26,7 +26,25 @@ namespace Loader {  AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)      : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)),        nca_loader(std::make_unique<AppLoader_NCA>( -          xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {} +          xci->GetNCAFileByType(FileSys::NCAContentType::Program))) { +    if (xci->GetStatus() != ResultStatus::Success) +        return; +    const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); +    if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) +        return; +    const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS()); +    if (romfs == nullptr) +        return; +    for (const auto& language : FileSys::LANGUAGE_NAMES) { +        icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat"); +        if (icon_file != nullptr) +            break; +    } +    const auto nacp_raw = romfs->GetFile("control.nacp"); +    if (nacp_raw == nullptr) +        return; +    nacp_file = std::make_shared<FileSys::NACP>(nacp_raw); +}  AppLoader_XCI::~AppLoader_XCI() = default; @@ -71,4 +89,17 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {      return nca_loader->ReadProgramId(out_program_id);  } +ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { +    if (icon_file == nullptr) +        return ResultStatus::ErrorInvalidFormat; +    buffer = icon_file->ReadAllBytes(); +    return ResultStatus::Success; +} + +ResultStatus AppLoader_XCI::ReadTitle(std::string& title) { +    if (nacp_file == nullptr) +        return ResultStatus::ErrorInvalidFormat; +    title = nacp_file->GetApplicationName(); +    return ResultStatus::Success; +}  } // namespace Loader diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 0dbcfbdf8..973833050 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h @@ -33,12 +33,17 @@ public:      ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;      ResultStatus ReadProgramId(u64& out_program_id) override; +    ResultStatus ReadIcon(std::vector<u8>& buffer) override; +    ResultStatus ReadTitle(std::string& title) override;  private:      FileSys::ProgramMetadata metadata;      std::unique_ptr<FileSys::XCI> xci;      std::unique_ptr<AppLoader_NCA> nca_loader; + +    FileSys::VirtualFile icon_file; +    std::shared_ptr<FileSys::NACP> nacp_file;  };  } // namespace Loader diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 5c0ae8009..ed22a2090 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -238,6 +238,8 @@ void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {      auto& buffer = shader.const_buffers[bind_data.index]; +    ASSERT(bind_data.index < Regs::MaxConstBuffers); +      buffer.enabled = bind_data.valid.Value() != 0;      buffer.index = bind_data.index;      buffer.address = regs.const_buffer.BufferAddress(); diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 4d0ff96a5..0506ac8fe 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -44,7 +44,7 @@ public:          static constexpr size_t MaxShaderProgram = 6;          static constexpr size_t MaxShaderStage = 5;          // Maximum number of const buffers per shader stage. -        static constexpr size_t MaxConstBuffers = 16; +        static constexpr size_t MaxConstBuffers = 18;          enum class QueryMode : u32 {              Write = 0, diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index c7e3fb4b1..0d33c5a5e 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -254,20 +254,15 @@ union Instruction {              BitField<56, 1, u64> invert_b;          } lop32i; -        float GetImm20_19() const { -            float result{}; +        u32 GetImm20_19() const {              u32 imm{static_cast<u32>(imm20_19)};              imm <<= 12;              imm |= negate_imm ? 0x80000000 : 0; -            std::memcpy(&result, &imm, sizeof(imm)); -            return result; +            return imm;          } -        float GetImm20_32() const { -            float result{}; -            s32 imm{static_cast<s32>(imm20_32)}; -            std::memcpy(&result, &imm, sizeof(imm)); -            return result; +        u32 GetImm20_32() const { +            return static_cast<u32>(imm20_32);          }          s32 GetSignedImm20_20() const { diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index b2a83ce0b..4ff4d71c5 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -42,6 +42,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {      case RenderTargetFormat::RGB10_A2_UNORM:      case RenderTargetFormat::BGRA8_UNORM:      case RenderTargetFormat::R32_FLOAT: +    case RenderTargetFormat::R11G11B10_FLOAT:          return 4;      default:          UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast<u32>(format)); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index c2a931469..bf6b5c3a0 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -161,7 +161,7 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,      // assume every shader uses them all.      for (unsigned index = 0; index < 16; ++index) {          auto& attrib = regs.vertex_attrib_format[index]; -        LOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}", +        LOG_TRACE(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",                    index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),                    attrib.offset.Value(), attrib.IsNormalized()); @@ -659,7 +659,10 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr          auto& buffer_draw_state =              state.draw.const_buffers[static_cast<size_t>(stage)][used_buffer.GetIndex()]; -        ASSERT_MSG(buffer.enabled, "Attempted to upload disabled constbuffer"); +        if (!buffer.enabled) { +            continue; +        } +          buffer_draw_state.enabled = true;          buffer_draw_state.bindpoint = current_bindpoint + bindpoint; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index e3217db81..1ff71d682 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -602,12 +602,12 @@ private:      /// Generates code representing a 19-bit immediate value      static std::string GetImmediate19(const Instruction& instr) { -        return std::to_string(instr.alu.GetImm20_19()); +        return fmt::format("uintBitsToFloat({})", instr.alu.GetImm20_19());      }      /// Generates code representing a 32-bit immediate value      static std::string GetImmediate32(const Instruction& instr) { -        return std::to_string(instr.alu.GetImm20_32()); +        return fmt::format("uintBitsToFloat({})", instr.alu.GetImm20_32());      }      /// Generates code representing a texture sampler. diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 24b1d956b..5c7b636e4 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -7,6 +7,10 @@  #include <array>  #include <glad/glad.h> +#include "video_core/engines/maxwell_3d.h" + +using Regs = Tegra::Engines::Maxwell3D::Regs; +  namespace TextureUnits {  struct TextureUnit { @@ -120,7 +124,7 @@ public:              GLuint bindpoint;              GLuint ssbo;          }; -        std::array<std::array<ConstBufferConfig, 16>, 5> const_buffers{}; +        std::array<std::array<ConstBufferConfig, Regs::MaxConstBuffers>, 5> const_buffers;      } draw;      struct { diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 16b1bd606..500d4d4b1 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -27,6 +27,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {      case Maxwell::VertexAttribute::Type::UnsignedNorm: {          switch (attrib.size) { +        case Maxwell::VertexAttribute::Size::Size_8_8:          case Maxwell::VertexAttribute::Size::Size_8_8_8_8:              return GL_UNSIGNED_BYTE;          case Maxwell::VertexAttribute::Size::Size_16_16: diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index bf9131193..899865e3b 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -430,7 +430,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum          break;      case GL_DEBUG_SEVERITY_NOTIFICATION:      case GL_DEBUG_SEVERITY_LOW: -        LOG_DEBUG(Render_OpenGL, format, str_source, str_type, id, message); +        LOG_TRACE(Render_OpenGL, format, str_source, str_type, id, message);          break;      }  } diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 475556806..46ed232d8 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -17,6 +17,8 @@ add_executable(yuzu      configuration/configure_debug.h      configuration/configure_dialog.cpp      configuration/configure_dialog.h +    configuration/configure_gamelist.cpp +    configuration/configure_gamelist.h      configuration/configure_general.cpp      configuration/configure_general.h      configuration/configure_graphics.cpp @@ -59,6 +61,7 @@ set(UIS      configuration/configure.ui      configuration/configure_audio.ui      configuration/configure_debug.ui +    configuration/configure_gamelist.ui      configuration/configure_general.ui      configuration/configure_graphics.ui      configuration/configure_input.ui diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index bf469ee73..0bd46dbac 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -122,6 +122,13 @@ void Config::ReadValues() {      qt_config->beginGroup("UI");      UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); +    qt_config->beginGroup("UIGameList"); +    UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool(); +    UISettings::values.icon_size = qt_config->value("icon_size", 48).toUInt(); +    UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 0).toUInt(); +    UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 3).toUInt(); +    qt_config->endGroup(); +      qt_config->beginGroup("UILayout");      UISettings::values.geometry = qt_config->value("geometry").toByteArray();      UISettings::values.state = qt_config->value("state").toByteArray(); @@ -234,6 +241,13 @@ void Config::SaveValues() {      qt_config->beginGroup("UI");      qt_config->setValue("theme", UISettings::values.theme); +    qt_config->beginGroup("UIGameList"); +    qt_config->setValue("show_unknown", UISettings::values.show_unknown); +    qt_config->setValue("icon_size", UISettings::values.icon_size); +    qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id); +    qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id); +    qt_config->endGroup(); +      qt_config->beginGroup("UILayout");      qt_config->setValue("geometry", UISettings::values.geometry);      qt_config->setValue("state", UISettings::values.state); diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index c8e0b88af..20f120134 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui @@ -24,6 +24,11 @@         <string>General</string>        </attribute>       </widget> +      <widget class="ConfigureGameList" name="gameListTab"> +        <attribute name="title"> +          <string>Game List</string> +        </attribute> +      </widget>       <widget class="ConfigureSystem" name="systemTab">        <attribute name="title">         <string>System</string> @@ -67,6 +72,12 @@     <header>configuration/configure_general.h</header>     <container>1</container>    </customwidget> +   <customwidget> +     <class>ConfigureGameList</class> +     <extends>QWidget</extends> +     <header>configuration/configure_gamelist.h</header> +     <container>1</container> +   </customwidget>    <customwidget>     <class>ConfigureSystem</class>     <extends>QWidget</extends> diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index cc4b326ae..daa4cc0d9 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -21,6 +21,7 @@ void ConfigureDialog::setConfiguration() {}  void ConfigureDialog::applyConfiguration() {      ui->generalTab->applyConfiguration(); +    ui->gameListTab->applyConfiguration();      ui->systemTab->applyConfiguration();      ui->inputTab->applyConfiguration();      ui->graphicsTab->applyConfiguration(); diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp new file mode 100644 index 000000000..1ae3423cf --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.cpp @@ -0,0 +1,63 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/core.h" +#include "core/settings.h" +#include "ui_configure_gamelist.h" +#include "ui_settings.h" +#include "yuzu/configuration/configure_gamelist.h" + +ConfigureGameList::ConfigureGameList(QWidget* parent) +    : QWidget(parent), ui(new Ui::ConfigureGameList) { +    ui->setupUi(this); + +    static const std::vector<std::pair<u32, std::string>> default_icon_sizes{ +        std::make_pair(0, "None"),        std::make_pair(32, "Small"), +        std::make_pair(64, "Standard"),   std::make_pair(128, "Large"), +        std::make_pair(256, "Full Size"), +    }; + +    for (const auto& size : default_icon_sizes) { +        ui->icon_size_combobox->addItem(QString::fromStdString(size.second + " (" + +                                                               std::to_string(size.first) + "x" + +                                                               std::to_string(size.first) + ")"), +                                        size.first); +    } + +    static const std::vector<std::string> row_text_names{ +        "Filename", +        "Filetype", +        "Title ID", +        "Title Name", +    }; + +    for (size_t i = 0; i < row_text_names.size(); ++i) { +        ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]), +                                         QVariant::fromValue(i)); +        ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]), +                                         QVariant::fromValue(i)); +    } + +    this->setConfiguration(); +} + +ConfigureGameList::~ConfigureGameList() {} + +void ConfigureGameList::setConfiguration() { +    ui->show_unknown->setChecked(UISettings::values.show_unknown); +    ui->icon_size_combobox->setCurrentIndex( +        ui->icon_size_combobox->findData(UISettings::values.icon_size)); +    ui->row_1_text_combobox->setCurrentIndex( +        ui->row_1_text_combobox->findData(UISettings::values.row_1_text_id)); +    ui->row_2_text_combobox->setCurrentIndex( +        ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id)); +} + +void ConfigureGameList::applyConfiguration() { +    UISettings::values.show_unknown = ui->show_unknown->isChecked(); +    UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); +    UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); +    UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt(); +    Settings::Apply(); +} diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_gamelist.h new file mode 100644 index 000000000..94fba6373 --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.h @@ -0,0 +1,28 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <QWidget> + +namespace Ui { +class ConfigureGameList; +} + +class ConfigureGameList : public QWidget { +    Q_OBJECT + +public: +    explicit ConfigureGameList(QWidget* parent = nullptr); +    ~ConfigureGameList(); + +    void applyConfiguration(); + +private: +    void setConfiguration(); + +private: +    std::unique_ptr<Ui::ConfigureGameList> ui; +}; diff --git a/src/yuzu/configuration/configure_gamelist.ui b/src/yuzu/configuration/configure_gamelist.ui new file mode 100644 index 000000000..7471fdb60 --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.ui @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ConfigureGameList</class> +  <widget class="QWidget" name="ConfigureGeneral"> +    <property name="geometry"> +      <rect> +        <x>0</x> +        <y>0</y> +        <width>300</width> +        <height>377</height> +      </rect> +    </property> +    <property name="windowTitle"> +      <string>Form</string> +    </property> +    <layout class="QHBoxLayout" name="HorizontalLayout"> +      <item> +        <layout class="QVBoxLayout" name="VerticalLayout"> +          <item> +            <widget class="QGroupBox" name="GeneralGroupBox"> +              <property name="title"> +                <string>General</string> +              </property> +              <layout class="QHBoxLayout" name="GeneralHorizontalLayout"> +                <item> +                  <layout class="QVBoxLayout" name="GeneralVerticalLayout"> +                    <item> +                      <widget class="QCheckBox" name="show_unknown"> +                        <property name="text"> +                          <string>Show files with type 'Unknown'</string> +                        </property> +                      </widget> +                    </item> +                  </layout> +                </item> +              </layout> +            </widget> +          </item> +          <item> +            <widget class="QGroupBox" name="IconSizeGroupBox"> +              <property name="title"> +                <string>Icon Size</string> +              </property> +              <layout class="QHBoxLayout" name="icon_size_qhbox_layout"> +                <item> +                  <layout class="QVBoxLayout" name="icon_size_qvbox_layout"> +                    <item> +                      <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2"> +                        <item> +                          <widget class="QLabel" name="icon_size_label"> +                            <property name="text"> +                              <string>Icon Size:</string> +                            </property> +                          </widget> +                        </item> +                        <item> +                          <widget class="QComboBox" name="icon_size_combobox"/> +                        </item> +                      </layout> +                    </item> +                  </layout> +                </item> +              </layout> +            </widget> +          </item> +          <item> +            <widget class="QGroupBox" name="RowGroupBox"> +              <property name="title"> +                <string>Row Text</string> +              </property> +              <layout class="QHBoxLayout" name="RowHorizontalLayout"> +                <item> +                  <layout class="QVBoxLayout" name="RowVerticalLayout"> +                    <item> +                      <layout class="QHBoxLayout" name="row_1_qhbox_layout"> +                        <item> +                          <widget class="QLabel" name="row_1_label"> +                            <property name="text"> +                              <string>Row 1 Text:</string> +                            </property> +                          </widget> +                        </item> +                        <item> +                          <widget class="QComboBox" name="row_1_text_combobox"/> +                        </item> +                      </layout> +                    </item> +                    <item> +                      <layout class="QHBoxLayout" name="row_2_qhbox_layout"> +                        <item> +                          <widget class="QLabel" name="row_2_label"> +                            <property name="text"> +                              <string>Row 2 Text:</string> +                            </property> +                          </widget> +                        </item> +                        <item> +                          <widget class="QComboBox" name="row_2_text_combobox"/> +                        </item> +                      </layout> +                    </item> +                  </layout> +                </item> +              </layout> +            </widget> +          </item> +          <item> +            <spacer name="verticalSpacer"> +              <property name="orientation"> +                <enum>Qt::Vertical</enum> +              </property> +              <property name="sizeHint" stdset="0"> +                <size> +                  <width>20</width> +                  <height>40</height> +                </size> +              </property> +            </spacer> +          </item> +        </layout> +      </item> +    </layout> +  </widget> + <resources/> + <connections/> +</ui> diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 24f38a3c7..5f47f5a2b 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -9,9 +9,12 @@  #include <QKeyEvent>  #include <QMenu>  #include <QThreadPool> +#include <boost/container/flat_map.hpp>  #include "common/common_paths.h"  #include "common/logging/log.h"  #include "common/string_util.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/control_metadata.h"  #include "core/file_sys/vfs_real.h"  #include "core/loader/loader.h"  #include "game_list.h" @@ -398,8 +401,32 @@ void GameList::RefreshGameDirectory() {  }  void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { -    const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory, -                                            const std::string& virtual_name) -> bool { +    boost::container::flat_map<u64, std::shared_ptr<FileSys::NCA>> nca_control_map; + +    const auto nca_control_callback = +        [this, &nca_control_map](u64* num_entries_out, const std::string& directory, +                                 const std::string& virtual_name) -> bool { +        std::string physical_name = directory + DIR_SEP + virtual_name; + +        if (stop_processing) +            return false; // Breaks the callback loop. + +        bool is_dir = FileUtil::IsDirectory(physical_name); +        QFileInfo file_info(physical_name.c_str()); +        if (!is_dir && file_info.suffix().toStdString() == "nca") { +            auto nca = std::make_shared<FileSys::NCA>( +                std::make_shared<FileSys::RealVfsFile>(physical_name)); +            if (nca->GetType() == FileSys::NCAContentType::Control) +                nca_control_map.insert_or_assign(nca->GetTitleId(), nca); +        } +        return true; +    }; + +    FileUtil::ForeachDirectoryEntry(nullptr, dir_path, nca_control_callback); + +    const auto callback = [this, recursion, +                           &nca_control_map](u64* num_entries_out, const std::string& directory, +                                             const std::string& virtual_name) -> bool {          std::string physical_name = directory + DIR_SEP + virtual_name;          if (stop_processing) @@ -410,17 +437,50 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign              (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {              std::unique_ptr<Loader::AppLoader> loader =                  Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name)); -            if (!loader) +            if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown || +                             loader->GetFileType() == Loader::FileType::Error) && +                            !UISettings::values.show_unknown))                  return true; -            std::vector<u8> smdh; -            loader->ReadIcon(smdh); - -            u64 program_id = 0; -            loader->ReadProgramId(program_id); +            std::vector<u8> icon; +            const auto res1 = loader->ReadIcon(icon); + +            u64 program_id; +            const auto res2 = loader->ReadProgramId(program_id); + +            std::string name = " "; +            const auto res3 = loader->ReadTitle(name); + +            if ((res1 == Loader::ResultStatus::ErrorNotUsed || +                 res1 == Loader::ResultStatus::ErrorNotImplemented) && +                (res3 == Loader::ResultStatus::ErrorNotUsed || +                 res3 == Loader::ResultStatus::ErrorNotImplemented) && +                res2 == Loader::ResultStatus::Success) { +                // Use from metadata pool. +                if (nca_control_map.find(program_id) != nca_control_map.end()) { +                    const auto nca = nca_control_map[program_id]; +                    const auto control_dir = nca->GetSubdirectories()[0]; + +                    const auto nacp_file = control_dir->GetFile("control.nacp"); +                    FileSys::NACP nacp(nacp_file); +                    name = nacp.GetApplicationName(); + +                    FileSys::VirtualFile icon_file = nullptr; +                    for (const auto& language : FileSys::LANGUAGE_NAMES) { +                        icon_file = control_dir->GetFile("icon_" + std::string(language) + ".dat"); +                        if (icon_file != nullptr) { +                            icon = icon_file->ReadAllBytes(); +                            break; +                        } +                    } +                } +            }              emit EntryReady({ -                new GameListItemPath(FormatGameName(physical_name), smdh, program_id), +                new GameListItemPath( +                    FormatGameName(physical_name), icon, QString::fromStdString(name), +                    QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())), +                    program_id),                  new GameListItem(                      QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),                  new GameListItemSize(FileUtil::GetSize(physical_name)), diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index aa69a098f..a22025e67 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -11,6 +11,7 @@  #include <QStandardItem>  #include <QString>  #include "common/string_util.h" +#include "ui_settings.h"  #include "yuzu/util/util.h"  /** @@ -18,8 +19,7 @@   * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)   * @return QPixmap default icon   */ -static QPixmap GetDefaultIcon(bool large) { -    int size = large ? 48 : 24; +static QPixmap GetDefaultIcon(u32 size) {      QPixmap icon(size, size);      icon.fill(Qt::transparent);      return icon; @@ -44,11 +44,25 @@ public:      static const int FullPathRole = Qt::UserRole + 1;      static const int TitleRole = Qt::UserRole + 2;      static const int ProgramIdRole = Qt::UserRole + 3; +    static const int FileTypeRole = Qt::UserRole + 4;      GameListItemPath() = default; -    GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data, u64 program_id) { +    GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data, +                     const QString& game_name, const QString& game_type, u64 program_id) +        : GameListItem() {          setData(game_path, FullPathRole); +        setData(game_name, TitleRole);          setData(qulonglong(program_id), ProgramIdRole); +        setData(game_type, FileTypeRole); + +        QPixmap picture; +        u32 size = UISettings::values.icon_size; +        if (!picture.loadFromData(picture_data.data(), picture_data.size())) +            picture = GetDefaultIcon(size); + +        picture = picture.scaled(size, size); + +        setData(picture, Qt::DecorationRole);      }      QVariant data(int role) const override { @@ -57,7 +71,23 @@ public:              Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename,                                nullptr);              QString title = data(TitleRole).toString(); -            return QString::fromStdString(filename) + (title.isEmpty() ? "" : "\n    " + title); + +            std::vector<QString> row_data{ +                QString::fromStdString(filename), +                data(FileTypeRole).toString(), +                QString::fromStdString(fmt::format("0x{:016X}", data(ProgramIdRole).toULongLong())), +                data(TitleRole).toString(), +            }; + +            auto row1 = row_data.at(UISettings::values.row_1_text_id); +            auto row2 = row_data.at(UISettings::values.row_2_text_id); + +            if (row1.isEmpty() || row1 == row2) +                return row2; +            if (row2.isEmpty()) +                return row1; + +            return row1 + "\n    " + row2;          } else {              return GameListItem::data(role);          } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 17ed62c72..a6241e63e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -768,6 +768,7 @@ void GMainWindow::OnConfigure() {          configureDialog.applyConfiguration();          if (UISettings::values.theme != old_theme)              UpdateUITheme(); +        game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);          config->Save();      }  } diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h index 2286c2559..051494bc5 100644 --- a/src/yuzu/ui_settings.h +++ b/src/yuzu/ui_settings.h @@ -54,6 +54,12 @@ struct Values {      // logging      bool show_console; + +    // Game List +    bool show_unknown; +    uint32_t icon_size; +    uint8_t row_1_text_id; +    uint8_t row_2_text_id;  };  extern Values values; | 
