summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/common/CMakeLists.txt4
-rw-r--r--src/common/bit_field.h17
-rw-r--r--src/common/cityhash.cpp340
-rw-r--r--src/common/cityhash.h110
-rw-r--r--src/common/code_block.h85
-rw-r--r--src/common/common_funcs.h7
-rw-r--r--src/common/common_types.h30
-rw-r--r--src/common/hash.cpp141
-rw-r--r--src/common/hash.h55
-rw-r--r--src/common/math_util.h5
-rw-r--r--src/common/thread.h19
-rw-r--r--src/common/vector_math.h30
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/core.cpp28
-rw-r--r--src/core/core.h12
-rw-r--r--src/core/file_sys/disk_filesystem.cpp14
-rw-r--r--src/core/file_sys/disk_filesystem.h7
-rw-r--r--src/core/file_sys/filesystem.h2
-rw-r--r--src/core/file_sys/partition_filesystem.cpp125
-rw-r--r--src/core/file_sys/partition_filesystem.h87
-rw-r--r--src/core/file_sys/romfs_filesystem.cpp2
-rw-r--r--src/core/file_sys/romfs_filesystem.h2
-rw-r--r--src/core/hle/kernel/resource_limit.cpp46
-rw-r--r--src/core/hle/kernel/resource_limit.h26
-rw-r--r--src/core/hle/kernel/svc.cpp23
-rw-r--r--src/core/hle/kernel/vm_manager.cpp2
-rw-r--r--src/core/hle/service/acc/acc.cpp14
-rw-r--r--src/core/hle/service/acc/acc.h6
-rw-r--r--src/core/hle/service/acc/acc_aa.cpp6
-rw-r--r--src/core/hle/service/acc/acc_aa.h6
-rw-r--r--src/core/hle/service/acc/acc_su.cpp6
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp6
-rw-r--r--src/core/hle/service/acc/acc_u0.h6
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp6
-rw-r--r--src/core/hle/service/acc/acc_u1.h6
-rw-r--r--src/core/hle/service/am/am.cpp6
-rw-r--r--src/core/hle/service/am/applet_ae.cpp6
-rw-r--r--src/core/hle/service/am/applet_oe.cpp6
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp6
-rw-r--r--src/core/hle/service/aoc/aoc_u.h6
-rw-r--r--src/core/hle/service/apm/apm.cpp6
-rw-r--r--src/core/hle/service/apm/apm.h6
-rw-r--r--src/core/hle/service/apm/interface.cpp6
-rw-r--r--src/core/hle/service/apm/interface.h6
-rw-r--r--src/core/hle/service/audio/audin_u.cpp6
-rw-r--r--src/core/hle/service/audio/audin_u.h6
-rw-r--r--src/core/hle/service/audio/audio.cpp6
-rw-r--r--src/core/hle/service/audio/audio.h6
-rw-r--r--src/core/hle/service/audio/audout_u.cpp6
-rw-r--r--src/core/hle/service/audio/audout_u.h6
-rw-r--r--src/core/hle/service/audio/audrec_u.cpp6
-rw-r--r--src/core/hle/service/audio/audrec_u.h6
-rw-r--r--src/core/hle/service/audio/audren_u.cpp6
-rw-r--r--src/core/hle/service/audio/audren_u.h6
-rw-r--r--src/core/hle/service/audio/codecctl.cpp6
-rw-r--r--src/core/hle/service/audio/codecctl.h6
-rw-r--r--src/core/hle/service/fatal/fatal.cpp6
-rw-r--r--src/core/hle/service/fatal/fatal.h6
-rw-r--r--src/core/hle/service/fatal/fatal_p.cpp6
-rw-r--r--src/core/hle/service/fatal/fatal_p.h6
-rw-r--r--src/core/hle/service/fatal/fatal_u.cpp6
-rw-r--r--src/core/hle/service/fatal/fatal_u.h6
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp6
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp32
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h6
-rw-r--r--src/core/hle/service/friend/friend.cpp6
-rw-r--r--src/core/hle/service/friend/friend.h6
-rw-r--r--src/core/hle/service/friend/friend_a.cpp6
-rw-r--r--src/core/hle/service/friend/friend_a.h6
-rw-r--r--src/core/hle/service/friend/friend_u.cpp6
-rw-r--r--src/core/hle/service/friend/friend_u.h6
-rw-r--r--src/core/hle/service/hid/hid.cpp6
-rw-r--r--src/core/hle/service/hid/hid.h6
-rw-r--r--src/core/hle/service/lm/lm.cpp6
-rw-r--r--src/core/hle/service/lm/lm.h6
-rw-r--r--src/core/hle/service/nfp/nfp.cpp6
-rw-r--r--src/core/hle/service/nfp/nfp.h6
-rw-r--r--src/core/hle/service/nfp/nfp_user.cpp6
-rw-r--r--src/core/hle/service/nfp/nfp_user.h6
-rw-r--r--src/core/hle/service/nifm/nifm.cpp6
-rw-r--r--src/core/hle/service/nifm/nifm.h6
-rw-r--r--src/core/hle/service/nifm/nifm_a.cpp6
-rw-r--r--src/core/hle/service/nifm/nifm_a.h6
-rw-r--r--src/core/hle/service/nifm/nifm_s.cpp6
-rw-r--r--src/core/hle/service/nifm/nifm_s.h6
-rw-r--r--src/core/hle/service/nifm/nifm_u.cpp6
-rw-r--r--src/core/hle/service/nifm/nifm_u.h6
-rw-r--r--src/core/hle/service/ns/ns.cpp6
-rw-r--r--src/core/hle/service/ns/ns.h6
-rw-r--r--src/core/hle/service/ns/pl_u.cpp37
-rw-r--r--src/core/hle/service/ns/pl_u.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h9
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h8
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp6
-rw-r--r--src/core/hle/service/nvdrv/interface.h6
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp6
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h6
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.cpp6
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.h6
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp6
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h6
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp9
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h6
-rw-r--r--src/core/hle/service/pctl/pctl.cpp6
-rw-r--r--src/core/hle/service/pctl/pctl.h6
-rw-r--r--src/core/hle/service/pctl/pctl_a.cpp6
-rw-r--r--src/core/hle/service/pctl/pctl_a.h6
-rw-r--r--src/core/hle/service/service.cpp52
-rw-r--r--src/core/hle/service/service.h2
-rw-r--r--src/core/hle/service/set/set.cpp7
-rw-r--r--src/core/hle/service/set/set.h6
-rw-r--r--src/core/hle/service/set/set_cal.cpp15
-rw-r--r--src/core/hle/service/set/set_cal.h6
-rw-r--r--src/core/hle/service/set/set_fd.cpp6
-rw-r--r--src/core/hle/service/set/set_fd.h6
-rw-r--r--src/core/hle/service/set/set_sys.cpp16
-rw-r--r--src/core/hle/service/set/set_sys.h6
-rw-r--r--src/core/hle/service/set/settings.cpp6
-rw-r--r--src/core/hle/service/set/settings.h6
-rw-r--r--src/core/hle/service/sm/controller.cpp6
-rw-r--r--src/core/hle/service/sm/controller.h6
-rw-r--r--src/core/hle/service/sm/sm.cpp10
-rw-r--r--src/core/hle/service/sm/sm.h12
-rw-r--r--src/core/hle/service/sockets/bsd.cpp31
-rw-r--r--src/core/hle/service/sockets/bsd.h6
-rw-r--r--src/core/hle/service/sockets/nsd.cpp6
-rw-r--r--src/core/hle/service/sockets/nsd.h6
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp7
-rw-r--r--src/core/hle/service/sockets/sfdnsres.h6
-rw-r--r--src/core/hle/service/sockets/sockets.cpp6
-rw-r--r--src/core/hle/service/sockets/sockets.h6
-rw-r--r--src/core/hle/service/spl/csrng.cpp6
-rw-r--r--src/core/hle/service/spl/csrng.h6
-rw-r--r--src/core/hle/service/spl/module.cpp6
-rw-r--r--src/core/hle/service/spl/module.h6
-rw-r--r--src/core/hle/service/spl/spl.cpp12
-rw-r--r--src/core/hle/service/spl/spl.h6
-rw-r--r--src/core/hle/service/ssl/ssl.cpp6
-rw-r--r--src/core/hle/service/ssl/ssl.h6
-rw-r--r--src/core/hle/service/time/time.cpp12
-rw-r--r--src/core/hle/service/time/time.h6
-rw-r--r--src/core/hle/service/time/time_s.cpp17
-rw-r--r--src/core/hle/service/time/time_s.h6
-rw-r--r--src/core/hle/service/time/time_u.cpp17
-rw-r--r--src/core/hle/service/time/time_u.h6
-rw-r--r--src/core/hle/service/vi/vi.cpp163
-rw-r--r--src/core/hle/service/vi/vi.h6
-rw-r--r--src/core/hle/service/vi/vi_m.cpp6
-rw-r--r--src/core/hle/service/vi/vi_m.h6
-rw-r--r--src/core/hle/service/vi/vi_s.cpp6
-rw-r--r--src/core/hle/service/vi/vi_s.h6
-rw-r--r--src/core/hle/service/vi/vi_u.cpp7
-rw-r--r--src/core/hle/service/vi/vi_u.h6
-rw-r--r--src/core/perf_stats.cpp3
-rw-r--r--src/input_common/motion_emu.cpp5
-rw-r--r--src/video_core/CMakeLists.txt3
-rw-r--r--src/video_core/engines/maxwell_3d.cpp37
-rw-r--r--src/video_core/engines/maxwell_3d.h118
-rw-r--r--src/video_core/engines/shader_bytecode.h439
-rw-r--r--src/video_core/gpu.h3
-rw-r--r--src/video_core/rasterizer_interface.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp406
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h88
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp191
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h122
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h139
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp791
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.h25
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp68
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h119
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp64
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h175
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp169
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.h56
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp18
-rw-r--r--src/video_core/renderer_opengl/gl_state.h6
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.h2
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h108
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp15
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h2
-rw-r--r--src/video_core/textures/decoders.cpp23
-rw-r--r--src/video_core/textures/decoders.h3
-rw-r--r--src/video_core/textures/texture.h29
-rw-r--r--src/video_core/utils.h2
-rw-r--r--src/yuzu/main.cpp15
-rw-r--r--src/yuzu_cmd/yuzu.cpp9
197 files changed, 3979 insertions, 1710 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 2ba1da195..32cb85de0 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -32,14 +32,14 @@ add_library(common STATIC
break_points.cpp
break_points.h
chunk_file.h
- code_block.h
+ cityhash.cpp
+ cityhash.h
color.h
common_funcs.h
common_paths.h
common_types.h
file_util.cpp
file_util.h
- hash.cpp
hash.h
linear_disk_cache.h
logging/backend.cpp
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 0cc0a1be0..65e357dec 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -115,7 +115,7 @@ private:
// assignment would copy the full storage value, rather than just the bits
// relevant to this particular bit field.
// We don't delete it because we want BitField to be trivially copyable.
- BitField& operator=(const BitField&) = default;
+ constexpr BitField& operator=(const BitField&) = default;
// StorageType is T for non-enum types and the underlying type of T if
// T is an enumeration. Note that T is wrapped within an enable_if in the
@@ -166,20 +166,20 @@ public:
// so that we can use this within unions
constexpr BitField() = default;
- FORCE_INLINE operator T() const {
+ constexpr FORCE_INLINE operator T() const {
return Value();
}
- FORCE_INLINE void Assign(const T& value) {
+ constexpr FORCE_INLINE void Assign(const T& value) {
storage = (storage & ~mask) | FormatValue(value);
}
- FORCE_INLINE T Value() const {
+ constexpr T Value() const {
return ExtractValue(storage);
}
// TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015
- FORCE_INLINE bool ToBool() const {
+ constexpr FORCE_INLINE bool ToBool() const {
return Value() != 0;
}
@@ -192,11 +192,6 @@ private:
static_assert(position < 8 * sizeof(T), "Invalid position");
static_assert(bits <= 8 * sizeof(T), "Invalid number of bits");
static_assert(bits > 0, "Invalid number of bits");
- static_assert(std::is_pod<T>::value, "Invalid base type");
+ static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField");
};
#pragma pack()
-
-#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
-static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value,
- "BitField must be trivially copyable");
-#endif
diff --git a/src/common/cityhash.cpp b/src/common/cityhash.cpp
new file mode 100644
index 000000000..de31ffbd8
--- /dev/null
+++ b/src/common/cityhash.cpp
@@ -0,0 +1,340 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// CityHash, by Geoff Pike and Jyrki Alakuijala
+//
+// This file provides CityHash64() and related functions.
+//
+// It's probably possible to create even faster hash functions by
+// writing a program that systematically explores some of the space of
+// possible hash functions, by using SIMD instructions, or by
+// compromising on hash quality.
+
+#include <algorithm>
+#include <string.h> // for memcpy and memset
+#include "cityhash.h"
+#include "common/swap.h"
+
+// #include "config.h"
+#ifdef __GNUC__
+#define HAVE_BUILTIN_EXPECT 1
+#endif
+#ifdef COMMON_BIG_ENDIAN
+#define WORDS_BIGENDIAN 1
+#endif
+
+using namespace std;
+
+typedef uint8_t uint8;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+
+namespace Common {
+
+static uint64 UNALIGNED_LOAD64(const char* p) {
+ uint64 result;
+ memcpy(&result, p, sizeof(result));
+ return result;
+}
+
+static uint32 UNALIGNED_LOAD32(const char* p) {
+ uint32 result;
+ memcpy(&result, p, sizeof(result));
+ return result;
+}
+
+#ifdef WORDS_BIGENDIAN
+#define uint32_in_expected_order(x) (swap32(x))
+#define uint64_in_expected_order(x) (swap64(x))
+#else
+#define uint32_in_expected_order(x) (x)
+#define uint64_in_expected_order(x) (x)
+#endif
+
+#if !defined(LIKELY)
+#if HAVE_BUILTIN_EXPECT
+#define LIKELY(x) (__builtin_expect(!!(x), 1))
+#else
+#define LIKELY(x) (x)
+#endif
+#endif
+
+static uint64 Fetch64(const char* p) {
+ return uint64_in_expected_order(UNALIGNED_LOAD64(p));
+}
+
+static uint32 Fetch32(const char* p) {
+ return uint32_in_expected_order(UNALIGNED_LOAD32(p));
+}
+
+// Some primes between 2^63 and 2^64 for various uses.
+static const uint64 k0 = 0xc3a5c85c97cb3127ULL;
+static const uint64 k1 = 0xb492b66fbe98f273ULL;
+static const uint64 k2 = 0x9ae16a3b2f90404fULL;
+
+// Bitwise right rotate. Normally this will compile to a single
+// instruction, especially if the shift is a manifest constant.
+static uint64 Rotate(uint64 val, int shift) {
+ // Avoid shifting by 64: doing so yields an undefined result.
+ return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
+}
+
+static uint64 ShiftMix(uint64 val) {
+ return val ^ (val >> 47);
+}
+
+static uint64 HashLen16(uint64 u, uint64 v) {
+ return Hash128to64(uint128(u, v));
+}
+
+static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
+ // Murmur-inspired hashing.
+ uint64 a = (u ^ v) * mul;
+ a ^= (a >> 47);
+ uint64 b = (v ^ a) * mul;
+ b ^= (b >> 47);
+ b *= mul;
+ return b;
+}
+
+static uint64 HashLen0to16(const char* s, size_t len) {
+ if (len >= 8) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch64(s) + k2;
+ uint64 b = Fetch64(s + len - 8);
+ uint64 c = Rotate(b, 37) * mul + a;
+ uint64 d = (Rotate(a, 25) + b) * mul;
+ return HashLen16(c, d, mul);
+ }
+ if (len >= 4) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch32(s);
+ return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
+ }
+ if (len > 0) {
+ uint8 a = s[0];
+ uint8 b = s[len >> 1];
+ uint8 c = s[len - 1];
+ uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8);
+ uint32 z = static_cast<uint32>(len) + (static_cast<uint32>(c) << 2);
+ return ShiftMix(y * k2 ^ z * k0) * k2;
+ }
+ return k2;
+}
+
+// This probably works well for 16-byte strings as well, but it may be overkill
+// in that case.
+static uint64 HashLen17to32(const char* s, size_t len) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch64(s) * k1;
+ uint64 b = Fetch64(s + 8);
+ uint64 c = Fetch64(s + len - 8) * mul;
+ uint64 d = Fetch64(s + len - 16) * k2;
+ return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d, a + Rotate(b + k2, 18) + c, mul);
+}
+
+// Return a 16-byte hash for 48 bytes. Quick and dirty.
+// Callers do best to use "random-looking" values for a and b.
+static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y, uint64 z, uint64 a,
+ uint64 b) {
+ a += w;
+ b = Rotate(b + a + z, 21);
+ uint64 c = a;
+ a += x;
+ a += y;
+ b += Rotate(a, 44);
+ return make_pair(a + z, b + c);
+}
+
+// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
+static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint64 b) {
+ return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
+ b);
+}
+
+// Return an 8-byte hash for 33 to 64 bytes.
+static uint64 HashLen33to64(const char* s, size_t len) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch64(s) * k2;
+ uint64 b = Fetch64(s + 8);
+ uint64 c = Fetch64(s + len - 24);
+ uint64 d = Fetch64(s + len - 32);
+ uint64 e = Fetch64(s + 16) * k2;
+ uint64 f = Fetch64(s + 24) * 9;
+ uint64 g = Fetch64(s + len - 8);
+ uint64 h = Fetch64(s + len - 16) * mul;
+ uint64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
+ uint64 v = ((a + g) ^ d) + f + 1;
+ uint64 w = swap64((u + v) * mul) + h;
+ uint64 x = Rotate(e + f, 42) + c;
+ uint64 y = (swap64((v + w) * mul) + g) * mul;
+ uint64 z = e + f + c;
+ a = swap64((x + z) * mul + y) + b;
+ b = ShiftMix((z + a) * mul + d + h) * mul;
+ return b + x;
+}
+
+uint64 CityHash64(const char* s, size_t len) {
+ if (len <= 32) {
+ if (len <= 16) {
+ return HashLen0to16(s, len);
+ } else {
+ return HashLen17to32(s, len);
+ }
+ } else if (len <= 64) {
+ return HashLen33to64(s, len);
+ }
+
+ // For strings over 64 bytes we hash the end first, and then as we
+ // loop we keep 56 bytes of state: v, w, x, y, and z.
+ uint64 x = Fetch64(s + len - 40);
+ uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
+ uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
+ pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
+ pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
+ x = x * k1 + Fetch64(s);
+
+ // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
+ len = (len - 1) & ~static_cast<size_t>(63);
+ do {
+ x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+ y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+ x ^= w.second;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate(z + w.first, 33) * k1;
+ v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ std::swap(z, x);
+ s += 64;
+ len -= 64;
+ } while (len != 0);
+ return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z,
+ HashLen16(v.second, w.second) + x);
+}
+
+uint64 CityHash64WithSeed(const char* s, size_t len, uint64 seed) {
+ return CityHash64WithSeeds(s, len, k2, seed);
+}
+
+uint64 CityHash64WithSeeds(const char* s, size_t len, uint64 seed0, uint64 seed1) {
+ return HashLen16(CityHash64(s, len) - seed0, seed1);
+}
+
+// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
+// of any length representable in signed long. Based on City and Murmur.
+static uint128 CityMurmur(const char* s, size_t len, uint128 seed) {
+ uint64 a = Uint128Low64(seed);
+ uint64 b = Uint128High64(seed);
+ uint64 c = 0;
+ uint64 d = 0;
+ signed long l = static_cast<long>(len) - 16;
+ if (l <= 0) { // len <= 16
+ a = ShiftMix(a * k1) * k1;
+ c = b * k1 + HashLen0to16(s, len);
+ d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c));
+ } else { // len > 16
+ c = HashLen16(Fetch64(s + len - 8) + k1, a);
+ d = HashLen16(b + len, c + Fetch64(s + len - 16));
+ a += d;
+ do {
+ a ^= ShiftMix(Fetch64(s) * k1) * k1;
+ a *= k1;
+ b ^= a;
+ c ^= ShiftMix(Fetch64(s + 8) * k1) * k1;
+ c *= k1;
+ d ^= c;
+ s += 16;
+ l -= 16;
+ } while (l > 0);
+ }
+ a = HashLen16(a, c);
+ b = HashLen16(d, b);
+ return uint128(a ^ b, HashLen16(b, a));
+}
+
+uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) {
+ if (len < 128) {
+ return CityMurmur(s, len, seed);
+ }
+
+ // We expect len >= 128 to be the common case. Keep 56 bytes of state:
+ // v, w, x, y, and z.
+ pair<uint64, uint64> v, w;
+ uint64 x = Uint128Low64(seed);
+ uint64 y = Uint128High64(seed);
+ uint64 z = len * k1;
+ v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
+ v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
+ w.first = Rotate(y + z, 35) * k1 + x;
+ w.second = Rotate(x + Fetch64(s + 88), 53) * k1;
+
+ // This is the same inner loop as CityHash64(), manually unrolled.
+ do {
+ x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+ y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+ x ^= w.second;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate(z + w.first, 33) * k1;
+ v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ std::swap(z, x);
+ s += 64;
+ x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+ y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+ x ^= w.second;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate(z + w.first, 33) * k1;
+ v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ std::swap(z, x);
+ s += 64;
+ len -= 128;
+ } while (LIKELY(len >= 128));
+ x += Rotate(v.first + z, 49) * k0;
+ y = y * k0 + Rotate(w.second, 37);
+ z = z * k0 + Rotate(w.first, 27);
+ w.first *= 9;
+ v.first *= k0;
+ // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
+ for (size_t tail_done = 0; tail_done < len;) {
+ tail_done += 32;
+ y = Rotate(x + y, 42) * k0 + v.second;
+ w.first += Fetch64(s + len - tail_done + 16);
+ x = x * k0 + w.first;
+ z += w.second + Fetch64(s + len - tail_done);
+ w.second += v.first;
+ v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
+ v.first *= k0;
+ }
+ // At this point our 56 bytes of state should contain more than
+ // enough information for a strong 128-bit hash. We use two
+ // different 56-byte-to-8-byte hashes to get a 16-byte final result.
+ x = HashLen16(x, v.first);
+ y = HashLen16(y + z, w.first);
+ return uint128(HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second));
+}
+
+uint128 CityHash128(const char* s, size_t len) {
+ return len >= 16
+ ? CityHash128WithSeed(s + 16, len - 16, uint128(Fetch64(s), Fetch64(s + 8) + k0))
+ : CityHash128WithSeed(s, len, uint128(k0, k1));
+}
+
+} // namespace Common
diff --git a/src/common/cityhash.h b/src/common/cityhash.h
new file mode 100644
index 000000000..bcebdb150
--- /dev/null
+++ b/src/common/cityhash.h
@@ -0,0 +1,110 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// CityHash, by Geoff Pike and Jyrki Alakuijala
+//
+// http://code.google.com/p/cityhash/
+//
+// This file provides a few functions for hashing strings. All of them are
+// high-quality functions in the sense that they pass standard tests such
+// as Austin Appleby's SMHasher. They are also fast.
+//
+// For 64-bit x86 code, on short strings, we don't know of anything faster than
+// CityHash64 that is of comparable quality. We believe our nearest competitor
+// is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash
+// tables and most other hashing (excluding cryptography).
+//
+// For 64-bit x86 code, on long strings, the picture is more complicated.
+// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,
+// CityHashCrc128 appears to be faster than all competitors of comparable
+// quality. CityHash128 is also good but not quite as fast. We believe our
+// nearest competitor is Bob Jenkins' Spooky. We don't have great data for
+// other 64-bit CPUs, but for long strings we know that Spooky is slightly
+// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.
+// Note that CityHashCrc128 is declared in citycrc.h.
+//
+// For 32-bit x86 code, we don't know of anything faster than CityHash32 that
+// is of comparable quality. We believe our nearest competitor is Murmur3A.
+// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)
+//
+// Functions in the CityHash family are not suitable for cryptography.
+//
+// Please see CityHash's README file for more details on our performance
+// measurements and so on.
+//
+// WARNING: This code has been only lightly tested on big-endian platforms!
+// It is known to work well on little-endian platforms that have a small penalty
+// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.
+// It should work on all 32-bit and 64-bit platforms that allow unaligned reads;
+// bug reports are welcome.
+//
+// By the way, for some hash functions, given strings a and b, the hash
+// of a+b is easily derived from the hashes of a and b. This property
+// doesn't hold for any hash functions in this file.
+
+#pragma once
+
+#include <utility>
+#include <stdint.h>
+#include <stdlib.h> // for size_t.
+
+namespace Common {
+
+typedef std::pair<uint64_t, uint64_t> uint128;
+
+inline uint64_t Uint128Low64(const uint128& x) {
+ return x.first;
+}
+inline uint64_t Uint128High64(const uint128& x) {
+ return x.second;
+}
+
+// Hash function for a byte array.
+uint64_t CityHash64(const char* buf, size_t len);
+
+// Hash function for a byte array. For convenience, a 64-bit seed is also
+// hashed into the result.
+uint64_t CityHash64WithSeed(const char* buf, size_t len, uint64_t seed);
+
+// Hash function for a byte array. For convenience, two seeds are also
+// hashed into the result.
+uint64_t CityHash64WithSeeds(const char* buf, size_t len, uint64_t seed0, uint64_t seed1);
+
+// Hash function for a byte array.
+uint128 CityHash128(const char* s, size_t len);
+
+// Hash function for a byte array. For convenience, a 128-bit seed is also
+// hashed into the result.
+uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed);
+
+// Hash 128 input bits down to 64 bits of output.
+// This is intended to be a reasonably good hash function.
+inline uint64_t Hash128to64(const uint128& x) {
+ // Murmur-inspired hashing.
+ const uint64_t kMul = 0x9ddfea08eb382d69ULL;
+ uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
+ a ^= (a >> 47);
+ uint64_t b = (Uint128High64(x) ^ a) * kMul;
+ b ^= (b >> 47);
+ b *= kMul;
+ return b;
+}
+
+} // namespace Common
diff --git a/src/common/code_block.h b/src/common/code_block.h
deleted file mode 100644
index 6a55a8e30..000000000
--- a/src/common/code_block.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <cstddef>
-#include "common/common_types.h"
-#include "common/memory_util.h"
-
-// Everything that needs to generate code should inherit from this.
-// You get memory management for free, plus, you can use all emitter functions without
-// having to prefix them with gen-> or something similar.
-// Example implementation:
-// class JIT : public CodeBlock<ARMXEmitter> {}
-template <class T>
-class CodeBlock : public T, NonCopyable {
-private:
- // A privately used function to set the executable RAM space to something invalid.
- // For debugging usefulness it should be used to set the RAM to a host specific breakpoint
- // instruction
- virtual void PoisonMemory() = 0;
-
-protected:
- u8* region;
- size_t region_size;
-
-public:
- CodeBlock() : region(nullptr), region_size(0) {}
- virtual ~CodeBlock() {
- if (region)
- FreeCodeSpace();
- }
-
- // Call this before you generate any code.
- void AllocCodeSpace(int size) {
- region_size = size;
- region = (u8*)AllocateExecutableMemory(region_size);
- T::SetCodePtr(region);
- }
-
- // Always clear code space with breakpoints, so that if someone accidentally executes
- // uninitialized, it just breaks into the debugger.
- void ClearCodeSpace() {
- PoisonMemory();
- ResetCodePtr();
- }
-
- // Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
- void FreeCodeSpace() {
-#ifdef __SYMBIAN32__
- ResetExecutableMemory(region);
-#else
- FreeMemoryPages(region, region_size);
-#endif
- region = nullptr;
- region_size = 0;
- }
-
- bool IsInSpace(const u8* ptr) {
- return (ptr >= region) && (ptr < (region + region_size));
- }
-
- // Cannot currently be undone. Will write protect the entire code region.
- // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
- void WriteProtect() {
- WriteProtectMemory(region, region_size, true);
- }
-
- void ResetCodePtr() {
- T::SetCodePtr(region);
- }
-
- size_t GetSpaceLeft() const {
- return region_size - (T::GetCodePtr() - region);
- }
-
- u8* GetBasePtr() {
- return region;
- }
-
- size_t GetOffset(const u8* ptr) const {
- return ptr - region;
- }
-};
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 6f0604958..7cf7b7997 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -9,8 +9,6 @@
#endif
#include "common/common_types.h"
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-
/// Textually concatenates two tokens. The double-expansion is required by the C preprocessor.
#define CONCAT2(x, y) DO_CONCAT2(x, y)
#define DO_CONCAT2(x, y) x##y
@@ -74,11 +72,6 @@ inline u64 _rotr64(u64 x, unsigned int shift) {
#else // _MSC_VER
-#if (_MSC_VER < 1900)
-// Function Cross-Compatibility
-#define snprintf _snprintf
-#endif
-
// Locale Cross-Compatibility
#define locale_t _locale_t
diff --git a/src/common/common_types.h b/src/common/common_types.h
index 844d34965..6b1766dca 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -27,29 +27,23 @@
#include <array>
#include <cstdint>
-#ifdef _MSC_VER
-#ifndef __func__
-#define __func__ __FUNCTION__
-#endif
-#endif
+using u8 = std::uint8_t; ///< 8-bit unsigned byte
+using u16 = std::uint16_t; ///< 16-bit unsigned short
+using u32 = std::uint32_t; ///< 32-bit unsigned word
+using u64 = std::uint64_t; ///< 64-bit unsigned int
-typedef std::uint8_t u8; ///< 8-bit unsigned byte
-typedef std::uint16_t u16; ///< 16-bit unsigned short
-typedef std::uint32_t u32; ///< 32-bit unsigned word
-typedef std::uint64_t u64; ///< 64-bit unsigned int
+using s8 = std::int8_t; ///< 8-bit signed byte
+using s16 = std::int16_t; ///< 16-bit signed short
+using s32 = std::int32_t; ///< 32-bit signed word
+using s64 = std::int64_t; ///< 64-bit signed int
-typedef std::int8_t s8; ///< 8-bit signed byte
-typedef std::int16_t s16; ///< 16-bit signed short
-typedef std::int32_t s32; ///< 32-bit signed word
-typedef std::int64_t s64; ///< 64-bit signed int
-
-typedef float f32; ///< 32-bit floating point
-typedef double f64; ///< 64-bit floating point
+using f32 = float; ///< 32-bit floating point
+using f64 = double; ///< 64-bit floating point
// TODO: It would be nice to eventually replace these with strong types that prevent accidental
// conversion between each other.
-typedef u64 VAddr; ///< Represents a pointer in the userspace virtual address space.
-typedef u64 PAddr; ///< Represents a pointer in the ARM11 physical address space.
+using VAddr = u64; ///< Represents a pointer in the userspace virtual address space.
+using PAddr = u64; ///< Represents a pointer in the ARM11 physical address space.
using u128 = std::array<std::uint64_t, 2>;
static_assert(sizeof(u128) == 16, "u128 must be 128 bits wide");
diff --git a/src/common/hash.cpp b/src/common/hash.cpp
deleted file mode 100644
index a02e9e5b9..000000000
--- a/src/common/hash.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#if defined(_MSC_VER)
-#include <stdlib.h>
-#endif
-#include "common/common_funcs.h"
-#include "common/common_types.h"
-#include "common/hash.h"
-
-namespace Common {
-
-// MurmurHash3 was written by Austin Appleby, and is placed in the public
-// domain. The author hereby disclaims copyright to this source code.
-
-// Block read - if your platform needs to do endian-swapping or can only handle aligned reads, do
-// the conversion here
-static FORCE_INLINE u64 getblock64(const u64* p, size_t i) {
- return p[i];
-}
-
-// Finalization mix - force all bits of a hash block to avalanche
-static FORCE_INLINE u64 fmix64(u64 k) {
- k ^= k >> 33;
- k *= 0xff51afd7ed558ccdllu;
- k ^= k >> 33;
- k *= 0xc4ceb9fe1a85ec53llu;
- k ^= k >> 33;
-
- return k;
-}
-
-// This is the 128-bit variant of the MurmurHash3 hash function that is targeted for 64-bit
-// platforms (MurmurHash3_x64_128). It was taken from:
-// https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
-void MurmurHash3_128(const void* key, size_t len, u32 seed, void* out) {
- const u8* data = (const u8*)key;
- const size_t nblocks = len / 16;
-
- u64 h1 = seed;
- u64 h2 = seed;
-
- const u64 c1 = 0x87c37b91114253d5llu;
- const u64 c2 = 0x4cf5ad432745937fllu;
-
- // Body
-
- const u64* blocks = (const u64*)(data);
-
- for (size_t i = 0; i < nblocks; i++) {
- u64 k1 = getblock64(blocks, i * 2 + 0);
- u64 k2 = getblock64(blocks, i * 2 + 1);
-
- k1 *= c1;
- k1 = _rotl64(k1, 31);
- k1 *= c2;
- h1 ^= k1;
-
- h1 = _rotl64(h1, 27);
- h1 += h2;
- h1 = h1 * 5 + 0x52dce729;
-
- k2 *= c2;
- k2 = _rotl64(k2, 33);
- k2 *= c1;
- h2 ^= k2;
-
- h2 = _rotl64(h2, 31);
- h2 += h1;
- h2 = h2 * 5 + 0x38495ab5;
- }
-
- // Tail
-
- const u8* tail = (const u8*)(data + nblocks * 16);
-
- u64 k1 = 0;
- u64 k2 = 0;
-
- switch (len & 15) {
- case 15:
- k2 ^= ((u64)tail[14]) << 48;
- case 14:
- k2 ^= ((u64)tail[13]) << 40;
- case 13:
- k2 ^= ((u64)tail[12]) << 32;
- case 12:
- k2 ^= ((u64)tail[11]) << 24;
- case 11:
- k2 ^= ((u64)tail[10]) << 16;
- case 10:
- k2 ^= ((u64)tail[9]) << 8;
- case 9:
- k2 ^= ((u64)tail[8]) << 0;
- k2 *= c2;
- k2 = _rotl64(k2, 33);
- k2 *= c1;
- h2 ^= k2;
-
- case 8:
- k1 ^= ((u64)tail[7]) << 56;
- case 7:
- k1 ^= ((u64)tail[6]) << 48;
- case 6:
- k1 ^= ((u64)tail[5]) << 40;
- case 5:
- k1 ^= ((u64)tail[4]) << 32;
- case 4:
- k1 ^= ((u64)tail[3]) << 24;
- case 3:
- k1 ^= ((u64)tail[2]) << 16;
- case 2:
- k1 ^= ((u64)tail[1]) << 8;
- case 1:
- k1 ^= ((u64)tail[0]) << 0;
- k1 *= c1;
- k1 = _rotl64(k1, 31);
- k1 *= c2;
- h1 ^= k1;
- };
-
- // Finalization
-
- h1 ^= len;
- h2 ^= len;
-
- h1 += h2;
- h2 += h1;
-
- h1 = fmix64(h1);
- h2 = fmix64(h2);
-
- h1 += h2;
- h2 += h1;
-
- ((u64*)out)[0] = h1;
- ((u64*)out)[1] = h2;
-}
-
-} // namespace Common
diff --git a/src/common/hash.h b/src/common/hash.h
index ee2560dad..73c326980 100644
--- a/src/common/hash.h
+++ b/src/common/hash.h
@@ -5,12 +5,12 @@
#pragma once
#include <cstddef>
+#include <cstring>
+#include "common/cityhash.h"
#include "common/common_types.h"
namespace Common {
-void MurmurHash3_128(const void* key, size_t len, u32 seed, void* out);
-
/**
* Computes a 64-bit hash over the specified block of data
* @param data Block of data to compute hash over
@@ -18,9 +18,54 @@ void MurmurHash3_128(const void* key, size_t len, u32 seed, void* out);
* @returns 64-bit hash value that was computed over the data block
*/
static inline u64 ComputeHash64(const void* data, size_t len) {
- u64 res[2];
- MurmurHash3_128(data, len, 0, res);
- return res[0];
+ return CityHash64(static_cast<const char*>(data), len);
+}
+
+/**
+ * Computes a 64-bit hash of a struct. In addition to being trivially copyable, it is also critical
+ * that either the struct includes no padding, or that any padding is initialized to a known value
+ * by memsetting the struct to 0 before filling it in.
+ */
+template <typename T>
+static inline u64 ComputeStructHash64(const T& data) {
+ static_assert(std::is_trivially_copyable<T>(),
+ "Type passed to ComputeStructHash64 must be trivially copyable");
+ return ComputeHash64(&data, sizeof(data));
}
+/// A helper template that ensures the padding in a struct is initialized by memsetting to 0.
+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");
+ /*
+ * 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
+ * copies the object representation (3.9) of X." = Bytewise copy instead of memberwise copy.
+ * This is important because the padding bytes are included in the hash and comparison between
+ * objects.
+ */
+ union {
+ T state;
+ };
+
+ HashableStruct() {
+ // Memset structure to zero padding bits, so that they will be deterministic when hashing
+ std::memset(&state, 0, sizeof(T));
+ }
+
+ bool operator==(const HashableStruct<T>& o) const {
+ return std::memcmp(&state, &o.state, sizeof(T)) == 0;
+ };
+
+ bool operator!=(const HashableStruct<T>& o) const {
+ return !(*this == o);
+ };
+
+ size_t Hash() const {
+ return Common::ComputeStructHash64(state);
+ }
+};
+
} // namespace Common
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 45a1ed367..c6a83c953 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -17,11 +17,6 @@ inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start
return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1));
}
-template <typename T>
-inline T Clamp(const T val, const T& min, const T& max) {
- return std::max(min, std::min(max, val));
-}
-
template <class T>
struct Rectangle {
T left;
diff --git a/src/common/thread.h b/src/common/thread.h
index fa475ab51..9465e1de7 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -11,25 +11,6 @@
#include <thread>
#include "common/common_types.h"
-// Support for C++11's thread_local keyword was surprisingly spotty in compilers until very
-// recently. Fortunately, thread local variables have been well supported for compilers for a while,
-// but with semantics supporting only POD types, so we can use a few defines to get some amount of
-// backwards compat support.
-// WARNING: This only works correctly with POD types.
-#if defined(__clang__)
-#if !__has_feature(cxx_thread_local)
-#define thread_local __thread
-#endif
-#elif defined(__GNUC__)
-#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
-#define thread_local __thread
-#endif
-#elif defined(_MSC_VER)
-#if _MSC_VER < 1900
-#define thread_local __declspec(thread)
-#endif
-#endif
-
namespace Common {
int CurrentThreadId();
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 3f0057d9e..3f15ac1f4 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -55,10 +55,6 @@ public:
T x;
T y;
- T* AsArray() {
- return &x;
- }
-
Vec2() = default;
Vec2(const T& _x, const T& _y) : x(_x), y(_y) {}
@@ -71,11 +67,6 @@ public:
return Vec2<T>(f, f);
}
- void Write(T a[2]) {
- a[0] = x;
- a[1] = y;
- }
-
Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
return MakeVec(x + other.x, y + other.y);
}
@@ -205,10 +196,6 @@ public:
T y;
T z;
- T* AsArray() {
- return &x;
- }
-
Vec3() = default;
Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {}
@@ -225,12 +212,6 @@ public:
return MakeVec(f, f, f);
}
- void Write(T a[3]) {
- a[0] = x;
- a[1] = y;
- a[2] = z;
- }
-
Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
return MakeVec(x + other.x, y + other.y, z + other.z);
}
@@ -416,10 +397,6 @@ public:
T z;
T w;
- T* AsArray() {
- return &x;
- }
-
Vec4() = default;
Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {}
@@ -436,13 +413,6 @@ public:
return Vec4<T>(f, f, f, f);
}
- void Write(T a[4]) {
- a[0] = x;
- a[1] = y;
- a[2] = z;
- a[3] = w;
- }
-
Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
return MakeVec(x + other.x, y + other.y, z + other.z, w + other.w);
}
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9877b83fe..c1a645460 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -12,6 +12,8 @@ add_library(core STATIC
file_sys/errors.h
file_sys/filesystem.cpp
file_sys/filesystem.h
+ file_sys/partition_filesystem.cpp
+ file_sys/partition_filesystem.h
file_sys/path_parser.cpp
file_sys/path_parser.h
file_sys/program_metadata.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 9f5507a65..ee4af4dcc 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -12,10 +12,13 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/service.h"
+#include "core/hle/service/sm/controller.h"
+#include "core/hle/service/sm/sm.h"
#include "core/hw/hw.h"
#include "core/loader/loader.h"
#include "core/memory_setup.h"
@@ -26,6 +29,8 @@ namespace Core {
/*static*/ System System::s_instance;
+System::~System() = default;
+
System::ResultStatus System::RunLoop(bool tight_loop) {
status = ResultStatus::Success;
if (!cpu_core) {
@@ -167,10 +172,12 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
telemetry_session = std::make_unique<Core::TelemetrySession>();
+ service_manager = std::make_shared<Service::SM::ServiceManager>();
+
HW::Init();
Kernel::Init(system_mode);
scheduler = std::make_unique<Kernel::Scheduler>(cpu_core.get());
- Service::Init();
+ Service::Init(service_manager);
GDBStub::Init();
if (!VideoCore::Init(emu_window)) {
@@ -200,17 +207,26 @@ void System::Shutdown() {
VideoCore::Shutdown();
GDBStub::Shutdown();
Service::Shutdown();
- scheduler = nullptr;
+ scheduler.reset();
Kernel::Shutdown();
HW::Shutdown();
- telemetry_session = nullptr;
- gpu_core = nullptr;
- cpu_core = nullptr;
+ service_manager.reset();
+ telemetry_session.reset();
+ gpu_core.reset();
+ cpu_core.reset();
CoreTiming::Shutdown();
- app_loader = nullptr;
+ app_loader.reset();
LOG_DEBUG(Core, "Shutdown OK");
}
+Service::SM::ServiceManager& System::ServiceManager() {
+ return *service_manager;
+}
+
+const Service::SM::ServiceManager& System::ServiceManager() const {
+ return *service_manager;
+}
+
} // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index f497dc022..f81cbfb3c 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -19,10 +19,16 @@
class EmuWindow;
class ARM_Interface;
+namespace Service::SM {
+class ServiceManager;
+}
+
namespace Core {
class System {
public:
+ ~System();
+
/**
* Gets the instance of the System singleton class.
* @returns Reference to the instance of the System singleton class.
@@ -137,6 +143,9 @@ public:
return *app_loader;
}
+ Service::SM::ServiceManager& ServiceManager();
+ const Service::SM::ServiceManager& ServiceManager() const;
+
void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) {
debug_context = std::move(context);
}
@@ -171,6 +180,9 @@ private:
/// When true, signals that a reschedule should happen
bool reschedule_pending{};
+ /// Service manager
+ std::shared_ptr<Service::SM::ServiceManager> service_manager;
+
/// Telemetry session for this emulation session
std::unique_ptr<Core::TelemetrySession> telemetry_session;
diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp
index 4235f3935..ca1323873 100644
--- a/src/core/file_sys/disk_filesystem.cpp
+++ b/src/core/file_sys/disk_filesystem.cpp
@@ -57,10 +57,14 @@ ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::
std::make_unique<Disk_Storage>(std::move(file)));
}
-ResultCode Disk_FileSystem::DeleteFile(const Path& path) const {
- LOG_WARNING(Service_FS, "(STUBBED) called");
- // TODO(bunnei): Use correct error code
- return ResultCode(-1);
+ResultCode Disk_FileSystem::DeleteFile(const std::string& path) const {
+ if (!FileUtil::Exists(path)) {
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+ FileUtil::Delete(path);
+
+ return RESULT_SUCCESS;
}
ResultCode Disk_FileSystem::RenameFile(const Path& src_path, const Path& dest_path) const {
@@ -179,7 +183,7 @@ bool Disk_Storage::SetSize(const u64 size) const {
return true;
}
-Disk_Directory::Disk_Directory(const std::string& path) : directory() {
+Disk_Directory::Disk_Directory(const std::string& path) {
unsigned size = FileUtil::ScanDirectoryTree(path, directory);
directory.size = size;
directory.isDirectory = true;
diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h
index 742d7db1a..8f9e1145a 100644
--- a/src/core/file_sys/disk_filesystem.h
+++ b/src/core/file_sys/disk_filesystem.h
@@ -25,7 +25,7 @@ public:
ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const std::string& path,
Mode mode) const override;
- ResultCode DeleteFile(const Path& path) const override;
+ ResultCode DeleteFile(const std::string& path) const override;
ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override;
ResultCode DeleteDirectory(const Path& path) const override;
ResultCode DeleteDirectoryRecursively(const Path& path) const override;
@@ -43,7 +43,7 @@ protected:
class Disk_Storage : public StorageBackend {
public:
- Disk_Storage(std::shared_ptr<FileUtil::IOFile> file) : file(std::move(file)) {}
+ explicit Disk_Storage(std::shared_ptr<FileUtil::IOFile> file) : file(std::move(file)) {}
ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override;
ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
@@ -60,7 +60,7 @@ private:
class Disk_Directory : public DirectoryBackend {
public:
- Disk_Directory(const std::string& path);
+ explicit Disk_Directory(const std::string& path);
~Disk_Directory() override {
Close();
@@ -74,7 +74,6 @@ public:
}
protected:
- u32 total_entries_in_directory;
FileUtil::FSTEntry directory;
// We need to remember the last entry we returned, so a subsequent call to Read will continue
diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h
index 399427ca2..beefcfdb2 100644
--- a/src/core/file_sys/filesystem.h
+++ b/src/core/file_sys/filesystem.h
@@ -97,7 +97,7 @@ public:
* @param path Path relative to the archive
* @return Result of the operation
*/
- virtual ResultCode DeleteFile(const Path& path) const = 0;
+ virtual ResultCode DeleteFile(const std::string& path) const = 0;
/**
* Create a directory specified by its path
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
new file mode 100644
index 000000000..4a58a9291
--- /dev/null
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -0,0 +1,125 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cinttypes>
+#include <utility>
+#include "common/file_util.h"
+#include "common/logging/log.h"
+#include "core/file_sys/partition_filesystem.h"
+#include "core/loader/loader.h"
+
+namespace FileSys {
+
+Loader::ResultStatus PartitionFilesystem::Load(const std::string& file_path, size_t offset) {
+ FileUtil::IOFile file(file_path, "rb");
+ if (!file.IsOpen())
+ return Loader::ResultStatus::Error;
+
+ // At least be as large as the header
+ if (file.GetSize() < sizeof(Header))
+ return Loader::ResultStatus::Error;
+
+ // For cartridges, HFSs can get very large, so we need to calculate the size up to
+ // the actual content itself instead of just blindly reading in the entire file.
+ Header pfs_header;
+ if (!file.ReadBytes(&pfs_header, sizeof(Header)))
+ return Loader::ResultStatus::Error;
+
+ bool is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0);
+ size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry);
+ size_t metadata_size =
+ sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size;
+
+ // Actually read in now...
+ file.Seek(offset, SEEK_SET);
+ std::vector<u8> file_data(metadata_size);
+
+ if (!file.ReadBytes(file_data.data(), metadata_size))
+ return Loader::ResultStatus::Error;
+
+ Loader::ResultStatus result = Load(file_data);
+ if (result != Loader::ResultStatus::Success)
+ LOG_ERROR(Service_FS, "Failed to load PFS from file %s!", file_path.c_str());
+
+ return result;
+}
+
+Loader::ResultStatus PartitionFilesystem::Load(const std::vector<u8>& file_data, size_t offset) {
+ size_t total_size = file_data.size() - offset;
+ if (total_size < sizeof(Header))
+ return Loader::ResultStatus::Error;
+
+ memcpy(&pfs_header, &file_data[offset], sizeof(Header));
+ is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0);
+
+ size_t entries_offset = offset + sizeof(Header);
+ size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry);
+ size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size);
+ for (u16 i = 0; i < pfs_header.num_entries; i++) {
+ FileEntry entry;
+
+ memcpy(&entry.fs_entry, &file_data[entries_offset + (i * entry_size)], sizeof(FSEntry));
+ entry.name = std::string(reinterpret_cast<const char*>(
+ &file_data[strtab_offset + entry.fs_entry.strtab_offset]));
+ pfs_entries.push_back(std::move(entry));
+ }
+
+ content_offset = strtab_offset + pfs_header.strtab_size;
+
+ return Loader::ResultStatus::Success;
+}
+
+u32 PartitionFilesystem::GetNumEntries() const {
+ return pfs_header.num_entries;
+}
+
+u64 PartitionFilesystem::GetEntryOffset(int index) const {
+ if (index > GetNumEntries())
+ return 0;
+
+ return content_offset + pfs_entries[index].fs_entry.offset;
+}
+
+u64 PartitionFilesystem::GetEntrySize(int index) const {
+ if (index > GetNumEntries())
+ return 0;
+
+ return pfs_entries[index].fs_entry.size;
+}
+
+std::string PartitionFilesystem::GetEntryName(int index) const {
+ if (index > GetNumEntries())
+ return "";
+
+ return pfs_entries[index].name;
+}
+
+u64 PartitionFilesystem::GetFileOffset(const std::string& name) const {
+ for (u32 i = 0; i < pfs_header.num_entries; i++) {
+ if (pfs_entries[i].name == name)
+ return content_offset + pfs_entries[i].fs_entry.offset;
+ }
+
+ return 0;
+}
+
+u64 PartitionFilesystem::GetFileSize(const std::string& name) const {
+ for (u32 i = 0; i < pfs_header.num_entries; i++) {
+ if (pfs_entries[i].name == name)
+ return pfs_entries[i].fs_entry.size;
+ }
+
+ return 0;
+}
+
+void PartitionFilesystem::Print() const {
+ NGLOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic.data());
+ NGLOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries);
+ for (u32 i = 0; i < pfs_header.num_entries; i++) {
+ NGLOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i,
+ pfs_entries[i].name.c_str(), pfs_entries[i].fs_entry.size,
+ GetFileOffset(pfs_entries[i].name));
+ }
+}
+} // namespace FileSys
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h
new file mode 100644
index 000000000..573c90057
--- /dev/null
+++ b/src/core/file_sys/partition_filesystem.h
@@ -0,0 +1,87 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <string>
+#include <vector>
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/swap.h"
+
+namespace Loader {
+enum class ResultStatus;
+}
+
+namespace FileSys {
+
+/**
+ * Helper which implements an interface to parse PFS/HFS filesystems.
+ * Data can either be loaded from a file path or data with an offset into it.
+ */
+class PartitionFilesystem {
+public:
+ Loader::ResultStatus Load(const std::string& file_path, size_t offset = 0);
+ Loader::ResultStatus Load(const std::vector<u8>& file_data, size_t offset = 0);
+
+ u32 GetNumEntries() const;
+ u64 GetEntryOffset(int index) const;
+ u64 GetEntrySize(int index) const;
+ std::string GetEntryName(int index) const;
+ u64 GetFileOffset(const std::string& name) const;
+ u64 GetFileSize(const std::string& name) const;
+
+ void Print() const;
+
+private:
+ struct Header {
+ std::array<char, 4> magic;
+ u32_le num_entries;
+ u32_le strtab_size;
+ INSERT_PADDING_BYTES(0x4);
+ };
+
+ static_assert(sizeof(Header) == 0x10, "PFS/HFS header structure size is wrong");
+
+#pragma pack(push, 1)
+ struct FSEntry {
+ u64_le offset;
+ u64_le size;
+ u32_le strtab_offset;
+ };
+
+ static_assert(sizeof(FSEntry) == 0x14, "FS entry structure size is wrong");
+
+ struct PFSEntry {
+ FSEntry fs_entry;
+ INSERT_PADDING_BYTES(0x4);
+ };
+
+ static_assert(sizeof(PFSEntry) == 0x18, "PFS entry structure size is wrong");
+
+ struct HFSEntry {
+ FSEntry fs_entry;
+ u32_le hash_region_size;
+ INSERT_PADDING_BYTES(0x8);
+ std::array<char, 0x20> hash;
+ };
+
+ static_assert(sizeof(HFSEntry) == 0x40, "HFS entry structure size is wrong");
+
+#pragma pack(pop)
+
+ struct FileEntry {
+ FSEntry fs_entry;
+ std::string name;
+ };
+
+ Header pfs_header;
+ bool is_hfs;
+ size_t content_offset;
+
+ std::vector<FileEntry> pfs_entries;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp
index 0c6cc3157..3d77e2d5f 100644
--- a/src/core/file_sys/romfs_filesystem.cpp
+++ b/src/core/file_sys/romfs_filesystem.cpp
@@ -20,7 +20,7 @@ ResultVal<std::unique_ptr<StorageBackend>> RomFS_FileSystem::OpenFile(const std:
std::make_unique<RomFS_Storage>(romfs_file, data_offset, data_size));
}
-ResultCode RomFS_FileSystem::DeleteFile(const Path& path) const {
+ResultCode RomFS_FileSystem::DeleteFile(const std::string& path) const {
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive (%s).",
GetName().c_str());
// TODO(bunnei): Use correct error code
diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h
index 3f94c04d0..1b5cac409 100644
--- a/src/core/file_sys/romfs_filesystem.h
+++ b/src/core/file_sys/romfs_filesystem.h
@@ -31,7 +31,7 @@ public:
ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const std::string& path,
Mode mode) const override;
- ResultCode DeleteFile(const Path& path) const override;
+ ResultCode DeleteFile(const std::string& path) const override;
ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override;
ResultCode DeleteDirectory(const Path& path) const override;
ResultCode DeleteDirectoryRecursively(const Path& path) const override;
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index 0149a3ed6..88ca8ad7e 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -34,57 +34,57 @@ SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory cat
}
}
-s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const {
+s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
switch (resource) {
- case COMMIT:
+ case ResourceType::Commit:
return current_commit;
- case THREAD:
+ case ResourceType::Thread:
return current_threads;
- case EVENT:
+ case ResourceType::Event:
return current_events;
- case MUTEX:
+ case ResourceType::Mutex:
return current_mutexes;
- case SEMAPHORE:
+ case ResourceType::Semaphore:
return current_semaphores;
- case TIMER:
+ case ResourceType::Timer:
return current_timers;
- case SHARED_MEMORY:
+ case ResourceType::SharedMemory:
return current_shared_mems;
- case ADDRESS_ARBITER:
+ case ResourceType::AddressArbiter:
return current_address_arbiters;
- case CPU_TIME:
+ case ResourceType::CPUTime:
return current_cpu_time;
default:
- LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
+ LOG_ERROR(Kernel, "Unknown resource type=%08X", static_cast<u32>(resource));
UNIMPLEMENTED();
return 0;
}
}
-u32 ResourceLimit::GetMaxResourceValue(u32 resource) const {
+u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
switch (resource) {
- case PRIORITY:
+ case ResourceType::Priority:
return max_priority;
- case COMMIT:
+ case ResourceType::Commit:
return max_commit;
- case THREAD:
+ case ResourceType::Thread:
return max_threads;
- case EVENT:
+ case ResourceType::Event:
return max_events;
- case MUTEX:
+ case ResourceType::Mutex:
return max_mutexes;
- case SEMAPHORE:
+ case ResourceType::Semaphore:
return max_semaphores;
- case TIMER:
+ case ResourceType::Timer:
return max_timers;
- case SHARED_MEMORY:
+ case ResourceType::SharedMemory:
return max_shared_mems;
- case ADDRESS_ARBITER:
+ case ResourceType::AddressArbiter:
return max_address_arbiters;
- case CPU_TIME:
+ case ResourceType::CPUTime:
return max_cpu_time;
default:
- LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
+ LOG_ERROR(Kernel, "Unknown resource type=%08X", static_cast<u32>(resource));
UNIMPLEMENTED();
return 0;
}
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 1a0ca11f1..cc689a27a 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -16,17 +16,17 @@ enum class ResourceLimitCategory : u8 {
OTHER = 3
};
-enum ResourceTypes {
- PRIORITY = 0,
- COMMIT = 1,
- THREAD = 2,
- EVENT = 3,
- MUTEX = 4,
- SEMAPHORE = 5,
- TIMER = 6,
- SHARED_MEMORY = 7,
- ADDRESS_ARBITER = 8,
- CPU_TIME = 9,
+enum class ResourceType {
+ Priority = 0,
+ Commit = 1,
+ Thread = 2,
+ Event = 3,
+ Mutex = 4,
+ Semaphore = 5,
+ Timer = 6,
+ SharedMemory = 7,
+ AddressArbiter = 8,
+ CPUTime = 9,
};
class ResourceLimit final : public Object {
@@ -60,14 +60,14 @@ public:
* @param resource Requested resource type
* @returns The current value of the resource type
*/
- s32 GetCurrentResourceValue(u32 resource) const;
+ s32 GetCurrentResourceValue(ResourceType resource) const;
/**
* Gets the max value for the specified resource.
* @param resource Requested resource type
* @returns The max value of the resource type
*/
- u32 GetMaxResourceValue(u32 resource) const;
+ u32 GetMaxResourceValue(ResourceType resource) const;
/// Name of resource limit object.
std::string name;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 36ea23cd9..633740992 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -4,6 +4,7 @@
#include <algorithm>
#include <cinttypes>
+#include <iterator>
#include "common/logging/log.h"
#include "common/microprofile.h"
@@ -406,7 +407,7 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
// Note: The kernel uses the current process's resource limit instead of
// the one from the thread owner's resource limit.
SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
- if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) {
+ if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) {
return ERR_NOT_AUTHORIZED;
}
@@ -540,7 +541,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
}
SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
- if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) {
+ if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) {
return ERR_NOT_AUTHORIZED;
}
@@ -861,14 +862,14 @@ static const FunctionDef SVC_Table[] = {
{0x2B, nullptr, "FlushDataCache"},
{0x2C, nullptr, "MapPhysicalMemory"},
{0x2D, nullptr, "UnmapPhysicalMemory"},
- {0x2E, nullptr, "Unknown"},
+ {0x2E, nullptr, "GetNextThreadInfo"},
{0x2F, nullptr, "GetLastThreadInfo"},
{0x30, nullptr, "GetResourceLimitLimitValue"},
{0x31, nullptr, "GetResourceLimitCurrentValue"},
{0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
{0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
- {0x34, nullptr, "Unknown"},
- {0x35, nullptr, "Unknown"},
+ {0x34, nullptr, "WaitForAddress"},
+ {0x35, nullptr, "SignalToAddress"},
{0x36, nullptr, "Unknown"},
{0x37, nullptr, "Unknown"},
{0x38, nullptr, "Unknown"},
@@ -876,7 +877,7 @@ static const FunctionDef SVC_Table[] = {
{0x3A, nullptr, "Unknown"},
{0x3B, nullptr, "Unknown"},
{0x3C, nullptr, "DumpInfo"},
- {0x3D, nullptr, "Unknown"},
+ {0x3D, nullptr, "DumpInfoNew"},
{0x3E, nullptr, "Unknown"},
{0x3F, nullptr, "Unknown"},
{0x40, nullptr, "CreateSession"},
@@ -887,9 +888,9 @@ static const FunctionDef SVC_Table[] = {
{0x45, nullptr, "CreateEvent"},
{0x46, nullptr, "Unknown"},
{0x47, nullptr, "Unknown"},
- {0x48, nullptr, "Unknown"},
- {0x49, nullptr, "Unknown"},
- {0x4A, nullptr, "Unknown"},
+ {0x48, nullptr, "AllocateUnsafeMemory"},
+ {0x49, nullptr, "FreeUnsafeMemory"},
+ {0x4A, nullptr, "SetUnsafeAllocationLimit"},
{0x4B, nullptr, "CreateJitMemory"},
{0x4C, nullptr, "MapJitMemory"},
{0x4D, nullptr, "SleepSystem"},
@@ -926,7 +927,7 @@ static const FunctionDef SVC_Table[] = {
{0x6C, nullptr, "SetHardwareBreakPoint"},
{0x6D, nullptr, "GetDebugThreadParam"},
{0x6E, nullptr, "Unknown"},
- {0x6F, nullptr, "Unknown"},
+ {0x6F, nullptr, "GetMemoryInfo"},
{0x70, nullptr, "CreatePort"},
{0x71, nullptr, "ManageNamedPort"},
{0x72, nullptr, "ConnectToPort"},
@@ -946,7 +947,7 @@ static const FunctionDef SVC_Table[] = {
};
static const FunctionDef* GetSVCInfo(u32 func_num) {
- if (func_num >= ARRAY_SIZE(SVC_Table)) {
+ if (func_num >= std::size(SVC_Table)) {
LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num);
return nullptr;
}
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 1c2f873aa..acd65ee68 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -380,7 +380,7 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
u64 VMManager::GetTotalMemoryUsage() {
LOG_WARNING(Kernel, "(STUBBED) called");
- return 0xBE000000;
+ return 0xF8000000;
}
u64 VMManager::GetTotalHeapUsage() {
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index cfb6e05a5..6bafb2dce 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -10,8 +10,7 @@
#include "core/hle/service/acc/acc_u0.h"
#include "core/hle/service/acc/acc_u1.h"
-namespace Service {
-namespace Account {
+namespace Service::Account {
// TODO: RE this structure
struct UserData {
@@ -38,7 +37,10 @@ class IProfile final : public ServiceFramework<IProfile> {
public:
IProfile() : ServiceFramework("IProfile") {
static const FunctionInfo functions[] = {
+ {0, nullptr, "Get"},
{1, &IProfile::GetBase, "GetBase"},
+ {10, nullptr, "GetImageSize"},
+ {11, nullptr, "LoadImage"},
};
RegisterHandlers(functions);
}
@@ -59,6 +61,11 @@ public:
static const FunctionInfo functions[] = {
{0, &IManagerForApplication::CheckAvailability, "CheckAvailability"},
{1, &IManagerForApplication::GetAccountId, "GetAccountId"},
+ {2, nullptr, "EnsureIdTokenCacheAsync"},
+ {3, nullptr, "LoadIdTokenCache"},
+ {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"},
+ {150, nullptr, "CreateAuthorizationRequest"},
+ {160, nullptr, "StoreOpenContext"},
};
RegisterHandlers(functions);
}
@@ -140,5 +147,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<ACC_U1>(module)->InstallAsService(service_manager);
}
-} // namespace Account
-} // namespace Service
+} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h
index 2d2f57b7d..58f8d260c 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Account {
+namespace Service::Account {
class Module final {
public:
@@ -31,5 +30,4 @@ public:
/// Registers all ACC services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace Account
-} // namespace Service
+} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_aa.cpp b/src/core/hle/service/acc/acc_aa.cpp
index 76deaa07f..280b3e464 100644
--- a/src/core/hle/service/acc/acc_aa.cpp
+++ b/src/core/hle/service/acc/acc_aa.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/acc/acc_aa.h"
-namespace Service {
-namespace Account {
+namespace Service::Account {
ACC_AA::ACC_AA(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:aa") {
static const FunctionInfo functions[] = {
@@ -18,5 +17,4 @@ ACC_AA::ACC_AA(std::shared_ptr<Module> module) : Module::Interface(std::move(mod
RegisterHandlers(functions);
}
-} // namespace Account
-} // namespace Service
+} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_aa.h b/src/core/hle/service/acc/acc_aa.h
index 5069c6890..796f7ef85 100644
--- a/src/core/hle/service/acc/acc_aa.h
+++ b/src/core/hle/service/acc/acc_aa.h
@@ -6,13 +6,11 @@
#include "core/hle/service/acc/acc.h"
-namespace Service {
-namespace Account {
+namespace Service::Account {
class ACC_AA final : public Module::Interface {
public:
explicit ACC_AA(std::shared_ptr<Module> module);
};
-} // namespace Account
-} // namespace Service
+} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index 538f9d9b1..9ffb40b22 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/acc/acc_su.h"
-namespace Service {
-namespace Account {
+namespace Service::Account {
ACC_SU::ACC_SU(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:su") {
static const FunctionInfo functions[] = {
@@ -51,5 +50,4 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module) : Module::Interface(std::move(mod
RegisterHandlers(functions);
}
-} // namespace Account
-} // namespace Service
+} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index 7b9c667ef..44e21ac09 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/acc/acc_u0.h"
-namespace Service {
-namespace Account {
+namespace Service::Account {
ACC_U0::ACC_U0(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u0") {
static const FunctionInfo functions[] = {
@@ -31,5 +30,4 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module) : Module::Interface(std::move(mod
RegisterHandlers(functions);
}
-} // namespace Account
-} // namespace Service
+} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_u0.h b/src/core/hle/service/acc/acc_u0.h
index d4f36e172..6ded596b3 100644
--- a/src/core/hle/service/acc/acc_u0.h
+++ b/src/core/hle/service/acc/acc_u0.h
@@ -6,13 +6,11 @@
#include "core/hle/service/acc/acc.h"
-namespace Service {
-namespace Account {
+namespace Service::Account {
class ACC_U0 final : public Module::Interface {
public:
explicit ACC_U0(std::shared_ptr<Module> module);
};
-} // namespace Account
-} // namespace Service
+} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index dea353554..d101d4e0d 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/acc/acc_u1.h"
-namespace Service {
-namespace Account {
+namespace Service::Account {
ACC_U1::ACC_U1(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u1") {
static const FunctionInfo functions[] = {
@@ -38,5 +37,4 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module) : Module::Interface(std::move(mod
RegisterHandlers(functions);
}
-} // namespace Account
-} // namespace Service
+} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_u1.h b/src/core/hle/service/acc/acc_u1.h
index 432d5b3e9..5e3e7659b 100644
--- a/src/core/hle/service/acc/acc_u1.h
+++ b/src/core/hle/service/acc/acc_u1.h
@@ -6,13 +6,11 @@
#include "core/hle/service/acc/acc.h"
-namespace Service {
-namespace Account {
+namespace Service::Account {
class ACC_U1 final : public Module::Interface {
public:
explicit ACC_U1(std::shared_ptr<Module> module);
};
-} // namespace Account
-} // namespace Service
+} // namespace Service::Account
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index bfc431e88..f41a59afe 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -14,8 +14,7 @@
#include "core/hle/service/nvflinger/nvflinger.h"
#include "core/settings.h"
-namespace Service {
-namespace AM {
+namespace Service::AM {
IWindowController::IWindowController() : ServiceFramework("IWindowController") {
static const FunctionInfo functions[] = {
@@ -571,5 +570,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager,
std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager);
}
-} // namespace AM
-} // namespace Service
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index 154d346d5..4f0698a8a 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -8,8 +8,7 @@
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/nvflinger/nvflinger.h"
-namespace Service {
-namespace AM {
+namespace Service::AM {
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
@@ -109,5 +108,4 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
RegisterHandlers(functions);
}
-} // namespace AM
-} // namespace Service
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index 334c38392..674b4d753 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -8,8 +8,7 @@
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/nvflinger/nvflinger.h"
-namespace Service {
-namespace AM {
+namespace Service::AM {
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
@@ -104,5 +103,4 @@ AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
RegisterHandlers(functions);
}
-} // namespace AM
-} // namespace Service
+} // namespace Service::AM
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index f64001df3..6e7438580 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -6,8 +6,7 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/aoc/aoc_u.h"
-namespace Service {
-namespace AOC {
+namespace Service::AOC {
AOC_U::AOC_U() : ServiceFramework("aoc:u") {
static const FunctionInfo functions[] = {
@@ -42,5 +41,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<AOC_U>()->InstallAsService(service_manager);
}
-} // namespace AOC
-} // namespace Service
+} // namespace Service::AOC
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index 6e0ba15a5..17d48ef30 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace AOC {
+namespace Service::AOC {
class AOC_U final : public ServiceFramework<AOC_U> {
public:
@@ -22,5 +21,4 @@ private:
/// Registers all AOC services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace AOC
-} // namespace Service
+} // namespace Service::AOC
diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp
index c4b09b435..7a185c6c8 100644
--- a/src/core/hle/service/apm/apm.cpp
+++ b/src/core/hle/service/apm/apm.cpp
@@ -7,8 +7,7 @@
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/apm/interface.h"
-namespace Service {
-namespace APM {
+namespace Service::APM {
void InstallInterfaces(SM::ServiceManager& service_manager) {
auto module_ = std::make_shared<Module>();
@@ -16,5 +15,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager);
}
-} // namespace APM
-} // namespace Service
+} // namespace Service::APM
diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h
index 070ab21f8..90a80d51b 100644
--- a/src/core/hle/service/apm/apm.h
+++ b/src/core/hle/service/apm/apm.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace APM {
+namespace Service::APM {
enum class PerformanceMode : u8 {
Handheld = 0,
@@ -23,5 +22,4 @@ public:
/// Registers all AM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace APM
-} // namespace Service
+} // namespace Service::APM
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index 0179351ba..4e11f3f14 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -7,8 +7,7 @@
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/apm/interface.h"
-namespace Service {
-namespace APM {
+namespace Service::APM {
class ISession final : public ServiceFramework<ISession> {
public:
@@ -62,5 +61,4 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<ISession>();
}
-} // namespace APM
-} // namespace Service
+} // namespace Service::APM
diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h
index 7d53721de..b99dbb412 100644
--- a/src/core/hle/service/apm/interface.h
+++ b/src/core/hle/service/apm/interface.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace APM {
+namespace Service::APM {
class APM final : public ServiceFramework<APM> {
public:
@@ -23,5 +22,4 @@ private:
/// Registers all AM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace APM
-} // namespace Service
+} // namespace Service::APM
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index 3c495b3a0..dca2bfb92 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -7,8 +7,7 @@
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/audio/audin_u.h"
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
class IAudioIn final : public ServiceFramework<IAudioIn> {
public:
@@ -44,5 +43,4 @@ AudInU::AudInU() : ServiceFramework("audin:u") {
RegisterHandlers(functions);
}
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h
index 2b8576756..2e65efb5b 100644
--- a/src/core/hle/service/audio/audin_u.h
+++ b/src/core/hle/service/audio/audin_u.h
@@ -10,8 +10,7 @@ namespace Kernel {
class HLERequestContext;
}
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
class AudInU final : public ServiceFramework<AudInU> {
public:
@@ -19,5 +18,4 @@ public:
~AudInU() = default;
};
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 3f7fb44eb..92f910b5f 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -9,8 +9,7 @@
#include "core/hle/service/audio/audren_u.h"
#include "core/hle/service/audio/codecctl.h"
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<AudOutU>()->InstallAsService(service_manager);
@@ -20,5 +19,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<CodecCtl>()->InstallAsService(service_manager);
}
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h
index cbd56b2a8..95e5691f7 100644
--- a/src/core/hle/service/audio/audio.h
+++ b/src/core/hle/service/audio/audio.h
@@ -6,11 +6,9 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
/// Registers all Audio services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index db6e6647c..2d7f8cb04 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -10,8 +10,7 @@
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/audio/audout_u.h"
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
/// Switch sample rate frequency
constexpr u32 sample_rate{48000};
@@ -204,5 +203,4 @@ AudOutU::AudOutU() : ServiceFramework("audout:u") {
RegisterHandlers(functions);
}
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index 7fbce2225..1f9bb9bcf 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -10,8 +10,7 @@ namespace Kernel {
class HLERequestContext;
}
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
class IAudioOut;
@@ -37,5 +36,4 @@ private:
};
};
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp
index 953104f19..b2be10919 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/audrec_u.cpp
@@ -7,8 +7,7 @@
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/audio/audrec_u.h"
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
class IFinalOutputRecorder final : public ServiceFramework<IFinalOutputRecorder> {
public:
@@ -36,5 +35,4 @@ AudRecU::AudRecU() : ServiceFramework("audrec:u") {
RegisterHandlers(functions);
}
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/audrec_u.h
index c31e412c1..46daa33a4 100644
--- a/src/core/hle/service/audio/audrec_u.h
+++ b/src/core/hle/service/audio/audrec_u.h
@@ -10,8 +10,7 @@ namespace Kernel {
class HLERequestContext;
}
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
class AudRecU final : public ServiceFramework<AudRecU> {
public:
@@ -19,5 +18,4 @@ public:
~AudRecU() = default;
};
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 0e78c57e9..d9245cb19 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -9,8 +9,7 @@
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/audio/audren_u.h"
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
/// TODO(bunnei): Find a proper value for the audio_ticks
constexpr u64 audio_ticks{static_cast<u64>(BASE_CLOCK_RATE / 200)};
@@ -272,5 +271,4 @@ void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
}
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index f59d1627d..71b632e80 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -10,8 +10,7 @@ namespace Kernel {
class HLERequestContext;
}
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
class AudRenU final : public ServiceFramework<AudRenU> {
public:
@@ -24,5 +23,4 @@ private:
void GetAudioDevice(Kernel::HLERequestContext& ctx);
};
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp
index 1c86d8d17..ba0f1d228 100644
--- a/src/core/hle/service/audio/codecctl.cpp
+++ b/src/core/hle/service/audio/codecctl.cpp
@@ -7,8 +7,7 @@
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/audio/codecctl.h"
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
CodecCtl::CodecCtl() : ServiceFramework("codecctl") {
static const FunctionInfo functions[] = {
@@ -29,5 +28,4 @@ CodecCtl::CodecCtl() : ServiceFramework("codecctl") {
RegisterHandlers(functions);
}
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h
index 1121ab0b1..d9ac29b67 100644
--- a/src/core/hle/service/audio/codecctl.h
+++ b/src/core/hle/service/audio/codecctl.h
@@ -10,8 +10,7 @@ namespace Kernel {
class HLERequestContext;
}
-namespace Service {
-namespace Audio {
+namespace Service::Audio {
class CodecCtl final : public ServiceFramework<CodecCtl> {
public:
@@ -19,5 +18,4 @@ public:
~CodecCtl() = default;
};
-} // namespace Audio
-} // namespace Service
+} // namespace Service::Audio
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index 1a18e0051..41d58f999 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -8,8 +8,7 @@
#include "core/hle/service/fatal/fatal_p.h"
#include "core/hle/service/fatal/fatal_u.h"
-namespace Service {
-namespace Fatal {
+namespace Service::Fatal {
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {}
@@ -34,5 +33,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<Fatal_U>(module)->InstallAsService(service_manager);
}
-} // namespace Fatal
-} // namespace Service
+} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h
index 85272b4be..2d8d08320 100644
--- a/src/core/hle/service/fatal/fatal.h
+++ b/src/core/hle/service/fatal/fatal.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Fatal {
+namespace Service::Fatal {
class Module final {
public:
@@ -25,5 +24,4 @@ public:
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace Fatal
-} // namespace Service
+} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp
index ba194e340..a5254ac2f 100644
--- a/src/core/hle/service/fatal/fatal_p.cpp
+++ b/src/core/hle/service/fatal/fatal_p.cpp
@@ -4,11 +4,9 @@
#include "core/hle/service/fatal/fatal_p.h"
-namespace Service {
-namespace Fatal {
+namespace Service::Fatal {
Fatal_P::Fatal_P(std::shared_ptr<Module> module)
: Module::Interface(std::move(module), "fatal:p") {}
-} // namespace Fatal
-} // namespace Service
+} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal_p.h b/src/core/hle/service/fatal/fatal_p.h
index d77b24bc4..bfd8c8b74 100644
--- a/src/core/hle/service/fatal/fatal_p.h
+++ b/src/core/hle/service/fatal/fatal_p.h
@@ -6,13 +6,11 @@
#include "core/hle/service/fatal/fatal.h"
-namespace Service {
-namespace Fatal {
+namespace Service::Fatal {
class Fatal_P final : public Module::Interface {
public:
explicit Fatal_P(std::shared_ptr<Module> module);
};
-} // namespace Fatal
-} // namespace Service
+} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp
index 065cc868d..26aa9f3b7 100644
--- a/src/core/hle/service/fatal/fatal_u.cpp
+++ b/src/core/hle/service/fatal/fatal_u.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/fatal/fatal_u.h"
-namespace Service {
-namespace Fatal {
+namespace Service::Fatal {
Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:u") {
static const FunctionInfo functions[] = {
@@ -15,5 +14,4 @@ Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(m
RegisterHandlers(functions);
}
-} // namespace Fatal
-} // namespace Service
+} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal_u.h b/src/core/hle/service/fatal/fatal_u.h
index 22374755e..9b1a9e97a 100644
--- a/src/core/hle/service/fatal/fatal_u.h
+++ b/src/core/hle/service/fatal/fatal_u.h
@@ -6,13 +6,11 @@
#include "core/hle/service/fatal/fatal.h"
-namespace Service {
-namespace Fatal {
+namespace Service::Fatal {
class Fatal_U final : public Module::Interface {
public:
explicit Fatal_U(std::shared_ptr<Module> module);
};
-} // namespace Fatal
-} // namespace Service
+} // namespace Service::Fatal
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 945832e98..9e504992f 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -10,8 +10,7 @@
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_srv.h"
-namespace Service {
-namespace FileSystem {
+namespace Service::FileSystem {
/**
* Map of registered file systems, identified by type. Once an file system is registered here, it
@@ -75,5 +74,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
}
-} // namespace FileSystem
-} // namespace Service
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 48c45b1b4..2f476c869 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -14,8 +14,7 @@
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_srv.h"
-namespace Service {
-namespace FileSystem {
+namespace Service::FileSystem {
class IStorage final : public ServiceFramework<IStorage> {
public:
@@ -73,7 +72,7 @@ public:
: ServiceFramework("IFile"), backend(std::move(backend)) {
static const FunctionInfo functions[] = {
{0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"},
- {2, nullptr, "Flush"}, {3, &IFile::SetSize, "SetSize"},
+ {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"},
{4, &IFile::GetSize, "GetSize"}, {5, nullptr, "OperateRange"},
};
RegisterHandlers(functions);
@@ -152,6 +151,14 @@ private:
rb.Push(RESULT_SUCCESS);
}
+ void Flush(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+ backend->Flush();
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
void SetSize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 size = rp.Pop<u64>();
@@ -228,7 +235,7 @@ public:
: ServiceFramework("IFileSystem"), backend(std::move(backend)) {
static const FunctionInfo functions[] = {
{0, &IFileSystem::CreateFile, "CreateFile"},
- {1, nullptr, "DeleteFile"},
+ {1, &IFileSystem::DeleteFile, "DeleteFile"},
{2, &IFileSystem::CreateDirectory, "CreateDirectory"},
{3, nullptr, "DeleteDirectory"},
{4, nullptr, "DeleteDirectoryRecursively"},
@@ -265,6 +272,20 @@ public:
rb.Push(backend->CreateFile(name, size));
}
+ void DeleteFile(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ auto file_buffer = ctx.ReadBuffer();
+ auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
+
+ std::string name(file_buffer.begin(), end);
+
+ LOG_DEBUG(Service_FS, "called file %s", name.c_str());
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(backend->DeleteFile(name));
+ }
+
void CreateDirectory(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
@@ -551,5 +572,4 @@ void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
OpenDataStorageByCurrentProcess(ctx);
}
-} // namespace FileSystem
-} // namespace Service
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 6dc5874c0..acb78fac1 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -11,8 +11,7 @@ namespace FileSys {
class FileSystemBackend;
}
-namespace Service {
-namespace FileSystem {
+namespace Service::FileSystem {
class FSP_SRV final : public ServiceFramework<FSP_SRV> {
public:
@@ -33,5 +32,4 @@ private:
std::unique_ptr<FileSys::FileSystemBackend> romfs;
};
-} // namespace FileSystem
-} // namespace Service
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index 051448b2a..c98a46e05 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -8,8 +8,7 @@
#include "core/hle/service/friend/friend_a.h"
#include "core/hle/service/friend/friend_u.h"
-namespace Service {
-namespace Friend {
+namespace Service::Friend {
void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
@@ -26,5 +25,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<Friend_U>(module)->InstallAsService(service_manager);
}
-} // namespace Friend
-} // namespace Service
+} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h
index 2b21b4e15..4b72115c0 100644
--- a/src/core/hle/service/friend/friend.h
+++ b/src/core/hle/service/friend/friend.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Friend {
+namespace Service::Friend {
class Module final {
public:
@@ -25,5 +24,4 @@ public:
/// Registers all Friend services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace Friend
-} // namespace Service
+} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/friend_a.cpp b/src/core/hle/service/friend/friend_a.cpp
index d64fe846a..a2cc81926 100644
--- a/src/core/hle/service/friend/friend_a.cpp
+++ b/src/core/hle/service/friend/friend_a.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/friend/friend_a.h"
-namespace Service {
-namespace Friend {
+namespace Service::Friend {
Friend_A::Friend_A(std::shared_ptr<Module> module)
: Module::Interface(std::move(module), "friend:a") {
@@ -16,5 +15,4 @@ Friend_A::Friend_A(std::shared_ptr<Module> module)
RegisterHandlers(functions);
}
-} // namespace Friend
-} // namespace Service
+} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/friend_a.h b/src/core/hle/service/friend/friend_a.h
index 68fa58297..81257583b 100644
--- a/src/core/hle/service/friend/friend_a.h
+++ b/src/core/hle/service/friend/friend_a.h
@@ -6,13 +6,11 @@
#include "core/hle/service/friend/friend.h"
-namespace Service {
-namespace Friend {
+namespace Service::Friend {
class Friend_A final : public Module::Interface {
public:
explicit Friend_A(std::shared_ptr<Module> module);
};
-} // namespace Friend
-} // namespace Service
+} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/friend_u.cpp b/src/core/hle/service/friend/friend_u.cpp
index 9a4b05b38..90b30883f 100644
--- a/src/core/hle/service/friend/friend_u.cpp
+++ b/src/core/hle/service/friend/friend_u.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/friend/friend_u.h"
-namespace Service {
-namespace Friend {
+namespace Service::Friend {
Friend_U::Friend_U(std::shared_ptr<Module> module)
: Module::Interface(std::move(module), "friend:u") {
@@ -16,5 +15,4 @@ Friend_U::Friend_U(std::shared_ptr<Module> module)
RegisterHandlers(functions);
}
-} // namespace Friend
-} // namespace Service
+} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/friend_u.h b/src/core/hle/service/friend/friend_u.h
index 6be49ff01..0d953d807 100644
--- a/src/core/hle/service/friend/friend_u.h
+++ b/src/core/hle/service/friend/friend_u.h
@@ -6,13 +6,11 @@
#include "core/hle/service/friend/friend.h"
-namespace Service {
-namespace Friend {
+namespace Service::Friend {
class Friend_U final : public Module::Interface {
public:
explicit Friend_U(std::shared_ptr<Module> module);
};
-} // namespace Friend
-} // namespace Service
+} // namespace Service::Friend
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index b59c52f07..aad5e688b 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -14,8 +14,7 @@
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/service.h"
-namespace Service {
-namespace HID {
+namespace Service::HID {
// Updating period for each HID device.
// TODO(shinyquagsire23): These need better values.
@@ -434,5 +433,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<Hid>()->InstallAsService(service_manager);
}
-} // namespace HID
-} // namespace Service
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 3de9adb4b..350174ccd 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -7,8 +7,7 @@
#include "core/hle/service/service.h"
#include "core/settings.h"
-namespace Service {
-namespace HID {
+namespace Service::HID {
// Begin enums and output structs
@@ -337,5 +336,4 @@ void ReloadInputDevices();
/// Registers all HID services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace HID
-} // namespace Service
+} // namespace Service::HID
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index b8e53d2c7..b87172dff 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -9,8 +9,7 @@
#include "core/hle/kernel/client_session.h"
#include "core/hle/service/lm/lm.h"
-namespace Service {
-namespace LM {
+namespace Service::LM {
class Logger final : public ServiceFramework<Logger> {
public:
@@ -189,5 +188,4 @@ LM::LM() : ServiceFramework("lm") {
RegisterHandlers(functions);
}
-} // namespace LM
-} // namespace Service
+} // namespace Service::LM
diff --git a/src/core/hle/service/lm/lm.h b/src/core/hle/service/lm/lm.h
index 371135057..63d6506fe 100644
--- a/src/core/hle/service/lm/lm.h
+++ b/src/core/hle/service/lm/lm.h
@@ -8,8 +8,7 @@
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/service.h"
-namespace Service {
-namespace LM {
+namespace Service::LM {
class LM final : public ServiceFramework<LM> {
public:
@@ -23,5 +22,4 @@ private:
/// Registers all LM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace LM
-} // namespace Service
+} // namespace Service::LM
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 49870841c..91e5f527a 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -7,8 +7,7 @@
#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nfp/nfp_user.h"
-namespace Service {
-namespace NFP {
+namespace Service::NFP {
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {}
@@ -24,5 +23,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<NFP_User>(module)->InstallAsService(service_manager);
}
-} // namespace NFP
-} // namespace Service
+} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 1163e9954..095209ad8 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace NFP {
+namespace Service::NFP {
class Module final {
public:
@@ -24,5 +23,4 @@ public:
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace NFP
-} // namespace Service
+} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp
index 14e5647c4..e94c271e7 100644
--- a/src/core/hle/service/nfp/nfp_user.cpp
+++ b/src/core/hle/service/nfp/nfp_user.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/nfp/nfp_user.h"
-namespace Service {
-namespace NFP {
+namespace Service::NFP {
NFP_User::NFP_User(std::shared_ptr<Module> module)
: Module::Interface(std::move(module), "nfp:user") {
@@ -15,5 +14,4 @@ NFP_User::NFP_User(std::shared_ptr<Module> module)
RegisterHandlers(functions);
}
-} // namespace NFP
-} // namespace Service
+} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h
index 1606444ca..700043114 100644
--- a/src/core/hle/service/nfp/nfp_user.h
+++ b/src/core/hle/service/nfp/nfp_user.h
@@ -6,13 +6,11 @@
#include "core/hle/service/nfp/nfp.h"
-namespace Service {
-namespace NFP {
+namespace Service::NFP {
class NFP_User final : public Module::Interface {
public:
explicit NFP_User(std::shared_ptr<Module> module);
};
-} // namespace NFP
-} // namespace Service
+} // namespace Service::NFP
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index b32112db3..df1e7f8fe 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -9,8 +9,7 @@
#include "core/hle/service/nifm/nifm_s.h"
#include "core/hle/service/nifm/nifm_u.h"
-namespace Service {
-namespace NIFM {
+namespace Service::NIFM {
class IScanRequest final : public ServiceFramework<IScanRequest> {
public:
@@ -208,5 +207,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<NIFM_U>(module)->InstallAsService(service_manager);
}
-} // namespace NIFM
-} // namespace Service
+} // namespace Service::NIFM
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h
index 11d263b12..4ad3f3bcf 100644
--- a/src/core/hle/service/nifm/nifm.h
+++ b/src/core/hle/service/nifm/nifm.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace NIFM {
+namespace Service::NIFM {
class Module final {
public:
@@ -25,5 +24,4 @@ public:
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace NIFM
-} // namespace Service
+} // namespace Service::NIFM
diff --git a/src/core/hle/service/nifm/nifm_a.cpp b/src/core/hle/service/nifm/nifm_a.cpp
index f75df8c04..b7f296a20 100644
--- a/src/core/hle/service/nifm/nifm_a.cpp
+++ b/src/core/hle/service/nifm/nifm_a.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/nifm/nifm_a.h"
-namespace Service {
-namespace NIFM {
+namespace Service::NIFM {
NIFM_A::NIFM_A(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "nifm:a") {
static const FunctionInfo functions[] = {
@@ -15,5 +14,4 @@ NIFM_A::NIFM_A(std::shared_ptr<Module> module) : Module::Interface(std::move(mod
RegisterHandlers(functions);
}
-} // namespace NIFM
-} // namespace Service
+} // namespace Service::NIFM
diff --git a/src/core/hle/service/nifm/nifm_a.h b/src/core/hle/service/nifm/nifm_a.h
index eaea14e29..c3ba33110 100644
--- a/src/core/hle/service/nifm/nifm_a.h
+++ b/src/core/hle/service/nifm/nifm_a.h
@@ -6,13 +6,11 @@
#include "core/hle/service/nifm/nifm.h"
-namespace Service {
-namespace NIFM {
+namespace Service::NIFM {
class NIFM_A final : public Module::Interface {
public:
explicit NIFM_A(std::shared_ptr<Module> module);
};
-} // namespace NIFM
-} // namespace Service
+} // namespace Service::NIFM
diff --git a/src/core/hle/service/nifm/nifm_s.cpp b/src/core/hle/service/nifm/nifm_s.cpp
index 9c0b300e4..96e3c0cee 100644
--- a/src/core/hle/service/nifm/nifm_s.cpp
+++ b/src/core/hle/service/nifm/nifm_s.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/nifm/nifm_s.h"
-namespace Service {
-namespace NIFM {
+namespace Service::NIFM {
NIFM_S::NIFM_S(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "nifm:s") {
static const FunctionInfo functions[] = {
@@ -15,5 +14,4 @@ NIFM_S::NIFM_S(std::shared_ptr<Module> module) : Module::Interface(std::move(mod
RegisterHandlers(functions);
}
-} // namespace NIFM
-} // namespace Service
+} // namespace Service::NIFM
diff --git a/src/core/hle/service/nifm/nifm_s.h b/src/core/hle/service/nifm/nifm_s.h
index f9e2d8039..8d1635a5d 100644
--- a/src/core/hle/service/nifm/nifm_s.h
+++ b/src/core/hle/service/nifm/nifm_s.h
@@ -6,13 +6,11 @@
#include "core/hle/service/nifm/nifm.h"
-namespace Service {
-namespace NIFM {
+namespace Service::NIFM {
class NIFM_S final : public Module::Interface {
public:
explicit NIFM_S(std::shared_ptr<Module> module);
};
-} // namespace NIFM
-} // namespace Service
+} // namespace Service::NIFM
diff --git a/src/core/hle/service/nifm/nifm_u.cpp b/src/core/hle/service/nifm/nifm_u.cpp
index 44e6f483d..8cb75b903 100644
--- a/src/core/hle/service/nifm/nifm_u.cpp
+++ b/src/core/hle/service/nifm/nifm_u.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/nifm/nifm_u.h"
-namespace Service {
-namespace NIFM {
+namespace Service::NIFM {
NIFM_U::NIFM_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "nifm:u") {
static const FunctionInfo functions[] = {
@@ -15,5 +14,4 @@ NIFM_U::NIFM_U(std::shared_ptr<Module> module) : Module::Interface(std::move(mod
RegisterHandlers(functions);
}
-} // namespace NIFM
-} // namespace Service
+} // namespace Service::NIFM
diff --git a/src/core/hle/service/nifm/nifm_u.h b/src/core/hle/service/nifm/nifm_u.h
index 912006775..def9726b1 100644
--- a/src/core/hle/service/nifm/nifm_u.h
+++ b/src/core/hle/service/nifm/nifm_u.h
@@ -6,13 +6,11 @@
#include "core/hle/service/nifm/nifm.h"
-namespace Service {
-namespace NIFM {
+namespace Service::NIFM {
class NIFM_U final : public Module::Interface {
public:
explicit NIFM_U(std::shared_ptr<Module> module);
};
-} // namespace NIFM
-} // namespace Service
+} // namespace Service::NIFM
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 45681c50f..89c703310 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -5,12 +5,10 @@
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/ns/pl_u.h"
-namespace Service {
-namespace NS {
+namespace Service::NS {
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<PL_U>()->InstallAsService(service_manager);
}
-} // namespace NS
-} // namespace Service
+} // namespace Service::NS
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
index a4b7e3ded..b81ca8f1e 100644
--- a/src/core/hle/service/ns/ns.h
+++ b/src/core/hle/service/ns/ns.h
@@ -6,11 +6,9 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace NS {
+namespace Service::NS {
/// Registers all NS services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace NS
-} // namespace Service
+} // namespace Service::NS
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index d5e0b5f14..c416ad720 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -8,8 +8,7 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/ns/pl_u.h"
-namespace Service {
-namespace NS {
+namespace Service::NS {
struct FontRegion {
u32 offset;
@@ -47,10 +46,10 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
FileUtil::CreateFullPath(filepath); // Create path if not already created
FileUtil::IOFile file(filepath, "rb");
+ shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE);
if (file.IsOpen()) {
// Read shared font data
ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE);
- shared_font = std::make_shared<std::vector<u8>>(static_cast<size_t>(file.GetSize()));
file.ReadBytes(shared_font->data(), shared_font->size());
} else {
LOG_WARNING(Service_NS, "Unable to load shared font: %s", filepath.c_str());
@@ -97,22 +96,19 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
}
void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
- if (shared_font != nullptr) {
- // TODO(bunnei): This is a less-than-ideal solution to load a RAM dump of the Switch shared
- // font data. This (likely) relies on exact address, size, and offsets from the original
- // dump. In the future, we need to replace this with a more robust solution.
-
- // Map backing memory for the font data
- Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, shared_font, 0,
- SHARED_FONT_MEM_SIZE,
- Kernel::MemoryState::Shared);
-
- // Create shared font memory object
- shared_font_mem = Kernel::SharedMemory::Create(
- Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite,
- Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
- "PL_U:shared_font_mem");
- }
+ // TODO(bunnei): This is a less-than-ideal solution to load a RAM dump of the Switch shared
+ // font data. This (likely) relies on exact address, size, and offsets from the original
+ // dump. In the future, we need to replace this with a more robust solution.
+
+ // Map backing memory for the font data
+ Core::CurrentProcess()->vm_manager.MapMemoryBlock(
+ SHARED_FONT_MEM_VADDR, shared_font, 0, SHARED_FONT_MEM_SIZE, Kernel::MemoryState::Shared);
+
+ // Create shared font memory object
+ shared_font_mem = Kernel::SharedMemory::Create(
+ Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite,
+ Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
+ "PL_U:shared_font_mem");
LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -120,5 +116,4 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(shared_font_mem);
}
-} // namespace NS
-} // namespace Service
+} // namespace Service::NS
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h
index 360482d13..b175c9c44 100644
--- a/src/core/hle/service/ns/pl_u.h
+++ b/src/core/hle/service/ns/pl_u.h
@@ -8,8 +8,7 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/service.h"
-namespace Service {
-namespace NS {
+namespace Service::NS {
class PL_U final : public ServiceFramework<PL_U> {
public:
@@ -30,5 +29,4 @@ private:
std::shared_ptr<std::vector<u8>> shared_font;
};
-} // namespace NS
-} // namespace Service
+} // namespace Service::NS
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index cdc25b059..0f02a1a18 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -9,9 +9,7 @@
#include "common/common_types.h"
#include "common/swap.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
/// Represents an abstract nvidia device node. It is to be subclassed by concrete device nodes to
/// implement the ioctl interface.
@@ -38,6 +36,4 @@ public:
virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) = 0;
};
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 87b3a2d74..61f22b1a5 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -10,9 +10,7 @@
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
UNIMPLEMENTED();
@@ -35,6 +33,4 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
VideoCore::g_renderer->SwapBuffers(framebuffer);
}
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 66f56f23d..3d3979723 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -10,9 +10,7 @@
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
class nvmap;
@@ -31,6 +29,4 @@ private:
std::shared_ptr<nvmap> nvmap_dev;
};
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // 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 9892402fa..71e844959 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -9,9 +9,7 @@
#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called, command=0x%08x, input_size=0x%zx, output_size=0x%zx",
@@ -115,6 +113,4 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o
return 0;
}
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index f8a60cce7..d86c3ebd9 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -11,9 +11,7 @@
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
class nvmap;
@@ -100,6 +98,4 @@ private:
std::shared_ptr<nvmap> nvmap_dev;
};
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // 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 45711d686..660a0f665 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -6,9 +6,7 @@
#include "common/logging/log.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called, command=0x%08x, input_size=0x%zx, output_size=0x%zx",
@@ -59,6 +57,4 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
return 0;
}
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 0ca01aa6d..76a8b33c2 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -11,9 +11,7 @@
#include "common/common_types.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
class nvhost_ctrl final : public nvdevice {
public:
@@ -55,6 +53,4 @@ private:
u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output);
};
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia::Devices
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 3b353d742..18ea12ef5 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -7,9 +7,7 @@
#include "common/logging/log.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called, command=0x%08x, input_size=0x%zx, output_size=0x%zx",
@@ -122,6 +120,4 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&
return 0;
}
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index dc0476993..31040cdbe 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -9,9 +9,7 @@
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
class nvhost_ctrl_gpu final : public nvdevice {
public:
@@ -125,6 +123,5 @@ private:
u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output);
u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output);
};
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index da44c65f3..a16e90457 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -9,9 +9,7 @@
#include "core/core.h"
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called, command=0x%08x, input_size=0x%zx, output_size=0x%zx",
@@ -142,6 +140,4 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
return 0;
}
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // 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 e7e9a0088..703c36bbb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -10,9 +10,7 @@
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
class nvmap;
constexpr u32 NVGPU_IOCTL_MAGIC('H');
@@ -139,6 +137,4 @@ private:
std::shared_ptr<nvmap> nvmap_dev;
};
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // 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 b3842eb4c..4bb1f57f6 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -9,9 +9,7 @@
#include "common/logging/log.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
VAddr nvmap::GetObjectAddress(u32 handle) const {
auto object = GetObject(handle);
@@ -144,6 +142,4 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
return 0;
}
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 4681e438b..431eb3773 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -12,9 +12,7 @@
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
-namespace Service {
-namespace Nvidia {
-namespace Devices {
+namespace Service::Nvidia::Devices {
class nvmap final : public nvdevice {
public:
@@ -111,6 +109,4 @@ private:
u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output);
};
-} // namespace Devices
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index 567c2cd7c..d0d64a840 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -9,8 +9,7 @@
#include "core/hle/service/nvdrv/interface.h"
#include "core/hle/service/nvdrv/nvdrv.h"
-namespace Service {
-namespace Nvidia {
+namespace Service::Nvidia {
void NVDRV::Open(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NVDRV, "called");
@@ -111,5 +110,4 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
query_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NVDRV::query_event");
}
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index daf2302af..959b5ba29 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -10,8 +10,7 @@
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/service.h"
-namespace Service {
-namespace Nvidia {
+namespace Service::Nvidia {
class NVDRV final : public ServiceFramework<NVDRV> {
public:
@@ -34,5 +33,4 @@ private:
Kernel::SharedPtr<Kernel::Event> query_event;
};
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index ea00240e6..170420418 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -14,8 +14,7 @@
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvdrv/nvmemp.h"
-namespace Service {
-namespace Nvidia {
+namespace Service::Nvidia {
std::weak_ptr<Module> nvdrv;
@@ -69,5 +68,4 @@ ResultCode Module::Close(u32 fd) {
return RESULT_SUCCESS;
}
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index 6a55ff96d..579940817 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -10,8 +10,7 @@
#include "common/common_types.h"
#include "core/hle/service/service.h"
-namespace Service {
-namespace Nvidia {
+namespace Service::Nvidia {
namespace Devices {
class nvdevice;
@@ -61,5 +60,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager);
extern std::weak_ptr<Module> nvdrv;
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp
index 35d6c0c13..9ca6e5512 100644
--- a/src/core/hle/service/nvdrv/nvmemp.cpp
+++ b/src/core/hle/service/nvdrv/nvmemp.cpp
@@ -8,8 +8,7 @@
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvdrv/nvmemp.h"
-namespace Service {
-namespace Nvidia {
+namespace Service::Nvidia {
NVMEMP::NVMEMP() : ServiceFramework("nvmemp") {
static const FunctionInfo functions[] = {
@@ -27,5 +26,4 @@ void NVMEMP::Cmd1(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED();
}
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h
index fb16026b0..dfdcabf4a 100644
--- a/src/core/hle/service/nvdrv/nvmemp.h
+++ b/src/core/hle/service/nvdrv/nvmemp.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Nvidia {
+namespace Service::Nvidia {
class NVMEMP final : public ServiceFramework<NVMEMP> {
public:
@@ -19,5 +18,4 @@ private:
void Cmd1(Kernel::HLERequestContext& ctx);
};
-} // namespace Nvidia
-} // namespace Service
+} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index e4ff2e267..03a4fed59 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -9,8 +9,7 @@
#include "core/core_timing.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
-namespace Service {
-namespace NVFlinger {
+namespace Service::NVFlinger {
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle");
@@ -111,5 +110,4 @@ void BufferQueue::SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_eve
buffer_wait_event = std::move(wait_event);
}
-} // namespace NVFlinger
-} // namespace Service
+} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 1de5767cb..95adc4706 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -13,8 +13,7 @@ namespace CoreTiming {
struct EventType;
}
-namespace Service {
-namespace NVFlinger {
+namespace Service::NVFlinger {
struct IGBPBuffer {
u32_le magic;
@@ -98,5 +97,4 @@ private:
Kernel::SharedPtr<Kernel::Event> buffer_wait_event;
};
-} // namespace NVFlinger
-} // namespace Service
+} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 0d30f54dc..a99ebc8e6 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -5,6 +5,7 @@
#include <algorithm>
#include "common/alignment.h"
+#include "common/microprofile.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/core_timing.h"
@@ -15,8 +16,7 @@
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
-namespace Service {
-namespace NVFlinger {
+namespace Service::NVFlinger {
constexpr size_t SCREEN_REFRESH_RATE = 60;
constexpr u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
@@ -128,6 +128,8 @@ void NVFlinger::Compose() {
// Search for a queued buffer and acquire it
auto buffer = buffer_queue->AcquireBuffer();
+ MicroProfileFlip();
+
if (buffer == boost::none) {
// There was no queued buffer to draw, render previous frame
Core::System::GetInstance().perf_stats.EndGameFrame();
@@ -162,5 +164,4 @@ Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
vsync_event = Kernel::Event::Create(Kernel::ResetType::Pulse, "Display VSync Event");
}
-} // namespace NVFlinger
-} // namespace Service
+} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 3126018ad..2c908297b 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -12,8 +12,7 @@ namespace CoreTiming {
struct EventType;
}
-namespace Service {
-namespace NVFlinger {
+namespace Service::NVFlinger {
class BufferQueue;
@@ -80,5 +79,4 @@ private:
CoreTiming::EventType* composition_event;
};
-} // namespace NVFlinger
-} // namespace Service
+} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index 692b27a71..6ee81866d 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -5,12 +5,10 @@
#include "core/hle/service/pctl/pctl.h"
#include "core/hle/service/pctl/pctl_a.h"
-namespace Service {
-namespace PCTL {
+namespace Service::PCTL {
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<PCTL_A>()->InstallAsService(service_manager);
}
-} // namespace PCTL
-} // namespace Service
+} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index 5fa67dd1b..f0a84b115 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -6,11 +6,9 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace PCTL {
+namespace Service::PCTL {
/// Registers all PCTL services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace PCTL
-} // namespace Service
+} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_a.cpp b/src/core/hle/service/pctl/pctl_a.cpp
index 4e644be64..9fb4628ad 100644
--- a/src/core/hle/service/pctl/pctl_a.cpp
+++ b/src/core/hle/service/pctl/pctl_a.cpp
@@ -6,8 +6,7 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/pctl/pctl_a.h"
-namespace Service {
-namespace PCTL {
+namespace Service::PCTL {
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
public:
@@ -125,5 +124,4 @@ PCTL_A::PCTL_A() : ServiceFramework("pctl:a") {
RegisterHandlers(functions);
}
-} // namespace PCTL
-} // namespace Service
+} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_a.h b/src/core/hle/service/pctl/pctl_a.h
index 3aa8873a9..09ed82e1b 100644
--- a/src/core/hle/service/pctl/pctl_a.h
+++ b/src/core/hle/service/pctl/pctl_a.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace PCTL {
+namespace Service::PCTL {
class PCTL_A final : public ServiceFramework<PCTL_A> {
public:
@@ -18,5 +17,4 @@ private:
void CreateService(Kernel::HLERequestContext& ctx);
};
-} // namespace PCTL
-} // namespace Service
+} // namespace Service::PCTL
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index c5490c1ae..08ce29677 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -145,7 +145,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
return ResultCode(ErrorModule::HIPC, ErrorDescription::RemoteProcessDead);
}
case IPC::CommandType::Control: {
- SM::g_service_manager->InvokeControlRequest(context);
+ Core::System::GetInstance().ServiceManager().InvokeControlRequest(context);
break;
}
case IPC::CommandType::Request: {
@@ -170,42 +170,40 @@ void AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
}
/// Initialize ServiceManager
-void Init() {
+void Init(std::shared_ptr<SM::ServiceManager>& sm) {
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
// here and pass it into the respective InstallInterfaces functions.
auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>();
- SM::g_service_manager = std::make_shared<SM::ServiceManager>();
- SM::ServiceManager::InstallInterfaces(SM::g_service_manager);
-
- Account::InstallInterfaces(*SM::g_service_manager);
- AM::InstallInterfaces(*SM::g_service_manager, nv_flinger);
- AOC::InstallInterfaces(*SM::g_service_manager);
- APM::InstallInterfaces(*SM::g_service_manager);
- Audio::InstallInterfaces(*SM::g_service_manager);
- Fatal::InstallInterfaces(*SM::g_service_manager);
- FileSystem::InstallInterfaces(*SM::g_service_manager);
- Friend::InstallInterfaces(*SM::g_service_manager);
- HID::InstallInterfaces(*SM::g_service_manager);
- LM::InstallInterfaces(*SM::g_service_manager);
- NFP::InstallInterfaces(*SM::g_service_manager);
- NIFM::InstallInterfaces(*SM::g_service_manager);
- NS::InstallInterfaces(*SM::g_service_manager);
- Nvidia::InstallInterfaces(*SM::g_service_manager);
- PCTL::InstallInterfaces(*SM::g_service_manager);
- Sockets::InstallInterfaces(*SM::g_service_manager);
- SPL::InstallInterfaces(*SM::g_service_manager);
- SSL::InstallInterfaces(*SM::g_service_manager);
- Time::InstallInterfaces(*SM::g_service_manager);
- VI::InstallInterfaces(*SM::g_service_manager, nv_flinger);
- Set::InstallInterfaces(*SM::g_service_manager);
+ SM::ServiceManager::InstallInterfaces(sm);
+
+ Account::InstallInterfaces(*sm);
+ AM::InstallInterfaces(*sm, nv_flinger);
+ AOC::InstallInterfaces(*sm);
+ APM::InstallInterfaces(*sm);
+ Audio::InstallInterfaces(*sm);
+ Fatal::InstallInterfaces(*sm);
+ FileSystem::InstallInterfaces(*sm);
+ Friend::InstallInterfaces(*sm);
+ HID::InstallInterfaces(*sm);
+ LM::InstallInterfaces(*sm);
+ NFP::InstallInterfaces(*sm);
+ NIFM::InstallInterfaces(*sm);
+ NS::InstallInterfaces(*sm);
+ Nvidia::InstallInterfaces(*sm);
+ PCTL::InstallInterfaces(*sm);
+ Sockets::InstallInterfaces(*sm);
+ SPL::InstallInterfaces(*sm);
+ SSL::InstallInterfaces(*sm);
+ Time::InstallInterfaces(*sm);
+ VI::InstallInterfaces(*sm, nv_flinger);
+ Set::InstallInterfaces(*sm);
LOG_DEBUG(Service, "initialized OK");
}
/// Shutdown ServiceManager
void Shutdown() {
- SM::g_service_manager = nullptr;
g_kernel_named_ports.clear();
LOG_DEBUG(Service, "shutdown OK");
}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 9c2e826da..fee841d46 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -178,7 +178,7 @@ private:
};
/// Initialize ServiceManager
-void Init();
+void Init(std::shared_ptr<SM::ServiceManager>& sm);
/// Shutdown ServiceManager
void Shutdown();
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index aa7c924e7..fc3e424d0 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -9,8 +9,7 @@
#include "core/hle/kernel/client_session.h"
#include "core/hle/service/set/set.h"
-namespace Service {
-namespace Set {
+namespace Service::Set {
void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
@@ -36,9 +35,9 @@ SET::SET() : ServiceFramework("set") {
{5, nullptr, "GetAvailableLanguageCodes2"},
{6, nullptr, "GetAvailableLanguageCodeCount2"},
{7, nullptr, "GetKeyCodeMap"},
+ {8, nullptr, "GetQuestFlag"},
};
RegisterHandlers(functions);
}
-} // namespace Set
-} // namespace Service
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 7b7814ed1..6a465949f 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Set {
+namespace Service::Set {
class SET final : public ServiceFramework<SET> {
public:
@@ -18,5 +17,4 @@ private:
void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx);
};
-} // namespace Set
-} // namespace Service
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp
index 6231acd96..7066ef725 100644
--- a/src/core/hle/service/set/set_cal.cpp
+++ b/src/core/hle/service/set/set_cal.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/set/set_cal.h"
-namespace Service {
-namespace Set {
+namespace Service::Set {
SET_CAL::SET_CAL() : ServiceFramework("set:cal") {
static const FunctionInfo functions[] = {
@@ -32,9 +31,17 @@ SET_CAL::SET_CAL() : ServiceFramework("set:cal") {
{21, nullptr, "GetEticketDeviceKey"},
{22, nullptr, "GetSpeakerParameter"},
{23, nullptr, "GetLcdVendorId"},
+ {24, nullptr, "GetEciDeviceCertificate2"},
+ {25, nullptr, "GetEciDeviceKey2"},
+ {26, nullptr, "GetAmiiboKey"},
+ {27, nullptr, "GetAmiiboEcqvCertificate"},
+ {28, nullptr, "GetAmiiboEcdsaCertificate"},
+ {29, nullptr, "GetAmiiboEcqvBlsKey"},
+ {30, nullptr, "GetAmiiboEcqvBlsCertificate"},
+ {31, nullptr, "GetAmiiboEcqvBlsRootCertificate"},
+ {32, nullptr, "GetUnknownId"},
};
RegisterHandlers(functions);
}
-} // namespace Set
-} // namespace Service
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_cal.h b/src/core/hle/service/set/set_cal.h
index 9c0b851d0..bb50336aa 100644
--- a/src/core/hle/service/set/set_cal.h
+++ b/src/core/hle/service/set/set_cal.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Set {
+namespace Service::Set {
class SET_CAL final : public ServiceFramework<SET_CAL> {
public:
@@ -15,5 +14,4 @@ public:
~SET_CAL() = default;
};
-} // namespace Set
-} // namespace Service
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp
index 8320d4250..c9f938716 100644
--- a/src/core/hle/service/set/set_fd.cpp
+++ b/src/core/hle/service/set/set_fd.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/set/set_fd.h"
-namespace Service {
-namespace Set {
+namespace Service::Set {
SET_FD::SET_FD() : ServiceFramework("set:fd") {
static const FunctionInfo functions[] = {
@@ -21,5 +20,4 @@ SET_FD::SET_FD() : ServiceFramework("set:fd") {
RegisterHandlers(functions);
}
-} // namespace Set
-} // namespace Service
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_fd.h b/src/core/hle/service/set/set_fd.h
index 65b36bcb3..dbd850bc7 100644
--- a/src/core/hle/service/set/set_fd.h
+++ b/src/core/hle/service/set/set_fd.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Set {
+namespace Service::Set {
class SET_FD final : public ServiceFramework<SET_FD> {
public:
@@ -15,5 +14,4 @@ public:
~SET_FD() = default;
};
-} // namespace Set
-} // namespace Service
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 363abd10a..fa85277fe 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -7,8 +7,7 @@
#include "core/hle/kernel/client_port.h"
#include "core/hle/service/set/set_sys.h"
-namespace Service {
-namespace Set {
+namespace Service::Set {
void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) {
@@ -27,6 +26,7 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
{2, nullptr, "GetNetworkSettings"},
{3, nullptr, "GetFirmwareVersion"},
{4, nullptr, "GetFirmwareVersion2"},
+ {5, nullptr, "GetFirmwareVersionDigest"},
{7, nullptr, "GetLockScreenFlag"},
{8, nullptr, "SetLockScreenFlag"},
{9, nullptr, "GetBacklightSettings"},
@@ -159,9 +159,17 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
{138, nullptr, "GetWebInspectorFlag"},
{139, nullptr, "GetAllowedSslHosts"},
{140, nullptr, "GetHostFsMountPoint"},
+ {141, nullptr, "GetRequiresRunRepairTimeReviser"},
+ {142, nullptr, "SetRequiresRunRepairTimeReviser"},
+ {143, nullptr, "SetBlePairingSettings"},
+ {144, nullptr, "GetBlePairingSettings"},
+ {145, nullptr, "GetConsoleSixAxisSensorAngularVelocityTimeBias"},
+ {146, nullptr, "SetConsoleSixAxisSensorAngularVelocityTimeBias"},
+ {147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"},
+ {148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"},
+ {149, nullptr, "GetRebootlessSystemUpdateVersion"},
};
RegisterHandlers(functions);
}
-} // namespace Set
-} // namespace Service
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h
index 105f1a3c7..b77a97cde 100644
--- a/src/core/hle/service/set/set_sys.h
+++ b/src/core/hle/service/set/set_sys.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Set {
+namespace Service::Set {
class SET_SYS final : public ServiceFramework<SET_SYS> {
public:
@@ -18,5 +17,4 @@ private:
void GetColorSetId(Kernel::HLERequestContext& ctx);
};
-} // namespace Set
-} // namespace Service
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/settings.cpp b/src/core/hle/service/set/settings.cpp
index c6bc9e240..cf5541ca8 100644
--- a/src/core/hle/service/set/settings.cpp
+++ b/src/core/hle/service/set/settings.cpp
@@ -8,8 +8,7 @@
#include "core/hle/service/set/set_sys.h"
#include "core/hle/service/set/settings.h"
-namespace Service {
-namespace Set {
+namespace Service::Set {
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<SET>()->InstallAsService(service_manager);
@@ -18,5 +17,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<SET_SYS>()->InstallAsService(service_manager);
}
-} // namespace Set
-} // namespace Service
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/settings.h b/src/core/hle/service/set/settings.h
index 6c8d5a58c..6606ce776 100644
--- a/src/core/hle/service/set/settings.h
+++ b/src/core/hle/service/set/settings.h
@@ -6,11 +6,9 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Set {
+namespace Service::Set {
/// Registers all Settings services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace Set
-} // namespace Service
+} // namespace Service::Set
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index e12c53442..13e31620d 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -7,8 +7,7 @@
#include "core/hle/kernel/session.h"
#include "core/hle/service/sm/controller.h"
-namespace Service {
-namespace SM {
+namespace Service::SM {
void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(!ctx.Session()->IsDomain(), "session is alread a domain");
@@ -58,5 +57,4 @@ Controller::Controller() : ServiceFramework("IpcController") {
RegisterHandlers(functions);
}
-} // namespace SM
-} // namespace Service
+} // namespace Service::SM
diff --git a/src/core/hle/service/sm/controller.h b/src/core/hle/service/sm/controller.h
index 7b4bc4b75..a4de52cd2 100644
--- a/src/core/hle/service/sm/controller.h
+++ b/src/core/hle/service/sm/controller.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace SM {
+namespace Service::SM {
class Controller final : public ServiceFramework<Controller> {
public:
@@ -21,5 +20,4 @@ private:
void QueryPointerBufferSize(Kernel::HLERequestContext& ctx);
};
-} // namespace SM
-} // namespace Service
+} // namespace Service::SM
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index bc72512a0..4578fc05f 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -12,8 +12,9 @@
#include "core/hle/service/sm/controller.h"
#include "core/hle/service/sm/sm.h"
-namespace Service {
-namespace SM {
+namespace Service::SM {
+
+ServiceManager::~ServiceManager() = default;
void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
controller_interface->InvokeRequest(context);
@@ -73,7 +74,7 @@ ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToSer
return client_port->Connect();
}
-std::shared_ptr<ServiceManager> g_service_manager;
+SM::~SM() = default;
/**
* SM::Initialize service function
@@ -132,5 +133,4 @@ SM::SM(std::shared_ptr<ServiceManager> service_manager)
RegisterHandlers(functions);
}
-} // namespace SM
-} // namespace Service
+} // namespace Service::SM
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 11fa788ca..13f5c4c28 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -17,14 +17,13 @@ class ServerPort;
class SessionRequestHandler;
} // namespace Kernel
-namespace Service {
-namespace SM {
+namespace Service::SM {
/// Interface to "sm:" service
class SM final : public ServiceFramework<SM> {
public:
SM(std::shared_ptr<ServiceManager> service_manager);
- ~SM() = default;
+ ~SM() override;
private:
void Initialize(Kernel::HLERequestContext& ctx);
@@ -45,6 +44,8 @@ class ServiceManager {
public:
static void InstallInterfaces(std::shared_ptr<ServiceManager> self);
+ ~ServiceManager();
+
ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
unsigned int max_sessions);
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
@@ -60,7 +61,4 @@ private:
std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services;
};
-extern std::shared_ptr<ServiceManager> g_service_manager;
-
-} // namespace SM
-} // namespace Service
+} // namespace Service::SM
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 790ff82b3..f99809bed 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -5,8 +5,7 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/sockets/bsd.h"
-namespace Service {
-namespace Sockets {
+namespace Service::Sockets {
void BSD::RegisterClient(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
@@ -79,12 +78,36 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
{0, &BSD::RegisterClient, "RegisterClient"},
{1, &BSD::StartMonitoring, "StartMonitoring"},
{2, &BSD::Socket, "Socket"},
+ {3, nullptr, "SocketExempt"},
+ {4, nullptr, "Open"},
+ {5, nullptr, "Select"},
+ {6, nullptr, "Poll"},
+ {7, nullptr, "Sysctl"},
+ {8, nullptr, "Recv"},
+ {9, nullptr, "RecvFrom"},
+ {10, nullptr, "Send"},
{11, &BSD::SendTo, "SendTo"},
+ {12, nullptr, "Accept"},
+ {13, nullptr, "Bind"},
{14, &BSD::Connect, "Connect"},
+ {15, nullptr, "GetPeerName"},
+ {16, nullptr, "GetSockName"},
+ {17, nullptr, "GetSockOpt"},
+ {18, nullptr, "Listen"},
+ {19, nullptr, "Ioctl"},
+ {20, nullptr, "Fcntl"},
+ {21, nullptr, "SetSockOpt"},
+ {22, nullptr, "Shutdown"},
+ {23, nullptr, "ShutdownAllSockets"},
+ {24, nullptr, "Write"},
+ {25, nullptr, "Read"},
{26, &BSD::Close, "Close"},
+ {27, nullptr, "DuplicateSocket"},
+ {28, nullptr, "GetResourceStatistics"},
+ {29, nullptr, "RecvMMsg"},
+ {30, nullptr, "SendMMsg"},
};
RegisterHandlers(functions);
}
-} // namespace Sockets
-} // namespace Service
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 32d949e95..a6b1ca7d0 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -7,8 +7,7 @@
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/service.h"
-namespace Service {
-namespace Sockets {
+namespace Service::Sockets {
class BSD final : public ServiceFramework<BSD> {
public:
@@ -27,5 +26,4 @@ private:
u32 next_fd = 1;
};
-} // namespace Sockets
-} // namespace Service
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp
index e3542d325..8682dc2e0 100644
--- a/src/core/hle/service/sockets/nsd.cpp
+++ b/src/core/hle/service/sockets/nsd.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/sockets/nsd.h"
-namespace Service {
-namespace Sockets {
+namespace Service::Sockets {
NSD::NSD(const char* name) : ServiceFramework(name) {
static const FunctionInfo functions[] = {
@@ -30,5 +29,4 @@ NSD::NSD(const char* name) : ServiceFramework(name) {
RegisterHandlers(functions);
}
-} // namespace Sockets
-} // namespace Service
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/nsd.h b/src/core/hle/service/sockets/nsd.h
index a7c15a860..3b7edfc43 100644
--- a/src/core/hle/service/sockets/nsd.h
+++ b/src/core/hle/service/sockets/nsd.h
@@ -7,8 +7,7 @@
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/service.h"
-namespace Service {
-namespace Sockets {
+namespace Service::Sockets {
class NSD final : public ServiceFramework<NSD> {
public:
@@ -16,5 +15,4 @@ public:
~NSD() = default;
};
-} // namespace Sockets
-} // namespace Service
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index eb4b5fa57..d235c4cfd 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -5,8 +5,7 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/sockets/sfdnsres.h"
-namespace Service {
-namespace Sockets {
+namespace Service::Sockets {
void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
@@ -30,9 +29,9 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") {
{7, nullptr, "GetNameInfo"},
{8, nullptr, "RequestCancelHandle"},
{9, nullptr, "CancelSocketCall"},
+ {11, nullptr, "ClearDnsIpServerAddressArray"},
};
RegisterHandlers(functions);
}
-} // namespace Sockets
-} // namespace Service
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h
index c07cc1594..62c7e35bf 100644
--- a/src/core/hle/service/sockets/sfdnsres.h
+++ b/src/core/hle/service/sockets/sfdnsres.h
@@ -7,8 +7,7 @@
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/service.h"
-namespace Service {
-namespace Sockets {
+namespace Service::Sockets {
class SFDNSRES final : public ServiceFramework<SFDNSRES> {
public:
@@ -19,5 +18,4 @@ private:
void GetAddrInfo(Kernel::HLERequestContext& ctx);
};
-} // namespace Sockets
-} // namespace Service
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp
index cedc276d9..05bd10d35 100644
--- a/src/core/hle/service/sockets/sockets.cpp
+++ b/src/core/hle/service/sockets/sockets.cpp
@@ -7,8 +7,7 @@
#include "core/hle/service/sockets/sfdnsres.h"
#include "core/hle/service/sockets/sockets.h"
-namespace Service {
-namespace Sockets {
+namespace Service::Sockets {
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<BSD>("bsd:s")->InstallAsService(service_manager);
@@ -18,5 +17,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<SFDNSRES>()->InstallAsService(service_manager);
}
-} // namespace Sockets
-} // namespace Service
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index 7e89c8d2c..ca8a6a7e0 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -6,11 +6,9 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Sockets {
+namespace Service::Sockets {
/// Registers all Sockets services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace Sockets
-} // namespace Service
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/spl/csrng.cpp b/src/core/hle/service/spl/csrng.cpp
index cde05717a..b9e6b799d 100644
--- a/src/core/hle/service/spl/csrng.cpp
+++ b/src/core/hle/service/spl/csrng.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/spl/csrng.h"
-namespace Service {
-namespace SPL {
+namespace Service::SPL {
CSRNG::CSRNG(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "csrng") {
static const FunctionInfo functions[] = {
@@ -14,5 +13,4 @@ CSRNG::CSRNG(std::shared_ptr<Module> module) : Module::Interface(std::move(modul
RegisterHandlers(functions);
}
-} // namespace SPL
-} // namespace Service
+} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/csrng.h b/src/core/hle/service/spl/csrng.h
index 59ca794dd..3f849b5a7 100644
--- a/src/core/hle/service/spl/csrng.h
+++ b/src/core/hle/service/spl/csrng.h
@@ -6,13 +6,11 @@
#include "core/hle/service/spl/module.h"
-namespace Service {
-namespace SPL {
+namespace Service::SPL {
class CSRNG final : public Module::Interface {
public:
explicit CSRNG(std::shared_ptr<Module> module);
};
-} // namespace SPL
-} // namespace Service
+} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index fc1bcd94c..3f5a342a7 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -11,8 +11,7 @@
#include "core/hle/service/spl/module.h"
#include "core/hle/service/spl/spl.h"
-namespace Service {
-namespace SPL {
+namespace Service::SPL {
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {}
@@ -38,5 +37,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<SPL>(module)->InstallAsService(service_manager);
}
-} // namespace SPL
-} // namespace Service
+} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h
index 12cdb2980..6ab91b400 100644
--- a/src/core/hle/service/spl/module.h
+++ b/src/core/hle/service/spl/module.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace SPL {
+namespace Service::SPL {
class Module final {
public:
@@ -25,5 +24,4 @@ public:
/// Registers all SPL services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace SPL
-} // namespace Service
+} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp
index deab29b91..bb1e03342 100644
--- a/src/core/hle/service/spl/spl.cpp
+++ b/src/core/hle/service/spl/spl.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/spl/spl.h"
-namespace Service {
-namespace SPL {
+namespace Service::SPL {
SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") {
static const FunctionInfo functions[] = {
@@ -33,9 +32,14 @@ SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module),
{23, nullptr, "GetSplWaitEvent"},
{24, nullptr, "SetSharedData"},
{25, nullptr, "GetSharedData"},
+ {26, nullptr, "ImportSslRsaKey"},
+ {27, nullptr, "SecureExpModWithSslKey"},
+ {28, nullptr, "ImportEsRsaKey"},
+ {29, nullptr, "SecureExpModWithEsKey"},
+ {30, nullptr, "EncryptManuRsaKeyForImport"},
+ {31, nullptr, "GetPackage2Hash"},
};
RegisterHandlers(functions);
}
-} // namespace SPL
-} // namespace Service
+} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/spl.h b/src/core/hle/service/spl/spl.h
index 9fd6059af..69c4c1747 100644
--- a/src/core/hle/service/spl/spl.h
+++ b/src/core/hle/service/spl/spl.h
@@ -6,13 +6,11 @@
#include "core/hle/service/spl/module.h"
-namespace Service {
-namespace SPL {
+namespace Service::SPL {
class SPL final : public Module::Interface {
public:
explicit SPL(std::shared_ptr<Module> module);
};
-} // namespace SPL
-} // namespace Service
+} // namespace Service::SPL
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 01a03ec83..11d438728 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -5,8 +5,7 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/ssl/ssl.h"
-namespace Service {
-namespace SSL {
+namespace Service::SSL {
class ISslConnection final : public ServiceFramework<ISslConnection> {
public:
@@ -107,5 +106,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<SSL>()->InstallAsService(service_manager);
}
-} // namespace SSL
-} // namespace Service
+} // namespace Service::SSL
diff --git a/src/core/hle/service/ssl/ssl.h b/src/core/hle/service/ssl/ssl.h
index 7fcff5ccd..87538a639 100644
--- a/src/core/hle/service/ssl/ssl.h
+++ b/src/core/hle/service/ssl/ssl.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace SSL {
+namespace Service::SSL {
class SSL final : public ServiceFramework<SSL> {
public:
@@ -21,5 +20,4 @@ private:
/// Registers all SSL services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace SSL
-} // namespace Service
+} // namespace Service::SSL
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index c3e46f866..2604ecc1c 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -12,15 +12,18 @@
#include "core/hle/service/time/time_s.h"
#include "core/hle/service/time/time_u.h"
-namespace Service {
-namespace Time {
+namespace Service::Time {
class ISystemClock final : public ServiceFramework<ISystemClock> {
public:
ISystemClock() : ServiceFramework("ISystemClock") {
static const FunctionInfo functions[] = {
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
- {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}};
+ {1, nullptr, "SetCurrentTime"},
+ {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"},
+ {3, nullptr, "SetSystemClockContext"},
+
+ };
RegisterHandlers(functions);
}
@@ -162,5 +165,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<TIME_U>(time)->InstallAsService(service_manager);
}
-} // namespace Time
-} // namespace Service
+} // namespace Service::Time
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 197029e7a..12fe1995a 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -6,8 +6,7 @@
#include "core/hle/service/service.h"
-namespace Service {
-namespace Time {
+namespace Service::Time {
// TODO(Rozelette) RE this structure
struct LocationName {
@@ -66,5 +65,4 @@ public:
/// Registers all Time services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
-} // namespace Time
-} // namespace Service
+} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_s.cpp b/src/core/hle/service/time/time_s.cpp
index b172b2bd6..0b599ea00 100644
--- a/src/core/hle/service/time/time_s.cpp
+++ b/src/core/hle/service/time/time_s.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/time/time_s.h"
-namespace Service {
-namespace Time {
+namespace Service::Time {
TIME_S::TIME_S(std::shared_ptr<Module> time) : Module::Interface(std::move(time), "time:s") {
static const FunctionInfo functions[] = {
@@ -14,9 +13,19 @@ TIME_S::TIME_S(std::shared_ptr<Module> time) : Module::Interface(std::move(time)
{2, &TIME_S::GetStandardSteadyClock, "GetStandardSteadyClock"},
{3, &TIME_S::GetTimeZoneService, "GetTimeZoneService"},
{4, &TIME_S::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
+ {5, nullptr, "GetEphemeralNetworkSystemClock"},
+ {50, nullptr, "SetStandardSteadyClockInternalOffset"},
+ {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
+ {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
+ {102, nullptr, "GetStandardUserSystemClockInitialYear"},
+ {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
+ {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
+ {400, nullptr, "GetClockSnapshot"},
+ {401, nullptr, "GetClockSnapshotFromSystemClockContext"},
+ {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
+ {501, nullptr, "CalculateSpanBetween"},
};
RegisterHandlers(functions);
}
-} // namespace Time
-} // namespace Service
+} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_s.h b/src/core/hle/service/time/time_s.h
index abc2a8c5a..4a2daa513 100644
--- a/src/core/hle/service/time/time_s.h
+++ b/src/core/hle/service/time/time_s.h
@@ -6,13 +6,11 @@
#include "core/hle/service/time/time.h"
-namespace Service {
-namespace Time {
+namespace Service::Time {
class TIME_S final : public Module::Interface {
public:
explicit TIME_S(std::shared_ptr<Module> time);
};
-} // namespace Time
-} // namespace Service
+} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_u.cpp b/src/core/hle/service/time/time_u.cpp
index fc1ace325..1ed42c419 100644
--- a/src/core/hle/service/time/time_u.cpp
+++ b/src/core/hle/service/time/time_u.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/time/time_u.h"
-namespace Service {
-namespace Time {
+namespace Service::Time {
TIME_U::TIME_U(std::shared_ptr<Module> time) : Module::Interface(std::move(time), "time:u") {
static const FunctionInfo functions[] = {
@@ -14,9 +13,19 @@ TIME_U::TIME_U(std::shared_ptr<Module> time) : Module::Interface(std::move(time)
{2, &TIME_U::GetStandardSteadyClock, "GetStandardSteadyClock"},
{3, &TIME_U::GetTimeZoneService, "GetTimeZoneService"},
{4, &TIME_U::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
+ {5, nullptr, "GetEphemeralNetworkSystemClock"},
+ {50, nullptr, "SetStandardSteadyClockInternalOffset"},
+ {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
+ {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
+ {102, nullptr, "GetStandardUserSystemClockInitialYear"},
+ {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
+ {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
+ {400, nullptr, "GetClockSnapshot"},
+ {401, nullptr, "GetClockSnapshotFromSystemClockContext"},
+ {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
+ {501, nullptr, "CalculateSpanBetween"},
};
RegisterHandlers(functions);
}
-} // namespace Time
-} // namespace Service
+} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_u.h b/src/core/hle/service/time/time_u.h
index f99d25057..3724bcdc7 100644
--- a/src/core/hle/service/time/time_u.h
+++ b/src/core/hle/service/time/time_u.h
@@ -6,13 +6,11 @@
#include "core/hle/service/time/time.h"
-namespace Service {
-namespace Time {
+namespace Service::Time {
class TIME_U final : public Module::Interface {
public:
explicit TIME_U(std::shared_ptr<Module> time);
};
-} // namespace Time
-} // namespace Service
+} // namespace Service::Time
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 715206493..36ae2215f 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -21,8 +21,7 @@
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
-namespace Service {
-namespace VI {
+namespace Service::VI {
struct DisplayInfo {
char display_name[0x40]{"Default"};
@@ -150,7 +149,7 @@ private:
class NativeWindow : public Parcel {
public:
- explicit NativeWindow(u32 id) : Parcel() {
+ explicit NativeWindow(u32 id) {
data.id = id;
}
~NativeWindow() override = default;
@@ -197,7 +196,7 @@ public:
class IGBPConnectResponseParcel : public Parcel {
public:
- explicit IGBPConnectResponseParcel(u32 width, u32 height) : Parcel() {
+ explicit IGBPConnectResponseParcel(u32 width, u32 height) {
data.width = width;
data.height = height;
}
@@ -247,10 +246,6 @@ public:
};
class IGBPSetPreallocatedBufferResponseParcel : public Parcel {
-public:
- IGBPSetPreallocatedBufferResponseParcel() : Parcel() {}
- ~IGBPSetPreallocatedBufferResponseParcel() override = default;
-
protected:
void SerializeData() override {
// TODO(Subv): Find out what this means
@@ -289,7 +284,7 @@ static_assert(sizeof(BufferProducerFence) == 36, "BufferProducerFence has wrong
class IGBPDequeueBufferResponseParcel : public Parcel {
public:
- explicit IGBPDequeueBufferResponseParcel(u32 slot) : Parcel(), slot(slot) {}
+ explicit IGBPDequeueBufferResponseParcel(u32 slot) : slot(slot) {}
~IGBPDequeueBufferResponseParcel() override = default;
protected:
@@ -383,7 +378,7 @@ public:
class IGBPQueueBufferResponseParcel : public Parcel {
public:
- explicit IGBPQueueBufferResponseParcel(u32 width, u32 height) : Parcel() {
+ explicit IGBPQueueBufferResponseParcel(u32 width, u32 height) {
data.width = width;
data.height = height;
}
@@ -424,7 +419,7 @@ public:
class IGBPQueryResponseParcel : public Parcel {
public:
- explicit IGBPQueryResponseParcel(u32 value) : Parcel(), value(value) {}
+ explicit IGBPQueryResponseParcel(u32 value) : value(value) {}
~IGBPQueryResponseParcel() override = default;
protected:
@@ -580,7 +575,48 @@ public:
ISystemDisplayService() : ServiceFramework("ISystemDisplayService") {
static const FunctionInfo functions[] = {
{1200, nullptr, "GetZOrderCountMin"},
+ {1202, nullptr, "GetZOrderCountMax"},
+ {1203, nullptr, "GetDisplayLogicalResolution"},
+ {1204, nullptr, "SetDisplayMagnification"},
+ {2201, nullptr, "SetLayerPosition"},
+ {2203, nullptr, "SetLayerSize"},
+ {2204, nullptr, "GetLayerZ"},
{2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
+ {2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"},
+ {2209, nullptr, "SetLayerAlpha"},
+ {2312, nullptr, "CreateStrayLayer"},
+ {2400, nullptr, "OpenIndirectLayer"},
+ {2401, nullptr, "CloseIndirectLayer"},
+ {2402, nullptr, "FlipIndirectLayer"},
+ {3000, nullptr, "ListDisplayModes"},
+ {3001, nullptr, "ListDisplayRgbRanges"},
+ {3002, nullptr, "ListDisplayContentTypes"},
+ {3200, nullptr, "GetDisplayMode"},
+ {3201, nullptr, "SetDisplayMode"},
+ {3202, nullptr, "GetDisplayUnderscan"},
+ {3203, nullptr, "SetDisplayUnderscan"},
+ {3204, nullptr, "GetDisplayContentType"},
+ {3205, nullptr, "SetDisplayContentType"},
+ {3206, nullptr, "GetDisplayRgbRange"},
+ {3207, nullptr, "SetDisplayRgbRange"},
+ {3208, nullptr, "GetDisplayCmuMode"},
+ {3209, nullptr, "SetDisplayCmuMode"},
+ {3210, nullptr, "GetDisplayContrastRatio"},
+ {3211, nullptr, "SetDisplayContrastRatio"},
+ {3214, nullptr, "GetDisplayGamma"},
+ {3215, nullptr, "SetDisplayGamma"},
+ {3216, nullptr, "GetDisplayCmuLuma"},
+ {3217, nullptr, "SetDisplayCmuLuma"},
+ {8225, nullptr, "GetSharedBufferMemoryHandleId"},
+ {8250, nullptr, "OpenSharedLayer"},
+ {8251, nullptr, "CloseSharedLayer"},
+ {8252, nullptr, "ConnectSharedLayer"},
+ {8253, nullptr, "DisconnectSharedLayer"},
+ {8254, nullptr, "AcquireSharedFrameBuffer"},
+ {8255, nullptr, "PresentSharedFrameBuffer"},
+ {8256, nullptr, "GetSharedFrameBufferAcquirableEvent"},
+ {8257, nullptr, "FillSharedFrameBufferColor"},
+ {8258, nullptr, "CancelSharedFrameBuffer"},
};
RegisterHandlers(functions);
}
@@ -596,6 +632,16 @@ private:
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(RESULT_SUCCESS);
}
+
+ void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ u64 layer_id = rp.Pop<u64>();
+ bool visibility = rp.Pop<bool>();
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x%x, visibility=%u", layer_id,
+ visibility);
+ }
};
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
@@ -603,10 +649,72 @@ public:
explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
: ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) {
static const FunctionInfo functions[] = {
+ {200, nullptr, "AllocateProcessHeapBlock"},
+ {201, nullptr, "FreeProcessHeapBlock"},
{1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"},
{1102, nullptr, "GetDisplayResolution"},
{2010, &IManagerDisplayService::CreateManagedLayer, "CreateManagedLayer"},
+ {2011, nullptr, "DestroyManagedLayer"},
+ {2050, nullptr, "CreateIndirectLayer"},
+ {2051, nullptr, "DestroyIndirectLayer"},
+ {2052, nullptr, "CreateIndirectProducerEndPoint"},
+ {2053, nullptr, "DestroyIndirectProducerEndPoint"},
+ {2054, nullptr, "CreateIndirectConsumerEndPoint"},
+ {2055, nullptr, "DestroyIndirectConsumerEndPoint"},
+ {2300, nullptr, "AcquireLayerTexturePresentingEvent"},
+ {2301, nullptr, "ReleaseLayerTexturePresentingEvent"},
+ {2302, nullptr, "GetDisplayHotplugEvent"},
+ {2402, nullptr, "GetDisplayHotplugState"},
+ {2501, nullptr, "GetCompositorErrorInfo"},
+ {2601, nullptr, "GetDisplayErrorEvent"},
+ {4201, nullptr, "SetDisplayAlpha"},
+ {4203, nullptr, "SetDisplayLayerStack"},
+ {4205, nullptr, "SetDisplayPowerState"},
+ {4206, nullptr, "SetDefaultDisplay"},
{6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
+ {6001, nullptr, "RemoveFromLayerStack"},
+ {6002, &IManagerDisplayService::SetLayerVisibility, "SetLayerVisibility"},
+ {6003, nullptr, "SetLayerConfig"},
+ {6004, nullptr, "AttachLayerPresentationTracer"},
+ {6005, nullptr, "DetachLayerPresentationTracer"},
+ {6006, nullptr, "StartLayerPresentationRecording"},
+ {6007, nullptr, "StopLayerPresentationRecording"},
+ {6008, nullptr, "StartLayerPresentationFenceWait"},
+ {6009, nullptr, "StopLayerPresentationFenceWait"},
+ {6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"},
+ {7000, nullptr, "SetContentVisibility"},
+ {8000, nullptr, "SetConductorLayer"},
+ {8100, nullptr, "SetIndirectProducerFlipOffset"},
+ {8200, nullptr, "CreateSharedBufferStaticStorage"},
+ {8201, nullptr, "CreateSharedBufferTransferMemory"},
+ {8202, nullptr, "DestroySharedBuffer"},
+ {8203, nullptr, "BindSharedLowLevelLayerToManagedLayer"},
+ {8204, nullptr, "BindSharedLowLevelLayerToIndirectLayer"},
+ {8207, nullptr, "UnbindSharedLowLevelLayer"},
+ {8208, nullptr, "ConnectSharedLowLevelLayerToSharedBuffer"},
+ {8209, nullptr, "DisconnectSharedLowLevelLayerFromSharedBuffer"},
+ {8210, nullptr, "CreateSharedLayer"},
+ {8211, nullptr, "DestroySharedLayer"},
+ {8216, nullptr, "AttachSharedLayerToLowLevelLayer"},
+ {8217, nullptr, "ForceDetachSharedLayerFromLowLevelLayer"},
+ {8218, nullptr, "StartDetachSharedLayerFromLowLevelLayer"},
+ {8219, nullptr, "FinishDetachSharedLayerFromLowLevelLayer"},
+ {8220, nullptr, "GetSharedLayerDetachReadyEvent"},
+ {8221, nullptr, "GetSharedLowLevelLayerSynchronizedEvent"},
+ {8222, nullptr, "CheckSharedLowLevelLayerSynchronized"},
+ {8223, nullptr, "RegisterSharedBufferImporterAruid"},
+ {8224, nullptr, "UnregisterSharedBufferImporterAruid"},
+ {8227, nullptr, "CreateSharedBufferProcessHeap"},
+ {8228, nullptr, "GetSharedLayerLayerStacks"},
+ {8229, nullptr, "SetSharedLayerLayerStacks"},
+ {8291, nullptr, "PresentDetachedSharedFrameBufferToLowLevelLayer"},
+ {8292, nullptr, "FillDetachedSharedFrameBufferColor"},
+ {8293, nullptr, "GetDetachedSharedFrameBufferImage"},
+ {8294, nullptr, "SetDetachedSharedFrameBufferImage"},
+ {8295, nullptr, "CopyDetachedSharedFrameBufferImage"},
+ {8296, nullptr, "SetDetachedSharedFrameBufferSubImage"},
+ {8297, nullptr, "GetSharedFrameBufferContentParameter"},
+ {8298, nullptr, "ExpandStartupLogoOnSharedFrameBuffer"},
};
RegisterHandlers(functions);
}
@@ -647,6 +755,16 @@ private:
rb.Push(RESULT_SUCCESS);
}
+ void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ u64 layer_id = rp.Pop<u64>();
+ bool visibility = rp.Pop<bool>();
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x%x, visibility=%u", layer_id,
+ visibility);
+ }
+
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
};
@@ -717,15 +835,15 @@ private:
IPC::RequestParser rp{ctx};
u64 display_id = rp.Pop<u64>();
- IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0);
rb.Push(RESULT_SUCCESS);
if (Settings::values.use_docked_mode) {
- rb.Push(static_cast<u32>(DisplayResolution::DockedWidth));
- rb.Push(static_cast<u32>(DisplayResolution::DockedHeight));
+ rb.Push(static_cast<u64>(DisplayResolution::DockedWidth));
+ rb.Push(static_cast<u64>(DisplayResolution::DockedHeight));
} else {
- rb.Push(static_cast<u32>(DisplayResolution::UndockedWidth));
- rb.Push(static_cast<u32>(DisplayResolution::UndockedHeight));
+ rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth));
+ rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight));
}
}
@@ -825,13 +943,21 @@ IApplicationDisplayService::IApplicationDisplayService(
"GetIndirectDisplayTransactionService"},
{1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
{1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
+ {1011, nullptr, "OpenDefaultDisplay"},
{1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
+ {1101, nullptr, "SetDisplayEnabled"},
{1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
- {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
{2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
+ {2021, nullptr, "CloseLayer"},
{2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
{2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
+ {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
+ {2102, nullptr, "ConvertScalingMode"},
+ {2450, nullptr, "GetIndirectLayerImageMap"},
+ {2451, nullptr, "GetIndirectLayerImageCropMap"},
+ {2460, nullptr, "GetIndirectLayerImageRequiredMemoryInfo"},
{5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
+ {5203, nullptr, "GetDisplayVsyncEventForDebug"},
};
RegisterHandlers(functions);
}
@@ -856,5 +982,4 @@ void InstallInterfaces(SM::ServiceManager& service_manager,
std::make_shared<VI_U>(module, nv_flinger)->InstallAsService(service_manager);
}
-} // namespace VI
-} // namespace Service
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 7f16fad8e..e8bda01d7 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -11,8 +11,7 @@ namespace CoreTiming {
struct EventType;
}
-namespace Service {
-namespace VI {
+namespace Service::VI {
enum class DisplayResolution : u32 {
DockedWidth = 1920,
@@ -40,5 +39,4 @@ public:
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
-} // namespace VI
-} // namespace Service
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp
index 5781fa9ec..d47da565b 100644
--- a/src/core/hle/service/vi/vi_m.cpp
+++ b/src/core/hle/service/vi/vi_m.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/vi/vi_m.h"
-namespace Service {
-namespace VI {
+namespace Service::VI {
VI_M::VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
: Module::Interface(std::move(module), "vi:m", std::move(nv_flinger)) {
@@ -16,5 +15,4 @@ VI_M::VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger>
RegisterHandlers(functions);
}
-} // namespace VI
-} // namespace Service
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h
index 0f7b799d6..6abb9b3a3 100644
--- a/src/core/hle/service/vi/vi_m.h
+++ b/src/core/hle/service/vi/vi_m.h
@@ -6,13 +6,11 @@
#include "core/hle/service/vi/vi.h"
-namespace Service {
-namespace VI {
+namespace Service::VI {
class VI_M final : public Module::Interface {
public:
explicit VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
};
-} // namespace VI
-} // namespace Service
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp
index 1f937b2a8..8f82e797f 100644
--- a/src/core/hle/service/vi/vi_s.cpp
+++ b/src/core/hle/service/vi/vi_s.cpp
@@ -4,8 +4,7 @@
#include "core/hle/service/vi/vi_s.h"
-namespace Service {
-namespace VI {
+namespace Service::VI {
VI_S::VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
: Module::Interface(std::move(module), "vi:s", std::move(nv_flinger)) {
@@ -16,5 +15,4 @@ VI_S::VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger>
RegisterHandlers(functions);
}
-} // namespace VI
-} // namespace Service
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h
index 7b32fdddc..8f16f804f 100644
--- a/src/core/hle/service/vi/vi_s.h
+++ b/src/core/hle/service/vi/vi_s.h
@@ -6,13 +6,11 @@
#include "core/hle/service/vi/vi.h"
-namespace Service {
-namespace VI {
+namespace Service::VI {
class VI_S final : public Module::Interface {
public:
explicit VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
};
-} // namespace VI
-} // namespace Service
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp
index 14e375b86..b84aed1d5 100644
--- a/src/core/hle/service/vi/vi_u.cpp
+++ b/src/core/hle/service/vi/vi_u.cpp
@@ -4,17 +4,14 @@
#include "core/hle/service/vi/vi_u.h"
-namespace Service {
-namespace VI {
+namespace Service::VI {
VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
: Module::Interface(std::move(module), "vi:u", std::move(nv_flinger)) {
static const FunctionInfo functions[] = {
{0, &VI_U::GetDisplayService, "GetDisplayService"},
- {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
};
RegisterHandlers(functions);
}
-} // namespace VI
-} // namespace Service
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h
index c557a2235..e9b4f76b2 100644
--- a/src/core/hle/service/vi/vi_u.h
+++ b/src/core/hle/service/vi/vi_u.h
@@ -6,13 +6,11 @@
#include "core/hle/service/vi/vi.h"
-namespace Service {
-namespace VI {
+namespace Service::VI {
class VI_U final : public Module::Interface {
public:
explicit VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
};
-} // namespace VI
-} // namespace Service
+} // namespace Service::VI
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index ad3b56fcc..5f53b16d3 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <chrono>
#include <mutex>
#include <thread>
@@ -87,7 +88,7 @@ void FrameLimiter::DoFrameLimiting(u64 current_system_time_us) {
frame_limiting_delta_err += microseconds(current_system_time_us - previous_system_time_us);
frame_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime);
frame_limiting_delta_err =
- MathUtil::Clamp(frame_limiting_delta_err, -MAX_LAG_TIME_US, MAX_LAG_TIME_US);
+ std::clamp(frame_limiting_delta_err, -MAX_LAG_TIME_US, MAX_LAG_TIME_US);
if (frame_limiting_delta_err > microseconds::zero()) {
std::this_thread::sleep_for(frame_limiting_delta_err);
diff --git a/src/input_common/motion_emu.cpp b/src/input_common/motion_emu.cpp
index 59a035e70..caffe48cb 100644
--- a/src/input_common/motion_emu.cpp
+++ b/src/input_common/motion_emu.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <chrono>
#include <mutex>
#include <thread>
@@ -43,8 +44,8 @@ public:
tilt_angle = 0;
} else {
tilt_direction = mouse_move.Cast<float>();
- tilt_angle = MathUtil::Clamp(tilt_direction.Normalize() * sensitivity, 0.0f,
- MathUtil::PI * 0.5f);
+ tilt_angle =
+ std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f, MathUtil::PI * 0.5f);
}
}
}
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index a710c4bc5..281810357 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -9,6 +9,7 @@ add_library(video_core STATIC
engines/maxwell_3d.h
engines/maxwell_compute.cpp
engines/maxwell_compute.h
+ engines/shader_bytecode.h
gpu.cpp
gpu.h
macro_interpreter.cpp
@@ -27,6 +28,8 @@ add_library(video_core STATIC
renderer_opengl/gl_shader_decompiler.h
renderer_opengl/gl_shader_gen.cpp
renderer_opengl/gl_shader_gen.h
+ renderer_opengl/gl_shader_manager.cpp
+ renderer_opengl/gl_shader_manager.h
renderer_opengl/gl_shader_util.cpp
renderer_opengl/gl_shader_util.h
renderer_opengl/gl_state.cpp
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 2d7c3152f..2a3ff234a 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -74,8 +74,6 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
regs.reg_array[method] = value;
-#define MAXWELL3D_REG_INDEX(field_name) (offsetof(Regs, field_name) / sizeof(u32))
-
switch (method) {
case MAXWELL3D_REG_INDEX(code_address.code_address_high):
case MAXWELL3D_REG_INDEX(code_address.code_address_low): {
@@ -136,7 +134,7 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
break;
}
-#undef MAXWELL3D_REG_INDEX
+ VideoCore::g_renderer->Rasterizer()->NotifyMaxwellRegisterChanged(method);
if (debug_context) {
debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr);
@@ -165,6 +163,7 @@ void Maxwell3D::ProcessQueryGet() {
void Maxwell3D::DrawArrays() {
LOG_DEBUG(HW_GPU, "called, topology=%d, count=%d", regs.draw.topology.Value(),
regs.vertex_buffer.count);
+ ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
auto debug_context = Core::System::GetInstance().GetGPUDebugContext();
@@ -176,7 +175,8 @@ void Maxwell3D::DrawArrays() {
debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
}
- VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(false /*is_indexed*/);
+ const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
+ VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(is_indexed);
}
void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {
@@ -218,10 +218,12 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
Texture::TICEntry tic_entry;
Memory::ReadBlock(tic_address_cpu, &tic_entry, sizeof(Texture::TICEntry));
- ASSERT_MSG(tic_entry.header_version == Texture::TICHeaderVersion::BlockLinear,
- "TIC versions other than BlockLinear are unimplemented");
+ ASSERT_MSG(tic_entry.header_version == Texture::TICHeaderVersion::BlockLinear ||
+ tic_entry.header_version == Texture::TICHeaderVersion::Pitch,
+ "TIC versions other than BlockLinear or Pitch are unimplemented");
- ASSERT_MSG(tic_entry.texture_type == Texture::TextureType::Texture2D,
+ ASSERT_MSG((tic_entry.texture_type == Texture::TextureType::Texture2D) ||
+ (tic_entry.texture_type == Texture::TextureType::Texture2DNoMipmap),
"Texture types other than Texture2D are unimplemented");
auto r_type = tic_entry.r_type.Value();
@@ -301,5 +303,26 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const {
return regs.reg_array[method];
}
+bool Maxwell3D::IsShaderStageEnabled(Regs::ShaderStage stage) const {
+ // The Vertex stage is always enabled.
+ if (stage == Regs::ShaderStage::Vertex)
+ return true;
+
+ switch (stage) {
+ case Regs::ShaderStage::TesselationControl:
+ return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::TesselationControl)]
+ .enable != 0;
+ case Regs::ShaderStage::TesselationEval:
+ return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::TesselationEval)]
+ .enable != 0;
+ case Regs::ShaderStage::Geometry:
+ return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::Geometry)].enable != 0;
+ case Regs::ShaderStage::Fragment:
+ return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::Fragment)].enable != 0;
+ }
+
+ UNREACHABLE();
+}
+
} // namespace Engines
} // namespace Tegra
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 98b39b2ff..d4fcedace 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -20,6 +20,9 @@
namespace Tegra {
namespace Engines {
+#define MAXWELL3D_REG_INDEX(field_name) \
+ (offsetof(Tegra::Engines::Maxwell3D::Regs, field_name) / sizeof(u32))
+
class Maxwell3D final {
public:
explicit Maxwell3D(MemoryManager& memory_manager);
@@ -248,6 +251,52 @@ public:
Patches = 0xe,
};
+ enum class IndexFormat : u32 {
+ UnsignedByte = 0x0,
+ UnsignedShort = 0x1,
+ UnsignedInt = 0x2,
+ };
+
+ struct Blend {
+ enum class Equation : u32 {
+ Add = 1,
+ Subtract = 2,
+ ReverseSubtract = 3,
+ Min = 4,
+ Max = 5,
+ };
+
+ enum class Factor : u32 {
+ Zero = 0x1,
+ One = 0x2,
+ SourceColor = 0x3,
+ OneMinusSourceColor = 0x4,
+ SourceAlpha = 0x5,
+ OneMinusSourceAlpha = 0x6,
+ DestAlpha = 0x7,
+ OneMinusDestAlpha = 0x8,
+ DestColor = 0x9,
+ OneMinusDestColor = 0xa,
+ SourceAlphaSaturate = 0xb,
+ Source1Color = 0x10,
+ OneMinusSource1Color = 0x11,
+ Source1Alpha = 0x12,
+ OneMinusSource1Alpha = 0x13,
+ ConstantColor = 0x61,
+ OneMinusConstantColor = 0x62,
+ ConstantAlpha = 0x63,
+ OneMinusConstantAlpha = 0x64,
+ };
+
+ u32 separate_alpha;
+ Equation equation_rgb;
+ Factor factor_source_rgb;
+ Factor factor_dest_rgb;
+ Equation equation_a;
+ Factor factor_source_a;
+ Factor factor_dest_a;
+ };
+
union {
struct {
INSERT_PADDING_WORDS(0x200);
@@ -270,7 +319,15 @@ public:
}
} rt[NumRenderTargets];
- INSERT_PADDING_WORDS(0x80);
+ struct {
+ f32 scale_x;
+ f32 scale_y;
+ f32 scale_z;
+ u32 translate_x;
+ u32 translate_y;
+ u32 translate_z;
+ INSERT_PADDING_WORDS(2);
+ } viewport_transform[NumViewports];
struct {
union {
@@ -375,7 +432,42 @@ public:
};
} draw;
- INSERT_PADDING_WORDS(0x139);
+ INSERT_PADDING_WORDS(0x6B);
+
+ struct {
+ u32 start_addr_high;
+ u32 start_addr_low;
+ u32 end_addr_high;
+ u32 end_addr_low;
+ IndexFormat format;
+ u32 first;
+ u32 count;
+
+ unsigned FormatSizeInBytes() const {
+ switch (format) {
+ case IndexFormat::UnsignedByte:
+ return 1;
+ case IndexFormat::UnsignedShort:
+ return 2;
+ case IndexFormat::UnsignedInt:
+ return 4;
+ }
+ UNREACHABLE();
+ }
+
+ GPUVAddr StartAddress() const {
+ return static_cast<GPUVAddr>(
+ (static_cast<GPUVAddr>(start_addr_high) << 32) | start_addr_low);
+ }
+
+ GPUVAddr EndAddress() const {
+ return static_cast<GPUVAddr>((static_cast<GPUVAddr>(end_addr_high) << 32) |
+ end_addr_low);
+ }
+ } index_array;
+
+ INSERT_PADDING_WORDS(0xC7);
+
struct {
u32 query_address_high;
u32 query_address_low;
@@ -410,7 +502,9 @@ public:
}
} vertex_array[NumVertexArrays];
- INSERT_PADDING_WORDS(0x40);
+ Blend blend;
+
+ INSERT_PADDING_WORDS(0x39);
struct {
u32 limit_high;
@@ -427,14 +521,11 @@ public:
BitField<0, 1, u32> enable;
BitField<4, 4, ShaderProgram> program;
};
- u32 start_id;
- INSERT_PADDING_WORDS(1);
- u32 gpr_alloc;
- ShaderStage type;
- INSERT_PADDING_WORDS(9);
+ u32 offset;
+ INSERT_PADDING_WORDS(14);
} shader_config[MaxShaderProgram];
- INSERT_PADDING_WORDS(0x8C);
+ INSERT_PADDING_WORDS(0x80);
struct {
u32 cb_size;
@@ -507,6 +598,7 @@ public:
};
State state{};
+ MemoryManager& memory_manager;
/// Reads a register value located at the input method address
u32 GetRegisterValue(u32 method) const;
@@ -520,9 +612,10 @@ public:
/// Returns a list of enabled textures for the specified shader stage.
std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const;
-private:
- MemoryManager& memory_manager;
+ /// Returns whether the specified shader stage is enabled or not.
+ bool IsShaderStageEnabled(Regs::ShaderStage stage) const;
+private:
std::unordered_map<u32, std::vector<u32>> uploaded_macros;
/// Macro method that is currently being executed / being fed parameters.
@@ -564,6 +657,7 @@ private:
"Field " #field_name " has invalid position")
ASSERT_REG_POSITION(rt, 0x200);
+ASSERT_REG_POSITION(viewport_transform[0], 0x280);
ASSERT_REG_POSITION(viewport, 0x300);
ASSERT_REG_POSITION(vertex_buffer, 0x35D);
ASSERT_REG_POSITION(zeta, 0x3F8);
@@ -573,8 +667,10 @@ ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(tic, 0x55D);
ASSERT_REG_POSITION(code_address, 0x582);
ASSERT_REG_POSITION(draw, 0x585);
+ASSERT_REG_POSITION(index_array, 0x5F2);
ASSERT_REG_POSITION(query, 0x6C0);
ASSERT_REG_POSITION(vertex_array[0], 0x700);
+ASSERT_REG_POSITION(blend, 0x780);
ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0);
ASSERT_REG_POSITION(shader_config[0], 0x800);
ASSERT_REG_POSITION(const_buffer, 0x8E0);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
new file mode 100644
index 000000000..5a006aee5
--- /dev/null
+++ b/src/video_core/engines/shader_bytecode.h
@@ -0,0 +1,439 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <bitset>
+#include <cstring>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <boost/optional.hpp>
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+
+namespace Tegra {
+namespace Shader {
+
+struct Register {
+ // Register 255 is special cased to always be 0
+ static constexpr size_t ZeroIndex = 255;
+
+ constexpr Register() = default;
+
+ constexpr Register(u64 value) : value(value) {}
+
+ constexpr operator u64() const {
+ return value;
+ }
+
+ template <typename T>
+ constexpr u64 operator-(const T& oth) const {
+ return value - oth;
+ }
+
+ template <typename T>
+ constexpr u64 operator&(const T& oth) const {
+ return value & oth;
+ }
+
+ constexpr u64 operator&(const Register& oth) const {
+ return value & oth.value;
+ }
+
+ constexpr u64 operator~() const {
+ return ~value;
+ }
+
+private:
+ u64 value{};
+};
+
+union Attribute {
+ Attribute() = default;
+
+ constexpr explicit Attribute(u64 value) : value(value) {}
+
+ enum class Index : u64 {
+ Position = 7,
+ Attribute_0 = 8,
+ };
+
+ union {
+ BitField<22, 2, u64> element;
+ BitField<24, 6, Index> index;
+ BitField<47, 3, u64> size;
+ } fmt20;
+
+ union {
+ BitField<30, 2, u64> element;
+ BitField<32, 6, Index> index;
+ } fmt28;
+
+ BitField<39, 8, u64> reg;
+ u64 value{};
+};
+
+union Sampler {
+ Sampler() = default;
+
+ constexpr explicit Sampler(u64 value) : value(value) {}
+
+ enum class Index : u64 {
+ Sampler_0 = 8,
+ };
+
+ BitField<36, 13, Index> index;
+ u64 value{};
+};
+
+union Uniform {
+ BitField<20, 14, u64> offset;
+ BitField<34, 5, u64> index;
+};
+
+} // namespace Shader
+} // namespace Tegra
+
+namespace std {
+
+// TODO(bunnei): The below is forbidden by the C++ standard, but works fine. See #330.
+template <>
+struct make_unsigned<Tegra::Shader::Attribute> {
+ using type = Tegra::Shader::Attribute;
+};
+
+template <>
+struct make_unsigned<Tegra::Shader::Register> {
+ using type = Tegra::Shader::Register;
+};
+
+} // namespace std
+
+namespace Tegra {
+namespace Shader {
+
+enum class Pred : u64 {
+ UnusedIndex = 0x7,
+ NeverExecute = 0xF,
+};
+
+enum class PredCondition : u64 {
+ LessThan = 1,
+ Equal = 2,
+ LessEqual = 3,
+ GreaterThan = 4,
+ NotEqual = 5,
+ GreaterEqual = 6,
+ // TODO(Subv): Other condition types
+};
+
+enum class PredOperation : u64 {
+ And = 0,
+ Or = 1,
+ Xor = 2,
+};
+
+enum class SubOp : u64 {
+ Cos = 0x0,
+ Sin = 0x1,
+ Ex2 = 0x2,
+ Lg2 = 0x3,
+ Rcp = 0x4,
+ Rsq = 0x5,
+ Min = 0x8,
+};
+
+union Instruction {
+ Instruction& operator=(const Instruction& instr) {
+ value = instr.value;
+ return *this;
+ }
+
+ constexpr Instruction(u64 value) : value{value} {}
+
+ BitField<0, 8, Register> gpr0;
+ BitField<8, 8, Register> gpr8;
+ union {
+ BitField<16, 4, Pred> full_pred;
+ BitField<16, 3, u64> pred_index;
+ } pred;
+ BitField<19, 1, u64> negate_pred;
+ BitField<20, 8, Register> gpr20;
+ BitField<20, 7, SubOp> sub_op;
+ BitField<28, 8, Register> gpr28;
+ BitField<39, 8, Register> gpr39;
+ BitField<48, 16, u64> opcode;
+
+ union {
+ BitField<20, 19, u64> imm20_19;
+ BitField<20, 32, u64> imm20_32;
+ BitField<45, 1, u64> negate_b;
+ BitField<46, 1, u64> abs_a;
+ BitField<48, 1, u64> negate_a;
+ BitField<49, 1, u64> abs_b;
+ BitField<50, 1, u64> abs_d;
+ BitField<56, 1, u64> negate_imm;
+
+ float GetImm20_19() const {
+ float result{};
+ u32 imm{static_cast<u32>(imm20_19)};
+ imm <<= 12;
+ imm |= negate_imm ? 0x80000000 : 0;
+ std::memcpy(&result, &imm, sizeof(imm));
+ return result;
+ }
+
+ float GetImm20_32() const {
+ float result{};
+ u32 imm{static_cast<u32>(imm20_32)};
+ std::memcpy(&result, &imm, sizeof(imm));
+ return result;
+ }
+ } alu;
+
+ union {
+ BitField<48, 1, u64> negate_b;
+ BitField<49, 1, u64> negate_c;
+ } ffma;
+
+ union {
+ BitField<0, 3, u64> pred0;
+ BitField<3, 3, u64> pred3;
+ BitField<7, 1, u64> abs_a;
+ BitField<39, 3, u64> pred39;
+ BitField<42, 1, u64> neg_pred;
+ BitField<43, 1, u64> neg_a;
+ BitField<44, 1, u64> abs_b;
+ BitField<45, 2, PredOperation> op;
+ BitField<47, 1, u64> ftz;
+ BitField<48, 4, PredCondition> cond;
+ BitField<56, 1, u64> neg_b;
+ } fsetp;
+
+ BitField<61, 1, u64> is_b_imm;
+ BitField<60, 1, u64> is_b_gpr;
+ BitField<59, 1, u64> is_c_gpr;
+
+ Attribute attribute;
+ Uniform uniform;
+ Sampler sampler;
+
+ u64 value;
+};
+static_assert(sizeof(Instruction) == 0x8, "Incorrect structure size");
+static_assert(std::is_standard_layout<Instruction>::value,
+ "Structure does not have standard layout");
+
+class OpCode {
+public:
+ enum class Id {
+ KIL,
+ LD_A,
+ ST_A,
+ TEXQ, // Texture Query
+ TEXS, // Texture Fetch with scalar/non-vec4 source/destinations
+ TLDS, // Texture Load with scalar/non-vec4 source/destinations
+ EXIT,
+ IPA,
+ FFMA_IMM, // Fused Multiply and Add
+ FFMA_CR,
+ FFMA_RC,
+ FFMA_RR,
+ FADD_C,
+ FADD_R,
+ FADD_IMM,
+ FMUL_C,
+ FMUL_R,
+ FMUL_IMM,
+ FMUL32_IMM,
+ MUFU, // Multi-Function Operator
+ RRO, // Range Reduction Operator
+ F2F_C,
+ F2F_R,
+ F2F_IMM,
+ F2I_C,
+ F2I_R,
+ F2I_IMM,
+ I2F_C,
+ I2F_R,
+ I2F_IMM,
+ LOP32I,
+ MOV_C,
+ MOV_R,
+ MOV_IMM,
+ MOV32I,
+ SHR_C,
+ SHR_R,
+ SHR_IMM,
+ FSETP_C, // Set Predicate
+ FSETP_R,
+ FSETP_IMM,
+ ISETP_C,
+ ISETP_IMM,
+ ISETP_R,
+ };
+
+ enum class Type {
+ Trivial,
+ Arithmetic,
+ Ffma,
+ Flow,
+ Memory,
+ FloatPredicate,
+ IntegerPredicate,
+ Unknown,
+ };
+
+ class Matcher {
+ public:
+ Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type)
+ : name{name}, mask{mask}, expected{expected}, id{id}, type{type} {}
+
+ const char* GetName() const {
+ return name;
+ }
+
+ u16 GetMask() const {
+ return mask;
+ }
+
+ Id GetId() const {
+ return id;
+ }
+
+ Type GetType() const {
+ return type;
+ }
+
+ /**
+ * Tests to see if the given instruction is the instruction this matcher represents.
+ * @param instruction The instruction to test
+ * @returns true if the given instruction matches.
+ */
+ bool Matches(u16 instruction) const {
+ return (instruction & mask) == expected;
+ }
+
+ private:
+ const char* name;
+ u16 mask;
+ u16 expected;
+ Id id;
+ Type type;
+ };
+
+ static boost::optional<const Matcher&> Decode(Instruction instr) {
+ static const auto table{GetDecodeTable()};
+
+ const auto matches_instruction = [instr](const auto& matcher) {
+ return matcher.Matches(static_cast<u16>(instr.opcode));
+ };
+
+ auto iter = std::find_if(table.begin(), table.end(), matches_instruction);
+ return iter != table.end() ? boost::optional<const Matcher&>(*iter) : boost::none;
+ }
+
+private:
+ struct Detail {
+ private:
+ static constexpr size_t opcode_bitsize = 16;
+
+ /**
+ * Generates the mask and the expected value after masking from a given bitstring.
+ * A '0' in a bitstring indicates that a zero must be present at that bit position.
+ * A '1' in a bitstring indicates that a one must be present at that bit position.
+ */
+ static auto GetMaskAndExpect(const char* const bitstring) {
+ u16 mask = 0, expect = 0;
+ for (size_t i = 0; i < opcode_bitsize; i++) {
+ const size_t bit_position = opcode_bitsize - i - 1;
+ switch (bitstring[i]) {
+ case '0':
+ mask |= 1 << bit_position;
+ break;
+ case '1':
+ expect |= 1 << bit_position;
+ mask |= 1 << bit_position;
+ break;
+ default:
+ // Ignore
+ break;
+ }
+ }
+ return std::make_tuple(mask, expect);
+ }
+
+ public:
+ /// Creates a matcher that can match and parse instructions based on bitstring.
+ static auto GetMatcher(const char* const bitstring, OpCode::Id op, OpCode::Type type,
+ const char* const name) {
+ const auto mask_expect = GetMaskAndExpect(bitstring);
+ return Matcher(name, std::get<0>(mask_expect), std::get<1>(mask_expect), op, type);
+ }
+ };
+
+ static std::vector<Matcher> GetDecodeTable() {
+ std::vector<Matcher> table = {
+#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
+ INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
+ INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
+ INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"),
+ INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"),
+ INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"),
+ INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"),
+ INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"),
+ INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
+ INST("001100101-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"),
+ INST("010010011-------", Id::FFMA_CR, Type::Ffma, "FFMA_CR"),
+ INST("010100011-------", Id::FFMA_RC, Type::Ffma, "FFMA_RC"),
+ INST("010110011-------", Id::FFMA_RR, Type::Ffma, "FFMA_RR"),
+ INST("0100110001011---", Id::FADD_C, Type::Arithmetic, "FADD_C"),
+ INST("0101110001011---", Id::FADD_R, Type::Arithmetic, "FADD_R"),
+ INST("0011100-01011---", Id::FADD_IMM, Type::Arithmetic, "FADD_IMM"),
+ INST("0100110001101---", Id::FMUL_C, Type::Arithmetic, "FMUL_C"),
+ INST("0101110001101---", Id::FMUL_R, Type::Arithmetic, "FMUL_R"),
+ INST("0011100-01101---", Id::FMUL_IMM, Type::Arithmetic, "FMUL_IMM"),
+ INST("00011110--------", Id::FMUL32_IMM, Type::Arithmetic, "FMUL32_IMM"),
+ INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"),
+ INST("0101110010010---", Id::RRO, Type::Arithmetic, "RRO"),
+ INST("0100110010101---", Id::F2F_C, Type::Arithmetic, "F2F_C"),
+ INST("0101110010101---", Id::F2F_R, Type::Arithmetic, "F2F_R"),
+ INST("0011100-10101---", Id::F2F_IMM, Type::Arithmetic, "F2F_IMM"),
+ INST("0100110010110---", Id::F2I_C, Type::Arithmetic, "F2I_C"),
+ INST("0101110010110---", Id::F2I_R, Type::Arithmetic, "F2I_R"),
+ INST("0011100-10110---", Id::F2I_IMM, Type::Arithmetic, "F2I_IMM"),
+ INST("0100110010111---", Id::I2F_C, Type::Arithmetic, "I2F_C"),
+ INST("0101110010111---", Id::I2F_R, Type::Arithmetic, "I2F_R"),
+ INST("0011100-10111---", Id::I2F_IMM, Type::Arithmetic, "I2F_IMM"),
+ INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"),
+ INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
+ INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
+ INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"),
+ INST("000000010000----", Id::MOV32I, Type::Arithmetic, "MOV32I"),
+ INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"),
+ INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"),
+ INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"),
+ INST("010010111011----", Id::FSETP_C, Type::FloatPredicate, "FSETP_C"),
+ INST("010110111011----", Id::FSETP_R, Type::FloatPredicate, "FSETP_R"),
+ INST("0011011-1011----", Id::FSETP_IMM, Type::FloatPredicate, "FSETP_IMM"),
+ INST("010010110110----", Id::ISETP_C, Type::IntegerPredicate, "ISETP_C"),
+ INST("010110110110----", Id::ISETP_R, Type::IntegerPredicate, "ISETP_R"),
+ INST("0011011-0110----", Id::ISETP_IMM, Type::IntegerPredicate, "ISETP_IMM"),
+ };
+#undef INST
+ std::stable_sort(table.begin(), table.end(), [](const auto& a, const auto& b) {
+ // If a matcher has more bits in its mask it is more specific, so it
+ // should come first.
+ return std::bitset<16>(a.GetMask()).count() > std::bitset<16>(b.GetMask()).count();
+ });
+
+ return table;
+ }
+};
+
+} // namespace Shader
+} // namespace Tegra
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 71a8661b4..2888daedc 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -15,7 +15,10 @@ namespace Tegra {
enum class RenderTargetFormat : u32 {
NONE = 0x0,
+ RGBA16_FLOAT = 0xCA,
+ RGB10_A2_UNORM = 0xD1,
RGBA8_UNORM = 0xD5,
+ RGBA8_SRGB = 0xD6,
};
class DebugContext;
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 35d262189..36629dd11 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -19,7 +19,7 @@ public:
virtual void DrawArrays() = 0;
/// Notify rasterizer that the specified Maxwell register has been changed
- virtual void NotifyMaxwellRegisterChanged(u32 id) = 0;
+ virtual void NotifyMaxwellRegisterChanged(u32 method) = 0;
/// Notify rasterizer that all caches should be flushed to Switch memory
virtual void FlushAll() = 0;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index f217a265b..2d4a0d6db 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <memory>
#include <string>
#include <tuple>
@@ -13,7 +14,6 @@
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
-#include "common/vector_math.h"
#include "core/core.h"
#include "core/hle/kernel/process.h"
#include "core/settings.h"
@@ -34,33 +34,7 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
-enum class UniformBindings : GLuint { Common, VS, FS };
-
-static void SetShaderUniformBlockBinding(GLuint shader, const char* name, UniformBindings binding,
- size_t expected_size) {
- GLuint ub_index = glGetUniformBlockIndex(shader, name);
- if (ub_index != GL_INVALID_INDEX) {
- GLint ub_size = 0;
- glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size);
- ASSERT_MSG(ub_size == expected_size,
- "Uniform block size did not match! Got %d, expected %zu",
- static_cast<int>(ub_size), expected_size);
- glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding));
- }
-}
-
-static void SetShaderUniformBlockBindings(GLuint shader) {
- SetShaderUniformBlockBinding(shader, "shader_data", UniformBindings::Common,
- sizeof(RasterizerOpenGL::UniformData));
- SetShaderUniformBlockBinding(shader, "vs_config", UniformBindings::VS,
- sizeof(RasterizerOpenGL::VSUniformData));
- SetShaderUniformBlockBinding(shader, "fs_config", UniformBindings::FS,
- sizeof(RasterizerOpenGL::FSUniformData));
-}
-
RasterizerOpenGL::RasterizerOpenGL() {
- shader_dirty = true;
-
has_ARB_buffer_storage = false;
has_ARB_direct_state_access = false;
has_ARB_separate_shader_objects = false;
@@ -72,6 +46,14 @@ RasterizerOpenGL::RasterizerOpenGL() {
state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
}
+ // Create SSBOs
+ for (size_t stage = 0; stage < ssbos.size(); ++stage) {
+ for (size_t buffer = 0; buffer < ssbos[stage].size(); ++buffer) {
+ ssbos[stage][buffer].Create();
+ state.draw.const_buffers[stage][buffer].ssbo = ssbos[stage][buffer].handle;
+ }
+ }
+
GLint ext_num;
glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
for (GLint i = 0; i < ext_num; i++) {
@@ -88,6 +70,8 @@ RasterizerOpenGL::RasterizerOpenGL() {
}
}
+ ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
+
// Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
state.clip_distance[0] = true;
@@ -102,36 +86,30 @@ RasterizerOpenGL::RasterizerOpenGL() {
state.draw.uniform_buffer = uniform_buffer.handle;
state.Apply();
- glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), nullptr, GL_STATIC_DRAW);
- glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniform_buffer.handle);
-
- uniform_block_data.dirty = true;
-
// Create render framebuffer
framebuffer.Create();
- if (has_ARB_separate_shader_objects) {
- hw_vao.Create();
- hw_vao_enabled_attributes.fill(false);
+ hw_vao.Create();
+ hw_vao_enabled_attributes.fill(false);
- stream_buffer = OGLStreamBuffer::MakeBuffer(has_ARB_buffer_storage, GL_ARRAY_BUFFER);
- stream_buffer->Create(STREAM_BUFFER_SIZE, STREAM_BUFFER_SIZE / 2);
- state.draw.vertex_buffer = stream_buffer->GetHandle();
+ stream_buffer = OGLStreamBuffer::MakeBuffer(has_ARB_buffer_storage, GL_ARRAY_BUFFER);
+ stream_buffer->Create(STREAM_BUFFER_SIZE, STREAM_BUFFER_SIZE / 2);
+ state.draw.vertex_buffer = stream_buffer->GetHandle();
- pipeline.Create();
- state.draw.program_pipeline = pipeline.handle;
- state.draw.shader_program = 0;
- state.draw.vertex_array = hw_vao.handle;
- state.Apply();
+ shader_program_manager = std::make_unique<GLShader::ProgramManager>();
+ state.draw.shader_program = 0;
+ state.draw.vertex_array = hw_vao.handle;
+ state.Apply();
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer->GetHandle());
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer->GetHandle());
- vs_uniform_buffer.Create();
- glBindBuffer(GL_UNIFORM_BUFFER, vs_uniform_buffer.handle);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY);
- glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle);
- } else {
- UNREACHABLE();
+ for (unsigned index = 0; index < uniform_buffers.size(); ++index) {
+ auto& buffer = uniform_buffers[index];
+ buffer.Create();
+ glBindBuffer(GL_UNIFORM_BUFFER, buffer.handle);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(GLShader::MaxwellUniformData), nullptr,
+ GL_STREAM_COPY);
+ glBindBufferBase(GL_UNIFORM_BUFFER, index, buffer.handle);
}
accelerate_draw = AccelDraw::Disabled;
@@ -149,17 +127,6 @@ RasterizerOpenGL::~RasterizerOpenGL() {
}
}
-void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) {
- const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
-
- if (is_indexed) {
- UNREACHABLE();
- }
-
- // TODO(bunnei): Add support for 1+ vertex arrays
- vs_input_size = regs.vertex_buffer.count * regs.vertex_array[0].stride;
-}
-
void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
MICROPROFILE_SCOPE(OpenGL_VAO);
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
@@ -171,6 +138,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
// TODO(bunnei): Add support for 1+ vertex arrays
const auto& vertex_array{regs.vertex_array[0]};
+ const auto& vertex_array_limit{regs.vertex_array_limit[0]};
ASSERT_MSG(vertex_array.enable, "vertex array 0 is disabled?");
ASSERT_MSG(!vertex_array.divisor, "vertex array 0 divisor is unimplemented!");
for (unsigned index = 1; index < Maxwell::NumVertexArrays; ++index) {
@@ -183,6 +151,10 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
// to avoid OpenGL errors.
for (unsigned index = 0; index < 16; ++index) {
auto& attrib = regs.vertex_attrib_format[index];
+ NGLOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
+ index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),
+ attrib.offset.Value(), attrib.IsNormalized());
+
glVertexAttribPointer(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
attrib.IsNormalized() ? GL_TRUE : GL_FALSE, vertex_array.stride,
reinterpret_cast<GLvoid*>(buffer_offset + attrib.offset));
@@ -191,7 +163,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
}
// Copy vertex array data
- const u32 data_size{vertex_array.stride * regs.vertex_buffer.count};
+ const u64 data_size{vertex_array_limit.LimitAddress() - vertex_array.StartAddress() + 1};
const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(vertex_array.StartAddress())};
res_cache.FlushRegion(data_addr, data_size, nullptr);
Memory::ReadBlock(data_addr, array_ptr, data_size);
@@ -200,26 +172,89 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
buffer_offset += data_size;
}
-void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset) {
- MICROPROFILE_SCOPE(OpenGL_VS);
- LOG_CRITICAL(Render_OpenGL, "Emulated shaders are not supported! Using a passthrough shader.");
- glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, current_shader->shader.handle);
-}
+void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size_t ptr_pos) {
+ // Helper function for uploading uniform data
+ const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) {
+ if (has_ARB_direct_state_access) {
+ glCopyNamedBufferSubData(stream_buffer->GetHandle(), handle, offset, 0, size);
+ } else {
+ glBindBuffer(GL_COPY_WRITE_BUFFER, handle);
+ glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, offset, 0, size);
+ }
+ };
-void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) {
- MICROPROFILE_SCOPE(OpenGL_FS);
- UNREACHABLE();
-}
+ auto& gpu = Core::System().GetInstance().GPU().Maxwell3D();
+ ASSERT_MSG(!gpu.regs.shader_config[0].enable, "VertexA is unsupported!");
-bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
- if (!has_ARB_separate_shader_objects) {
- UNREACHABLE();
- return false;
+ // Next available bindpoint to use when uploading the const buffers to the GLSL shaders.
+ u32 current_constbuffer_bindpoint = 0;
+
+ for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) {
+ ptr_pos += sizeof(GLShader::MaxwellUniformData);
+
+ auto& shader_config = gpu.regs.shader_config[index];
+ const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)};
+
+ const auto& stage = index - 1; // Stage indices are 0 - 5
+
+ const bool is_enabled = gpu.IsShaderStageEnabled(static_cast<Maxwell::ShaderStage>(stage));
+
+ // Skip stages that are not enabled
+ if (!is_enabled) {
+ continue;
+ }
+
+ // Upload uniform data as one UBO per stage
+ const GLintptr ubo_offset = buffer_offset + static_cast<GLintptr>(ptr_pos);
+ copy_buffer(uniform_buffers[stage].handle, ubo_offset,
+ sizeof(GLShader::MaxwellUniformData));
+ GLShader::MaxwellUniformData* ub_ptr =
+ reinterpret_cast<GLShader::MaxwellUniformData*>(&buffer_ptr[ptr_pos]);
+ ub_ptr->SetFromRegs(gpu.state.shader_stages[stage]);
+
+ // Fetch program code from memory
+ GLShader::ProgramCode program_code;
+ const u64 gpu_address{gpu.regs.code_address.CodeAddress() + shader_config.offset};
+ const VAddr cpu_address{gpu.memory_manager.PhysicalToVirtualAddress(gpu_address)};
+ Memory::ReadBlock(cpu_address, program_code.data(), program_code.size() * sizeof(u64));
+ GLShader::ShaderSetup setup{std::move(program_code)};
+
+ GLShader::ShaderEntries shader_resources;
+
+ switch (program) {
+ case Maxwell::ShaderProgram::VertexB: {
+ GLShader::MaxwellVSConfig vs_config{setup};
+ shader_resources =
+ shader_program_manager->UseProgrammableVertexShader(vs_config, setup);
+ break;
+ }
+ case Maxwell::ShaderProgram::Fragment: {
+ GLShader::MaxwellFSConfig fs_config{setup};
+ shader_resources =
+ shader_program_manager->UseProgrammableFragmentShader(fs_config, setup);
+ break;
+ }
+ default:
+ LOG_CRITICAL(HW_GPU, "Unimplemented shader index=%d, enable=%d, offset=0x%08X", index,
+ shader_config.enable.Value(), shader_config.offset);
+ UNREACHABLE();
+ }
+
+ GLuint gl_stage_program = shader_program_manager->GetCurrentProgramStage(
+ static_cast<Maxwell::ShaderStage>(stage));
+
+ // Configure the const buffers for this shader stage.
+ current_constbuffer_bindpoint =
+ SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), gl_stage_program,
+ current_constbuffer_bindpoint, shader_resources.const_buffer_entries);
}
+ shader_program_manager->UseTrivialGeometryShader();
+}
+
+bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
DrawArrays();
-
return true;
}
@@ -255,18 +290,18 @@ void RasterizerOpenGL::DrawArrays() {
: (depth_surface == nullptr ? 1u : depth_surface->res_scale);
MathUtil::Rectangle<u32> draw_rect{
- static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.left) +
- viewport_rect.left * res_scale,
- surfaces_rect.left, surfaces_rect.right)), // Left
- static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.bottom) +
- viewport_rect.top * res_scale,
- surfaces_rect.bottom, surfaces_rect.top)), // Top
- static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.left) +
- viewport_rect.right * res_scale,
- surfaces_rect.left, surfaces_rect.right)), // Right
- static_cast<u32>(MathUtil::Clamp<s32>(static_cast<s32>(surfaces_rect.bottom) +
- viewport_rect.bottom * res_scale,
- surfaces_rect.bottom, surfaces_rect.top))}; // Bottom
+ static_cast<u32>(
+ std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left * res_scale,
+ surfaces_rect.left, surfaces_rect.right)), // Left
+ static_cast<u32>(
+ std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top * res_scale,
+ surfaces_rect.bottom, surfaces_rect.top)), // Top
+ static_cast<u32>(
+ std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.right * res_scale,
+ surfaces_rect.left, surfaces_rect.right)), // Right
+ static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) +
+ viewport_rect.bottom * res_scale,
+ surfaces_rect.bottom, surfaces_rect.top))}; // Bottom
// Bind the framebuffer surfaces
BindFramebufferSurfaces(color_surface, depth_surface, has_stencil);
@@ -280,18 +315,6 @@ void RasterizerOpenGL::DrawArrays() {
// Sync and bind the texture surfaces
BindTextures();
- // Sync and bind the shader
- if (shader_dirty) {
- SetShader();
- shader_dirty = false;
- }
-
- // Sync the uniform data
- if (uniform_block_data.dirty) {
- glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UniformData), &uniform_block_data.data);
- uniform_block_data.dirty = false;
- }
-
// Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable
// scissor test to prevent drawing outside of the framebuffer region
state.scissor.enabled = true;
@@ -303,15 +326,22 @@ void RasterizerOpenGL::DrawArrays() {
// Draw the vertex batch
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
- AnalyzeVertexArray(is_indexed);
+ const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()};
+ const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count};
+
+ // TODO(bunnei): Add support for 1+ vertex arrays
+ vs_input_size = vertex_num * regs.vertex_array[0].stride;
+
state.draw.vertex_buffer = stream_buffer->GetHandle();
state.Apply();
size_t buffer_size = static_cast<size_t>(vs_input_size);
if (is_indexed) {
- UNREACHABLE();
+ buffer_size = Common::AlignUp(buffer_size, 4) + index_buffer_size;
}
- buffer_size += sizeof(VSUniformData);
+
+ // Uniform space for the 5 shader stages
+ buffer_size += sizeof(GLShader::MaxwellUniformData) * Maxwell::MaxShaderStage;
size_t ptr_pos = 0;
u8* buffer_ptr;
@@ -322,36 +352,37 @@ void RasterizerOpenGL::DrawArrays() {
SetupVertexArray(buffer_ptr, buffer_offset);
ptr_pos += vs_input_size;
+ // If indexed mode, copy the index buffer
GLintptr index_buffer_offset = 0;
if (is_indexed) {
- UNREACHABLE();
- }
+ ptr_pos = Common::AlignUp(ptr_pos, 4);
- SetupVertexShader(reinterpret_cast<VSUniformData*>(&buffer_ptr[ptr_pos]),
- buffer_offset + static_cast<GLintptr>(ptr_pos));
- const GLintptr vs_ubo_offset = buffer_offset + static_cast<GLintptr>(ptr_pos);
- ptr_pos += sizeof(VSUniformData);
+ const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager;
+ const VAddr index_data_addr{
+ memory_manager->PhysicalToVirtualAddress(regs.index_array.StartAddress())};
+ Memory::ReadBlock(index_data_addr, &buffer_ptr[ptr_pos], index_buffer_size);
- stream_buffer->Unmap();
+ index_buffer_offset = buffer_offset + static_cast<GLintptr>(ptr_pos);
+ ptr_pos += index_buffer_size;
+ }
- const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) {
- if (has_ARB_direct_state_access) {
- glCopyNamedBufferSubData(stream_buffer->GetHandle(), handle, offset, 0, size);
- } else {
- glBindBuffer(GL_COPY_WRITE_BUFFER, handle);
- glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, offset, 0, size);
- }
- };
+ SetupShaders(buffer_ptr, buffer_offset, ptr_pos);
- copy_buffer(vs_uniform_buffer.handle, vs_ubo_offset, sizeof(VSUniformData));
+ stream_buffer->Unmap();
- glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, current_shader->shader.handle);
+ shader_program_manager->ApplyTo(state);
+ state.Apply();
+ const GLenum primitive_mode{MaxwellToGL::PrimitiveTopology(regs.draw.topology)};
if (is_indexed) {
- UNREACHABLE();
+ const GLint index_min{static_cast<GLint>(regs.index_array.first)};
+ const GLint index_max{static_cast<GLint>(regs.index_array.first + regs.index_array.count)};
+ glDrawRangeElementsBaseVertex(primitive_mode, index_min, index_max, regs.index_array.count,
+ MaxwellToGL::IndexFormat(regs.index_array.format),
+ reinterpret_cast<const void*>(index_buffer_offset),
+ -index_min);
} else {
- glDrawArrays(MaxwellToGL::PrimitiveTopology(regs.draw.topology), 0,
- regs.vertex_buffer.count);
+ glDrawArrays(primitive_mode, 0, regs.vertex_buffer.count);
}
// Disable scissor test
@@ -384,7 +415,7 @@ void RasterizerOpenGL::DrawArrays() {
void RasterizerOpenGL::BindTextures() {
using Regs = Tegra::Engines::Maxwell3D::Regs;
- auto maxwell3d = Core::System::GetInstance().GPU().Get3DEngine();
+ auto& maxwell3d = Core::System::GetInstance().GPU().Get3DEngine();
// Each Maxwell shader stage can have an arbitrary number of textures, but we're limited to a
// certain number in OpenGL. We try to only use the minimum amount of host textures by not
@@ -415,7 +446,32 @@ void RasterizerOpenGL::BindTextures() {
}
}
-void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {}
+void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {
+ const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
+ switch (method) {
+ case MAXWELL3D_REG_INDEX(blend.separate_alpha):
+ ASSERT_MSG(false, "unimplemented");
+ break;
+ case MAXWELL3D_REG_INDEX(blend.equation_rgb):
+ state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
+ break;
+ case MAXWELL3D_REG_INDEX(blend.factor_source_rgb):
+ state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
+ break;
+ case MAXWELL3D_REG_INDEX(blend.factor_dest_rgb):
+ state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
+ break;
+ case MAXWELL3D_REG_INDEX(blend.equation_a):
+ state.blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
+ break;
+ case MAXWELL3D_REG_INDEX(blend.factor_source_a):
+ state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
+ break;
+ case MAXWELL3D_REG_INDEX(blend.factor_dest_a):
+ state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a);
+ break;
+ }
+}
void RasterizerOpenGL::FlushAll() {
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
@@ -467,9 +523,12 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebu
src_params.width = std::min(framebuffer.width, pixel_stride);
src_params.height = framebuffer.height;
src_params.stride = pixel_stride;
- src_params.is_tiled = false;
+ src_params.is_tiled = true;
+ src_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight;
src_params.pixel_format =
SurfaceParams::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format);
+ src_params.component_type =
+ SurfaceParams::ComponentTypeFromGPUPixelFormat(framebuffer.pixel_format);
src_params.UpdateParams();
MathUtil::Rectangle<u32> src_rect;
@@ -531,70 +590,53 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
}
}
-void RasterizerOpenGL::SetShader() {
- // TODO(bunnei): The below sets up a static test shader for passing untransformed vertices to
- // OpenGL for rendering. This should be removed/replaced when we start emulating Maxwell
- // shaders.
-
- static constexpr char vertex_shader[] = R"(
-#version 150 core
-
-in vec2 vert_position;
-in vec2 vert_tex_coord;
-out vec2 frag_tex_coord;
-
-void main() {
- // Multiply input position by the rotscale part of the matrix and then manually translate by
- // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
- // to `vec3(vert_position.xy, 1.0)`
- gl_Position = vec4(mat2(mat3x2(0.0015625f, 0.0, 0.0, -0.0027778, -1.0, 1.0)) * vert_position + mat3x2(0.0015625f, 0.0, 0.0, -0.0027778, -1.0, 1.0)[2], 0.0, 1.0);
- frag_tex_coord = vert_tex_coord;
-}
-)";
-
- static constexpr char fragment_shader[] = R"(
-#version 150 core
-
-in vec2 frag_tex_coord;
-out vec4 color;
-
-uniform sampler2D tex[32];
+u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint program,
+ u32 current_bindpoint,
+ const std::vector<GLShader::ConstBufferEntry>& entries) {
+ auto& gpu = Core::System::GetInstance().GPU();
+ auto& maxwell3d = gpu.Get3DEngine();
-void main() {
- color = texture(tex[0], frag_tex_coord);
-}
-)";
+ ASSERT_MSG(maxwell3d.IsShaderStageEnabled(stage),
+ "Attempted to upload constbuffer of disabled shader stage");
- if (current_shader) {
- return;
+ // Reset all buffer draw state for this stage.
+ for (auto& buffer : state.draw.const_buffers[static_cast<size_t>(stage)]) {
+ buffer.bindpoint = 0;
+ buffer.enabled = false;
}
- LOG_CRITICAL(Render_OpenGL, "Emulated shaders are not supported! Using a passthrough shader.");
-
- current_shader = &test_shader;
- if (has_ARB_separate_shader_objects) {
- test_shader.shader.Create(vertex_shader, nullptr, fragment_shader, {}, true);
- glActiveShaderProgram(pipeline.handle, test_shader.shader.handle);
- } else {
- UNREACHABLE();
+ // Upload only the enabled buffers from the 16 constbuffers of each shader stage
+ auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)];
+
+ for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
+ const auto& used_buffer = entries[bindpoint];
+ const auto& buffer = shader_stage.const_buffers[used_buffer.GetIndex()];
+ 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");
+ buffer_draw_state.enabled = true;
+ buffer_draw_state.bindpoint = current_bindpoint + bindpoint;
+
+ VAddr addr = gpu.memory_manager->PhysicalToVirtualAddress(buffer.address);
+ std::vector<u8> data(used_buffer.GetSize() * sizeof(float));
+ Memory::ReadBlock(addr, data.data(), data.size());
+
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer_draw_state.ssbo);
+ glBufferData(GL_SHADER_STORAGE_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
+
+ // Now configure the bindpoint of the buffer inside the shader
+ std::string buffer_name = used_buffer.GetName();
+ GLuint index =
+ glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, buffer_name.c_str());
+ if (index != -1)
+ glShaderStorageBlockBinding(program, index, buffer_draw_state.bindpoint);
}
- state.draw.shader_program = test_shader.shader.handle;
state.Apply();
- for (u32 texture = 0; texture < texture_samplers.size(); ++texture) {
- // Set the texture samplers to correspond to different texture units
- std::string uniform_name = "tex[" + std::to_string(texture) + "]";
- GLint uniform_tex = glGetUniformLocation(test_shader.shader.handle, uniform_name.c_str());
- if (uniform_tex != -1) {
- glUniform1i(uniform_tex, TextureUnits::MaxwellTexture(texture).id);
- }
- }
-
- if (has_ARB_separate_shader_objects) {
- state.draw.shader_program = 0;
- state.Apply();
- }
+ return current_bindpoint + entries.size();
}
void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index d868bf421..03e02b52a 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -6,19 +6,16 @@
#include <array>
#include <cstddef>
-#include <cstring>
#include <memory>
-#include <unordered_map>
#include <vector>
#include <glad/glad.h>
-#include "common/bit_field.h"
#include "common/common_types.h"
-#include "common/hash.h"
-#include "common/vector_math.h"
+#include "video_core/engines/maxwell_3d.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_shader_gen.h"
+#include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_stream_buffer.h"
@@ -30,7 +27,7 @@ public:
~RasterizerOpenGL() override;
void DrawArrays() override;
- void NotifyMaxwellRegisterChanged(u32 id) override;
+ void NotifyMaxwellRegisterChanged(u32 method) override;
void FlushAll() override;
void FlushRegion(VAddr addr, u64 size) override;
void InvalidateRegion(VAddr addr, u64 size) override;
@@ -45,7 +42,7 @@ public:
/// OpenGL shader generated for a given Maxwell register state
struct MaxwellShader {
/// OpenGL shader resource
- OGLShader shader;
+ OGLProgram shader;
};
struct VertexShader {
@@ -56,34 +53,6 @@ public:
OGLShader shader;
};
- /// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
- // NOTE: Always keep a vec4 at the end. The GL spec is not clear wether the alignment at
- // the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not.
- // Not following that rule will cause problems on some AMD drivers.
- struct UniformData {};
-
- // static_assert(
- // sizeof(UniformData) == 0x460,
- // "The size of the UniformData structure has changed, update the structure in the shader");
- static_assert(sizeof(UniformData) < 16384,
- "UniformData structure must be less than 16kb as per the OpenGL spec");
-
- struct VSUniformData {};
- // static_assert(
- // sizeof(VSUniformData) == 1856,
- // "The size of the VSUniformData structure has changed, update the structure in the
- // shader");
- static_assert(sizeof(VSUniformData) < 16384,
- "VSUniformData structure must be less than 16kb as per the OpenGL spec");
-
- struct FSUniformData {};
- // static_assert(
- // sizeof(FSUniformData) == 1856,
- // "The size of the FSUniformData structure has changed, update the structure in the
- // shader");
- static_assert(sizeof(FSUniformData) < 16384,
- "FSUniformData structure must be less than 16kb as per the OpenGL spec");
-
private:
class SamplerInfo {
public:
@@ -113,6 +82,18 @@ private:
/// Binds the required textures to OpenGL before drawing a batch.
void BindTextures();
+ /*
+ * Configures the current constbuffers to use for the draw command.
+ * @param stage The shader stage to configure buffers for.
+ * @param program The OpenGL program object that contains the specified stage.
+ * @param current_bindpoint The offset at which to start counting new buffer bindpoints.
+ * @param entries Vector describing the buffers that are actually used in the guest shader.
+ * @returns The next available bindpoint for use in the next shader stage.
+ */
+ u32 SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, GLuint program,
+ u32 current_bindpoint,
+ const std::vector<GLShader::ConstBufferEntry>& entries);
+
/// Syncs the viewport to match the guest state
void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale);
@@ -122,9 +103,6 @@ private:
/// Syncs the clip coefficients to match the guest state
void SyncClipCoef();
- /// Sets the OpenGL shader in accordance with the current guest state
- void SetShader();
-
/// Syncs the cull mode to match the guest state
void SyncCullMode();
@@ -152,23 +130,16 @@ private:
RasterizerCacheOpenGL res_cache;
- /// Shader used for test renderering - to be removed once we have emulated shaders
- MaxwellShader test_shader{};
-
- const MaxwellShader* current_shader{};
- bool shader_dirty{};
-
- struct {
- UniformData data;
- bool dirty;
- } uniform_block_data = {};
-
- OGLPipeline pipeline;
+ std::unique_ptr<GLShader::ProgramManager> shader_program_manager;
OGLVertexArray sw_vao;
OGLVertexArray hw_vao;
std::array<bool, 16> hw_vao_enabled_attributes;
- std::array<SamplerInfo, 32> texture_samplers;
+ std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers;
+ std::array<std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers>,
+ Tegra::Engines::Maxwell3D::Regs::MaxShaderStage>
+ ssbos;
+
static constexpr size_t VERTEX_BUFFER_SIZE = 128 * 1024 * 1024;
std::unique_ptr<OGLStreamBuffer> vertex_buffer;
OGLBuffer uniform_buffer;
@@ -179,22 +150,11 @@ private:
GLsizeiptr vs_input_size;
- void AnalyzeVertexArray(bool is_indexed);
void SetupVertexArray(u8* array_ptr, GLintptr buffer_offset);
- OGLBuffer vs_uniform_buffer;
- std::unordered_map<GLShader::MaxwellVSConfig, VertexShader*> vs_shader_map;
- std::unordered_map<std::string, VertexShader> vs_shader_cache;
- OGLShader vs_default_shader;
-
- void SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset);
-
- OGLBuffer fs_uniform_buffer;
- std::unordered_map<GLShader::MaxwellFSConfig, FragmentShader*> fs_shader_map;
- std::unordered_map<std::string, FragmentShader> fs_shader_cache;
- OGLShader fs_default_shader;
+ std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> uniform_buffers;
- void SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset);
+ void SetupShaders(u8* buffer_ptr, GLintptr buffer_offset, size_t ptr_pos);
enum class AccelDraw { Disabled, Arrays, Indexed };
AccelDraw accelerate_draw;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 5cbafa2e7..ced2b8247 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -7,7 +7,6 @@
#include <cstring>
#include <iterator>
#include <memory>
-#include <unordered_set>
#include <utility>
#include <vector>
#include <boost/optional.hpp>
@@ -20,7 +19,6 @@
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
-#include "common/vector_math.h"
#include "core/core.h"
#include "core/frontend/emu_window.h"
#include "core/hle/kernel/process.h"
@@ -36,6 +34,7 @@
using SurfaceType = SurfaceParams::SurfaceType;
using PixelFormat = SurfaceParams::PixelFormat;
+using ComponentType = SurfaceParams::ComponentType;
struct FormatTuple {
GLint internal_format;
@@ -47,26 +46,24 @@ struct FormatTuple {
u32 compression_factor;
};
-static constexpr std::array<FormatTuple, 1> fb_format_tuples = {{
- {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8
+static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
+ {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false, 1}, // ABGR8
+ {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false, 1}, // B5G6R5
+ {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1
+ {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT23
+ {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT45
}};
-static constexpr std::array<FormatTuple, 2> tex_format_tuples = {{
- {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8
- {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1
-}};
-
-static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) {
+static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
const SurfaceType type = SurfaceParams::GetFormatType(pixel_format);
- if (type == SurfaceType::Color) {
- ASSERT(static_cast<size_t>(pixel_format) < fb_format_tuples.size());
- return fb_format_tuples[static_cast<unsigned int>(pixel_format)];
+ if (type == SurfaceType::ColorTexture) {
+ ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
+ // For now only UNORM components are supported
+ ASSERT(component_type == ComponentType::UNorm);
+ return tex_format_tuples[static_cast<unsigned int>(pixel_format)];
} else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) {
// TODO(Subv): Implement depth formats
ASSERT_MSG(false, "Unimplemented");
- } else if (type == SurfaceType::Texture) {
- ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
- return tex_format_tuples[static_cast<unsigned int>(pixel_format)];
}
UNREACHABLE();
@@ -85,56 +82,42 @@ static u16 GetResolutionScaleFactor() {
}
template <bool morton_to_gl, PixelFormat format>
-static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) {
- constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
- constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
- for (u32 y = 0; y < 8; ++y) {
- for (u32 x = 0; x < 8; ++x) {
- u8* tile_ptr = tile_buffer + VideoCore::MortonInterleave(x, y) * bytes_per_pixel;
- u8* gl_ptr = gl_buffer + ((7 - y) * stride + x) * gl_bytes_per_pixel;
- if (morton_to_gl) {
- std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel);
- } else {
- std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel);
- }
- }
- }
-}
-
-template <bool morton_to_gl, PixelFormat format>
-void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) {
+void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, VAddr base, VAddr start,
+ VAddr end) {
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
- // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the
- // configuration for this and perform more generic un/swizzle
- LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
- VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
- Memory::GetPointer(base), gl_buffer, morton_to_gl);
-}
-
-template <>
-void MortonCopy<true, PixelFormat::DXT1>(u32 stride, u32 height, u8* gl_buffer, VAddr base,
- VAddr start, VAddr end) {
- constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::DXT1) / 8;
- constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::DXT1);
-
- // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the
- // configuration for this and perform more generic un/swizzle
- LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
- auto data =
- Tegra::Texture::UnswizzleTexture(base, Tegra::Texture::TextureFormat::DXT1, stride, height);
- std::memcpy(gl_buffer, data.data(), data.size());
+ if (morton_to_gl) {
+ auto data = Tegra::Texture::UnswizzleTexture(
+ base, SurfaceParams::TextureFormatFromPixelFormat(format), stride, height,
+ block_height);
+ std::memcpy(gl_buffer, data.data(), data.size());
+ } else {
+ // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check
+ // the configuration for this and perform more generic un/swizzle
+ LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
+ VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
+ Memory::GetPointer(base), gl_buffer, morton_to_gl);
+ }
}
-static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> morton_to_gl_fns = {
- MortonCopy<true, PixelFormat::RGBA8>,
- MortonCopy<true, PixelFormat::DXT1>,
+static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
+ SurfaceParams::MaxPixelFormat>
+ morton_to_gl_fns = {
+ MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>,
+ MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
+ MortonCopy<true, PixelFormat::DXT45>,
};
-static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> gl_to_morton_fns = {
- MortonCopy<false, PixelFormat::RGBA8>,
- MortonCopy<false, PixelFormat::DXT1>,
+static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
+ SurfaceParams::MaxPixelFormat>
+ gl_to_morton_fns = {
+ MortonCopy<false, PixelFormat::ABGR8>,
+ MortonCopy<false, PixelFormat::B5G6R5>,
+ // TODO(Subv): Swizzling the DXT1/DXT23/DXT45 formats is not yet supported
+ nullptr,
+ nullptr,
+ nullptr,
};
// Allocate an uninitialized texture of appropriate size and format for the surface
@@ -183,7 +166,7 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec
u32 buffers = 0;
- if (type == SurfaceType::Color || type == SurfaceType::Texture) {
+ if (type == SurfaceType::ColorTexture) {
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex,
0);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
@@ -311,15 +294,18 @@ MathUtil::Rectangle<u32> SurfaceParams::GetScaledSubRect(const SurfaceParams& su
bool SurfaceParams::ExactMatch(const SurfaceParams& other_surface) const {
return std::tie(other_surface.addr, other_surface.width, other_surface.height,
- other_surface.stride, other_surface.pixel_format, other_surface.is_tiled) ==
- std::tie(addr, width, height, stride, pixel_format, is_tiled) &&
+ other_surface.stride, other_surface.block_height, other_surface.pixel_format,
+ other_surface.component_type,
+ other_surface.is_tiled) == std::tie(addr, width, height, stride, block_height,
+ pixel_format, component_type, is_tiled) &&
pixel_format != PixelFormat::Invalid;
}
bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const {
return sub_surface.addr >= addr && sub_surface.end <= end &&
sub_surface.pixel_format == pixel_format && pixel_format != PixelFormat::Invalid &&
- sub_surface.is_tiled == is_tiled &&
+ sub_surface.is_tiled == is_tiled && sub_surface.block_height == block_height &&
+ sub_surface.component_type == component_type &&
(sub_surface.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 &&
(sub_surface.stride == stride || sub_surface.height <= (is_tiled ? 8u : 1u)) &&
GetSubRect(sub_surface).left + sub_surface.width <= stride;
@@ -328,7 +314,8 @@ bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const {
bool SurfaceParams::CanExpand(const SurfaceParams& expanded_surface) const {
return pixel_format != PixelFormat::Invalid && pixel_format == expanded_surface.pixel_format &&
addr <= expanded_surface.end && expanded_surface.addr <= end &&
- is_tiled == expanded_surface.is_tiled && stride == expanded_surface.stride &&
+ is_tiled == expanded_surface.is_tiled && block_height == expanded_surface.block_height &&
+ component_type == expanded_surface.component_type && stride == expanded_surface.stride &&
(std::max(expanded_surface.addr, addr) - std::min(expanded_surface.addr, addr)) %
BytesInPixels(stride * (is_tiled ? 8 : 1)) ==
0;
@@ -339,6 +326,10 @@ bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const {
end < texcopy_params.end) {
return false;
}
+ if (texcopy_params.block_height != block_height ||
+ texcopy_params.component_type != component_type)
+ return false;
+
if (texcopy_params.width != texcopy_params.stride) {
const u32 tile_stride = static_cast<u32>(BytesInPixels(stride * (is_tiled ? 8 : 1)));
return (texcopy_params.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 &&
@@ -481,18 +472,13 @@ void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) {
const u64 start_offset = load_start - addr;
if (!is_tiled) {
- ASSERT(type == SurfaceType::Color);
const u32 bytes_per_pixel{GetFormatBpp() >> 3};
- // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check
- // the configuration for this and perform more generic un/swizzle
- LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
- VideoCore::MortonCopyPixels128(width, height, bytes_per_pixel, 4,
- texture_src_data + start_offset, &gl_buffer[start_offset],
- true);
+ std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset,
+ bytes_per_pixel * width * height);
} else {
- morton_to_gl_fns[static_cast<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr,
- load_start, load_end);
+ morton_to_gl_fns[static_cast<size_t>(pixel_format)](
+ stride, block_height, height, &gl_buffer[0], addr, load_start, load_end);
}
}
@@ -533,11 +519,10 @@ void CachedSurface::FlushGLBuffer(VAddr flush_start, VAddr flush_end) {
if (backup_bytes)
std::memcpy(&dst_buffer[coarse_start_offset], &backup_data[0], backup_bytes);
} else if (!is_tiled) {
- ASSERT(type == SurfaceType::Color);
std::memcpy(dst_buffer + start_offset, &gl_buffer[start_offset], flush_end - flush_start);
} else {
- gl_to_morton_fns[static_cast<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr,
- flush_start, flush_end);
+ gl_to_morton_fns[static_cast<size_t>(pixel_format)](
+ stride, block_height, height, &gl_buffer[0], addr, flush_start, flush_end);
}
}
@@ -556,7 +541,7 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint
GLint y0 = static_cast<GLint>(rect.bottom);
size_t buffer_offset = (y0 * stride + x0) * GetGLBytesPerPixel(pixel_format);
- const FormatTuple& tuple = GetFormatTuple(pixel_format);
+ const FormatTuple& tuple = GetFormatTuple(pixel_format, component_type);
GLuint target_tex = texture.handle;
// If not 1x scale, create 1x texture that we will blit from to replace texture subrect in
@@ -629,7 +614,7 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
OpenGLState prev_state = state;
SCOPE_EXIT({ prev_state.Apply(); });
- const FormatTuple& tuple = GetFormatTuple(pixel_format);
+ const FormatTuple& tuple = GetFormatTuple(pixel_format, component_type);
// Ensure no bad interactions with GL_PACK_ALIGNMENT
ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0);
@@ -662,7 +647,7 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
state.draw.read_framebuffer = read_fb_handle;
state.Apply();
- if (type == SurfaceType::Color || type == SurfaceType::Texture) {
+ if (type == SurfaceType::ColorTexture) {
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
texture.handle, 0);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
@@ -685,7 +670,8 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
}
-enum MatchFlags {
+enum class MatchFlags {
+ None = 0,
Invalid = 1, // Flag that can be applied to other match types, invalid matches require
// validation before they can be used
Exact = 1 << 1, // Surfaces perfectly match
@@ -699,6 +685,10 @@ constexpr MatchFlags operator|(MatchFlags lhs, MatchFlags rhs) {
return static_cast<MatchFlags>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
+constexpr MatchFlags operator&(MatchFlags lhs, MatchFlags rhs) {
+ return static_cast<MatchFlags>(static_cast<int>(lhs) & static_cast<int>(rhs));
+}
+
/// Get the best surface match (and its match type) for the given flags
template <MatchFlags find_flags>
Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params,
@@ -716,15 +706,15 @@ Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params
: (params.res_scale <= surface->res_scale);
// validity will be checked in GetCopyableInterval
bool is_valid =
- find_flags & MatchFlags::Copy
+ (find_flags & MatchFlags::Copy) != MatchFlags::None
? true
: surface->IsRegionValid(validate_interval.value_or(params.GetInterval()));
- if (!(find_flags & MatchFlags::Invalid) && !is_valid)
+ if ((find_flags & MatchFlags::Invalid) == MatchFlags::None && !is_valid)
continue;
auto IsMatch_Helper = [&](auto check_type, auto match_fn) {
- if (!(find_flags & check_type))
+ if ((find_flags & check_type) == MatchFlags::None)
return;
bool matched;
@@ -818,7 +808,7 @@ void main() {
color = texelFetch(tbo, tbo_offset).rabg;
}
)";
- d24s8_abgr_shader.Create(vs_source, nullptr, fs_source);
+ d24s8_abgr_shader.CreateFromSource(vs_source, nullptr, fs_source);
OpenGLState state = OpenGLState::GetCurState();
GLuint old_program = state.draw.shader_program;
@@ -1041,9 +1031,25 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu
params.height = config.tic.Height();
params.is_tiled = config.tic.IsTiled();
params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(config.tic.format);
+
+ // TODO(Subv): Different types per component are not supported.
+ ASSERT(config.tic.r_type.Value() == config.tic.g_type.Value() &&
+ config.tic.r_type.Value() == config.tic.b_type.Value() &&
+ config.tic.r_type.Value() == config.tic.a_type.Value());
+
+ params.component_type = SurfaceParams::ComponentTypeFromTexture(config.tic.r_type.Value());
+
+ if (config.tic.IsTiled()) {
+ params.block_height = config.tic.BlockHeight();
+ } else {
+ // Use the texture-provided stride value if the texture isn't tiled.
+ params.stride = params.PixelsInBytes(config.tic.Pitch());
+ }
+
params.UpdateParams();
- if (config.tic.Width() % 8 != 0 || config.tic.Height() % 8 != 0) {
+ if (config.tic.Width() % 8 != 0 || config.tic.Height() % 8 != 0 ||
+ params.stride != params.width) {
Surface src_surface;
MathUtil::Rectangle<u32> rect;
std::tie(src_surface, rect) = GetSurfaceSubRect(params, ScaleMatch::Ignore, true);
@@ -1083,10 +1089,10 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
}
MathUtil::Rectangle<u32> viewport_clamped{
- static_cast<u32>(MathUtil::Clamp(viewport.left, 0, static_cast<s32>(config.width))),
- static_cast<u32>(MathUtil::Clamp(viewport.top, 0, static_cast<s32>(config.height))),
- static_cast<u32>(MathUtil::Clamp(viewport.right, 0, static_cast<s32>(config.width))),
- static_cast<u32>(MathUtil::Clamp(viewport.bottom, 0, static_cast<s32>(config.height)))};
+ static_cast<u32>(std::clamp(viewport.left, 0, static_cast<s32>(config.width))),
+ static_cast<u32>(std::clamp(viewport.top, 0, static_cast<s32>(config.height))),
+ static_cast<u32>(std::clamp(viewport.right, 0, static_cast<s32>(config.width))),
+ static_cast<u32>(std::clamp(viewport.bottom, 0, static_cast<s32>(config.height)))};
// get color and depth surfaces
SurfaceParams color_params;
@@ -1094,10 +1100,13 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
color_params.res_scale = resolution_scale_factor;
color_params.width = config.width;
color_params.height = config.height;
+ // TODO(Subv): Can framebuffers use a different block height?
+ color_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight;
SurfaceParams depth_params = color_params;
color_params.addr = memory_manager->PhysicalToVirtualAddress(config.Address());
color_params.pixel_format = SurfaceParams::PixelFormatFromRenderTargetFormat(config.format);
+ color_params.component_type = SurfaceParams::ComponentTypeFromRenderTarget(config.format);
color_params.UpdateParams();
ASSERT_MSG(!using_depth_fb, "depth buffer is unimplemented");
@@ -1293,7 +1302,6 @@ void RasterizerCacheOpenGL::InvalidateRegion(VAddr addr, u64 size, const Surface
const SurfaceInterval invalid_interval(addr, addr + size);
if (region_owner != nullptr) {
- ASSERT(region_owner->type != SurfaceType::Texture);
ASSERT(addr >= region_owner->addr && addr + size <= region_owner->end);
// Surfaces can't have a gap
ASSERT(region_owner->width == region_owner->stride);
@@ -1355,7 +1363,8 @@ Surface RasterizerCacheOpenGL::CreateSurface(const SurfaceParams& params) {
surface->gl_buffer_size = 0;
surface->invalid_regions.insert(surface->GetInterval());
- AllocateSurfaceTexture(surface->texture.handle, GetFormatTuple(surface->pixel_format),
+ AllocateSurfaceTexture(surface->texture.handle,
+ GetFormatTuple(surface->pixel_format, surface->component_type),
surface->GetScaledWidth(), surface->GetScaledHeight());
return surface;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 06524fc59..6861efe16 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -52,27 +52,45 @@ enum class ScaleMatch {
struct SurfaceParams {
enum class PixelFormat {
- RGBA8 = 0,
- DXT1 = 1,
+ ABGR8 = 0,
+ B5G6R5 = 1,
+ DXT1 = 2,
+ DXT23 = 3,
+ DXT45 = 4,
+
+ Max,
Invalid = 255,
};
+ static constexpr size_t MaxPixelFormat = static_cast<size_t>(PixelFormat::Max);
+
+ enum class ComponentType {
+ Invalid = 0,
+ SNorm = 1,
+ UNorm = 2,
+ SInt = 3,
+ UInt = 4,
+ Float = 5,
+ };
+
enum class SurfaceType {
- Color = 0,
- Texture = 1,
- Depth = 2,
- DepthStencil = 3,
- Fill = 4,
- Invalid = 5
+ ColorTexture = 0,
+ Depth = 1,
+ DepthStencil = 2,
+ Fill = 3,
+ Invalid = 4,
};
static constexpr unsigned int GetFormatBpp(PixelFormat format) {
if (format == PixelFormat::Invalid)
return 0;
- constexpr std::array<unsigned int, 2> bpp_table = {
- 32, // RGBA8
- 64, // DXT1
+ constexpr std::array<unsigned int, MaxPixelFormat> bpp_table = {
+ 32, // ABGR8
+ 16, // B5G6R5
+ 64, // DXT1
+ 128, // DXT23
+ 128, // DXT45
};
ASSERT(static_cast<size_t>(format) < bpp_table.size());
@@ -85,8 +103,9 @@ struct SurfaceParams {
static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
switch (format) {
case Tegra::RenderTargetFormat::RGBA8_UNORM:
- return PixelFormat::RGBA8;
+ return PixelFormat::ABGR8;
default:
+ NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
}
}
@@ -94,8 +113,9 @@ struct SurfaceParams {
static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
switch (format) {
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
- return PixelFormat::RGBA8;
+ return PixelFormat::ABGR8;
default:
+ NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
}
}
@@ -104,10 +124,69 @@ struct SurfaceParams {
// TODO(Subv): Properly implement this
switch (format) {
case Tegra::Texture::TextureFormat::A8R8G8B8:
- return PixelFormat::RGBA8;
+ return PixelFormat::ABGR8;
+ case Tegra::Texture::TextureFormat::B5G6R5:
+ return PixelFormat::B5G6R5;
case Tegra::Texture::TextureFormat::DXT1:
return PixelFormat::DXT1;
+ case Tegra::Texture::TextureFormat::DXT23:
+ return PixelFormat::DXT23;
+ case Tegra::Texture::TextureFormat::DXT45:
+ return PixelFormat::DXT45;
+ default:
+ NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
+ UNREACHABLE();
+ }
+ }
+
+ static Tegra::Texture::TextureFormat TextureFormatFromPixelFormat(PixelFormat format) {
+ // TODO(Subv): Properly implement this
+ switch (format) {
+ case PixelFormat::ABGR8:
+ return Tegra::Texture::TextureFormat::A8R8G8B8;
+ case PixelFormat::B5G6R5:
+ return Tegra::Texture::TextureFormat::B5G6R5;
+ case PixelFormat::DXT1:
+ return Tegra::Texture::TextureFormat::DXT1;
+ case PixelFormat::DXT23:
+ return Tegra::Texture::TextureFormat::DXT23;
+ case PixelFormat::DXT45:
+ return Tegra::Texture::TextureFormat::DXT45;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
+ // TODO(Subv): Implement more component types
+ switch (type) {
+ case Tegra::Texture::ComponentType::UNORM:
+ return ComponentType::UNorm;
default:
+ NGLOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
+ UNREACHABLE();
+ }
+ }
+
+ static ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
+ // TODO(Subv): Implement more render targets
+ switch (format) {
+ case Tegra::RenderTargetFormat::RGBA8_UNORM:
+ case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
+ return ComponentType::UNorm;
+ default:
+ NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
+ UNREACHABLE();
+ }
+ }
+
+ static ComponentType ComponentTypeFromGPUPixelFormat(
+ Tegra::FramebufferConfig::PixelFormat format) {
+ switch (format) {
+ case Tegra::FramebufferConfig::PixelFormat::ABGR8:
+ return ComponentType::UNorm;
+ default:
+ NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
}
}
@@ -116,8 +195,7 @@ struct SurfaceParams {
SurfaceType a_type = GetFormatType(pixel_format_a);
SurfaceType b_type = GetFormatType(pixel_format_b);
- if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) &&
- (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) {
+ if (a_type == SurfaceType::ColorTexture && b_type == SurfaceType::ColorTexture) {
return true;
}
@@ -133,12 +211,8 @@ struct SurfaceParams {
}
static SurfaceType GetFormatType(PixelFormat pixel_format) {
- if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::RGBA8)) {
- return SurfaceType::Color;
- }
-
- if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::DXT1)) {
- return SurfaceType::Texture;
+ if (static_cast<size_t>(pixel_format) < MaxPixelFormat) {
+ return SurfaceType::ColorTexture;
}
// TODO(Subv): Implement the other formats
@@ -210,11 +284,13 @@ struct SurfaceParams {
u32 width = 0;
u32 height = 0;
u32 stride = 0;
+ u32 block_height = 0;
u16 res_scale = 1;
bool is_tiled = false;
PixelFormat pixel_format = PixelFormat::Invalid;
SurfaceType type = SurfaceType::Invalid;
+ ComponentType component_type = ComponentType::Invalid;
};
struct CachedSurface : SurfaceParams {
@@ -334,7 +410,7 @@ private:
OGLVertexArray attributeless_vao;
OGLBuffer d24s8_abgr_buffer;
GLsizeiptr d24s8_abgr_buffer_size;
- OGLShader d24s8_abgr_shader;
+ OGLProgram d24s8_abgr_shader;
GLint d24s8_abgr_tbo_size_u_id;
GLint d24s8_abgr_viewport_u_id;
};
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index 7da5e74d1..93f9172e7 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -13,14 +13,16 @@
class OGLTexture : private NonCopyable {
public:
OGLTexture() = default;
- OGLTexture(OGLTexture&& o) {
- std::swap(handle, o.handle);
- }
+
+ OGLTexture(OGLTexture&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
+
~OGLTexture() {
Release();
}
- OGLTexture& operator=(OGLTexture&& o) {
- std::swap(handle, o.handle);
+
+ OGLTexture& operator=(OGLTexture&& o) noexcept {
+ Release();
+ handle = std::exchange(o.handle, 0);
return *this;
}
@@ -46,14 +48,16 @@ public:
class OGLSampler : private NonCopyable {
public:
OGLSampler() = default;
- OGLSampler(OGLSampler&& o) {
- std::swap(handle, o.handle);
- }
+
+ OGLSampler(OGLSampler&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
+
~OGLSampler() {
Release();
}
- OGLSampler& operator=(OGLSampler&& o) {
- std::swap(handle, o.handle);
+
+ OGLSampler& operator=(OGLSampler&& o) noexcept {
+ Release();
+ handle = std::exchange(o.handle, 0);
return *this;
}
@@ -79,25 +83,71 @@ public:
class OGLShader : private NonCopyable {
public:
OGLShader() = default;
- OGLShader(OGLShader&& o) {
- std::swap(handle, o.handle);
- }
+
+ OGLShader(OGLShader&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
+
~OGLShader() {
Release();
}
- OGLShader& operator=(OGLShader&& o) {
- std::swap(handle, o.handle);
+
+ OGLShader& operator=(OGLShader&& o) noexcept {
+ Release();
+ handle = std::exchange(o.handle, 0);
return *this;
}
- /// Creates a new internal OpenGL resource and stores the handle
- void Create(const char* vert_shader, const char* geo_shader, const char* frag_shader,
- const std::vector<const char*>& feedback_vars = {},
- bool separable_program = false) {
+ void Create(const char* source, GLenum type) {
if (handle != 0)
return;
- handle = GLShader::LoadProgram(vert_shader, geo_shader, frag_shader, feedback_vars,
- separable_program);
+ if (source == nullptr)
+ return;
+ handle = GLShader::LoadShader(source, type);
+ }
+
+ void Release() {
+ if (handle == 0)
+ return;
+ glDeleteShader(handle);
+ handle = 0;
+ }
+
+ GLuint handle = 0;
+};
+
+class OGLProgram : private NonCopyable {
+public:
+ OGLProgram() = default;
+
+ OGLProgram(OGLProgram&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
+
+ ~OGLProgram() {
+ Release();
+ }
+
+ OGLProgram& operator=(OGLProgram&& o) noexcept {
+ Release();
+ handle = std::exchange(o.handle, 0);
+ return *this;
+ }
+
+ template <typename... T>
+ void Create(bool separable_program, T... shaders) {
+ if (handle != 0)
+ return;
+ handle = GLShader::LoadProgram(separable_program, shaders...);
+ }
+
+ /// Creates a new internal OpenGL resource and stores the handle
+ void CreateFromSource(const char* vert_shader, const char* geo_shader, const char* frag_shader,
+ bool separable_program = false) {
+ OGLShader vert, geo, frag;
+ if (vert_shader)
+ vert.Create(vert_shader, GL_VERTEX_SHADER);
+ if (geo_shader)
+ geo.Create(geo_shader, GL_GEOMETRY_SHADER);
+ if (frag_shader)
+ frag.Create(frag_shader, GL_FRAGMENT_SHADER);
+ Create(separable_program, vert.handle, geo.handle, frag.handle);
}
/// Deletes the internal OpenGL resource
@@ -115,13 +165,12 @@ public:
class OGLPipeline : private NonCopyable {
public:
OGLPipeline() = default;
- OGLPipeline(OGLPipeline&& o) {
- handle = std::exchange<GLuint>(o.handle, 0);
- }
+ OGLPipeline(OGLPipeline&& o) noexcept : handle{std::exchange<GLuint>(o.handle, 0)} {}
+
~OGLPipeline() {
Release();
}
- OGLPipeline& operator=(OGLPipeline&& o) {
+ OGLPipeline& operator=(OGLPipeline&& o) noexcept {
handle = std::exchange<GLuint>(o.handle, 0);
return *this;
}
@@ -148,14 +197,16 @@ public:
class OGLBuffer : private NonCopyable {
public:
OGLBuffer() = default;
- OGLBuffer(OGLBuffer&& o) {
- std::swap(handle, o.handle);
- }
+
+ OGLBuffer(OGLBuffer&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
+
~OGLBuffer() {
Release();
}
- OGLBuffer& operator=(OGLBuffer&& o) {
- std::swap(handle, o.handle);
+
+ OGLBuffer& operator=(OGLBuffer&& o) noexcept {
+ Release();
+ handle = std::exchange(o.handle, 0);
return *this;
}
@@ -182,12 +233,12 @@ class OGLSync : private NonCopyable {
public:
OGLSync() = default;
- OGLSync(OGLSync&& o) : handle(std::exchange(o.handle, nullptr)) {}
+ OGLSync(OGLSync&& o) noexcept : handle(std::exchange(o.handle, nullptr)) {}
~OGLSync() {
Release();
}
- OGLSync& operator=(OGLSync&& o) {
+ OGLSync& operator=(OGLSync&& o) noexcept {
Release();
handle = std::exchange(o.handle, nullptr);
return *this;
@@ -214,14 +265,16 @@ public:
class OGLVertexArray : private NonCopyable {
public:
OGLVertexArray() = default;
- OGLVertexArray(OGLVertexArray&& o) {
- std::swap(handle, o.handle);
- }
+
+ OGLVertexArray(OGLVertexArray&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
+
~OGLVertexArray() {
Release();
}
- OGLVertexArray& operator=(OGLVertexArray&& o) {
- std::swap(handle, o.handle);
+
+ OGLVertexArray& operator=(OGLVertexArray&& o) noexcept {
+ Release();
+ handle = std::exchange(o.handle, 0);
return *this;
}
@@ -247,14 +300,16 @@ public:
class OGLFramebuffer : private NonCopyable {
public:
OGLFramebuffer() = default;
- OGLFramebuffer(OGLFramebuffer&& o) {
- std::swap(handle, o.handle);
- }
+
+ OGLFramebuffer(OGLFramebuffer&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
+
~OGLFramebuffer() {
Release();
}
- OGLFramebuffer& operator=(OGLFramebuffer&& o) {
- std::swap(handle, o.handle);
+
+ OGLFramebuffer& operator=(OGLFramebuffer&& o) noexcept {
+ Release();
+ handle = std::exchange(o.handle, 0);
return *this;
}
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 564ea8f9e..086424395 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -2,57 +2,778 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <map>
+#include <set>
#include <string>
-#include <queue>
+#include <string_view>
#include "common/assert.h"
#include "common/common_types.h"
+#include "video_core/engines/shader_bytecode.h"
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
-namespace Maxwell3D {
-namespace Shader {
+namespace GLShader {
namespace Decompiler {
+using Tegra::Shader::Attribute;
+using Tegra::Shader::Instruction;
+using Tegra::Shader::OpCode;
+using Tegra::Shader::Register;
+using Tegra::Shader::Sampler;
+using Tegra::Shader::SubOp;
+using Tegra::Shader::Uniform;
+
constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH;
-class Impl {
+class DecompileFail : public std::runtime_error {
+public:
+ using std::runtime_error::runtime_error;
+};
+
+/// Describes the behaviour of code path of a given entry point and a return point.
+enum class ExitMethod {
+ Undetermined, ///< Internal value. Only occur when analyzing JMP loop.
+ AlwaysReturn, ///< All code paths reach the return point.
+ Conditional, ///< Code path reaches the return point or an END instruction conditionally.
+ AlwaysEnd, ///< All code paths reach a END instruction.
+};
+
+/// A subroutine is a range of code refereced by a CALL, IF or LOOP instruction.
+struct Subroutine {
+ /// Generates a name suitable for GLSL source code.
+ std::string GetName() const {
+ return "sub_" + std::to_string(begin) + "_" + std::to_string(end);
+ }
+
+ u32 begin; ///< Entry point of the subroutine.
+ u32 end; ///< Return point of the subroutine.
+ ExitMethod exit_method; ///< Exit method of the subroutine.
+ std::set<u32> labels; ///< Addresses refereced by JMP instructions.
+
+ bool operator<(const Subroutine& rhs) const {
+ return std::tie(begin, end) < std::tie(rhs.begin, rhs.end);
+ }
+};
+
+/// Analyzes shader code and produces a set of subroutines.
+class ControlFlowAnalyzer {
public:
- Impl(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code,
- const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data, u32 main_offset,
- const std::function<std::string(u32)>& inputreg_getter,
- const std::function<std::string(u32)>& outputreg_getter, bool sanitize_mul,
- const std::string& emit_cb, const std::string& setemit_cb)
- : program_code(program_code), swizzle_data(swizzle_data), main_offset(main_offset),
- inputreg_getter(inputreg_getter), outputreg_getter(outputreg_getter),
- sanitize_mul(sanitize_mul), emit_cb(emit_cb), setemit_cb(setemit_cb) {}
+ ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset)
+ : program_code(program_code) {
+
+ // Recursively finds all subroutines.
+ const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END);
+ if (program_main.exit_method != ExitMethod::AlwaysEnd)
+ throw DecompileFail("Program does not always end");
+ }
- std::string Decompile() {
- UNREACHABLE();
- return {};
+ std::set<Subroutine> GetSubroutines() {
+ return std::move(subroutines);
}
private:
- const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code;
- const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data;
- u32 main_offset;
- const std::function<std::string(u32)>& inputreg_getter;
- const std::function<std::string(u32)>& outputreg_getter;
- bool sanitize_mul;
- const std::string& emit_cb;
- const std::string& setemit_cb;
+ const ProgramCode& program_code;
+ std::set<Subroutine> subroutines;
+ std::map<std::pair<u32, u32>, ExitMethod> exit_method_map;
+
+ /// Adds and analyzes a new subroutine if it is not added yet.
+ const Subroutine& AddSubroutine(u32 begin, u32 end) {
+ auto iter = subroutines.find(Subroutine{begin, end});
+ if (iter != subroutines.end())
+ return *iter;
+
+ Subroutine subroutine{begin, end};
+ subroutine.exit_method = Scan(begin, end, subroutine.labels);
+ if (subroutine.exit_method == ExitMethod::Undetermined)
+ throw DecompileFail("Recursive function detected");
+ return *subroutines.insert(std::move(subroutine)).first;
+ }
+
+ /// Scans a range of code for labels and determines the exit method.
+ ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) {
+ auto [iter, inserted] =
+ exit_method_map.emplace(std::make_pair(begin, end), ExitMethod::Undetermined);
+ ExitMethod& exit_method = iter->second;
+ if (!inserted)
+ return exit_method;
+
+ for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
+ if (const auto opcode = OpCode::Decode({program_code[offset]})) {
+ switch (opcode->GetId()) {
+ case OpCode::Id::EXIT: {
+ return exit_method = ExitMethod::AlwaysEnd;
+ }
+ }
+ }
+ }
+ return exit_method = ExitMethod::AlwaysReturn;
+ }
+};
+
+class ShaderWriter {
+public:
+ void AddLine(std::string_view text) {
+ DEBUG_ASSERT(scope >= 0);
+ if (!text.empty()) {
+ AppendIndentation();
+ }
+ shader_source += text;
+ AddNewLine();
+ }
+
+ void AddLine(char character) {
+ DEBUG_ASSERT(scope >= 0);
+ AppendIndentation();
+ shader_source += character;
+ AddNewLine();
+ }
+
+ void AddNewLine() {
+ DEBUG_ASSERT(scope >= 0);
+ shader_source += '\n';
+ }
+
+ std::string GetResult() {
+ return std::move(shader_source);
+ }
+
+ int scope = 0;
+
+private:
+ void AppendIndentation() {
+ shader_source.append(static_cast<size_t>(scope) * 4, ' ');
+ }
+
+ std::string shader_source;
};
-std::string DecompileProgram(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code,
- const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data,
- u32 main_offset,
- const std::function<std::string(u32)>& inputreg_getter,
- const std::function<std::string(u32)>& outputreg_getter,
- bool sanitize_mul, const std::string& emit_cb,
- const std::string& setemit_cb) {
- Impl impl(program_code, swizzle_data, main_offset, inputreg_getter, outputreg_getter,
- sanitize_mul, emit_cb, setemit_cb);
- return impl.Decompile();
+class GLSLGenerator {
+public:
+ GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
+ u32 main_offset, Maxwell3D::Regs::ShaderStage stage)
+ : subroutines(subroutines), program_code(program_code), main_offset(main_offset),
+ stage(stage) {
+
+ Generate();
+ }
+
+ std::string GetShaderCode() {
+ return declarations.GetResult() + shader.GetResult();
+ }
+
+ /// Returns entries in the shader that are useful for external functions
+ ShaderEntries GetEntries() const {
+ return {GetConstBuffersDeclarations()};
+ }
+
+private:
+ /// Gets the Subroutine object corresponding to the specified address.
+ const Subroutine& GetSubroutine(u32 begin, u32 end) const {
+ auto iter = subroutines.find(Subroutine{begin, end});
+ ASSERT(iter != subroutines.end());
+ return *iter;
+ }
+
+ /// Generates code representing an input attribute register.
+ std::string GetInputAttribute(Attribute::Index attribute) {
+ switch (attribute) {
+ case Attribute::Index::Position:
+ return "position";
+ default:
+ const u32 index{static_cast<u32>(attribute) -
+ static_cast<u32>(Attribute::Index::Attribute_0)};
+ if (attribute >= Attribute::Index::Attribute_0) {
+ declr_input_attribute.insert(attribute);
+ return "input_attribute_" + std::to_string(index);
+ }
+
+ NGLOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index);
+ UNREACHABLE();
+ }
+ }
+
+ /// Generates code representing an output attribute register.
+ std::string GetOutputAttribute(Attribute::Index attribute) {
+ switch (attribute) {
+ case Attribute::Index::Position:
+ return "position";
+ default:
+ const u32 index{static_cast<u32>(attribute) -
+ static_cast<u32>(Attribute::Index::Attribute_0)};
+ if (attribute >= Attribute::Index::Attribute_0) {
+ declr_output_attribute.insert(attribute);
+ return "output_attribute_" + std::to_string(index);
+ }
+
+ NGLOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index);
+ UNREACHABLE();
+ }
+ }
+
+ /// Generates code representing a 19-bit immediate value
+ static std::string GetImmediate19(const Instruction& instr) {
+ return std::to_string(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());
+ }
+
+ /// Generates code representing a temporary (GPR) register.
+ std::string GetRegister(const Register& reg, unsigned elem = 0) {
+ if (reg == Register::ZeroIndex)
+ return "0";
+ if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
+ // GPRs 0-3 are output color for the fragment shader
+ return std::string{"color."} + "rgba"[(reg + elem) & 3];
+ }
+
+ return *declr_register.insert("register_" + std::to_string(reg + elem)).first;
+ }
+
+ /// Generates code representing a uniform (C buffer) register.
+ std::string GetUniform(const Uniform& reg) {
+ declr_const_buffers[reg.index].MarkAsUsed(static_cast<unsigned>(reg.index),
+ static_cast<unsigned>(reg.offset), stage);
+ return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']';
+ }
+
+ /// Generates code representing a texture sampler.
+ std::string GetSampler(const Sampler& sampler) const {
+ // TODO(Subv): Support more than just texture sampler 0
+ ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported");
+ const unsigned index{static_cast<unsigned>(sampler.index.Value()) -
+ static_cast<unsigned>(Sampler::Index::Sampler_0)};
+ return "tex[" + std::to_string(index) + "]";
+ }
+
+ /**
+ * Adds code that calls a subroutine.
+ * @param subroutine the subroutine to call.
+ */
+ void CallSubroutine(const Subroutine& subroutine) {
+ if (subroutine.exit_method == ExitMethod::AlwaysEnd) {
+ shader.AddLine(subroutine.GetName() + "();");
+ shader.AddLine("return true;");
+ } else if (subroutine.exit_method == ExitMethod::Conditional) {
+ shader.AddLine("if (" + subroutine.GetName() + "()) { return true; }");
+ } else {
+ shader.AddLine(subroutine.GetName() + "();");
+ }
+ }
+
+ /**
+ * Writes code that does an assignment operation.
+ * @param reg the destination register code.
+ * @param value the code representing the value to assign.
+ */
+ void SetDest(u64 elem, const std::string& reg, const std::string& value,
+ u64 dest_num_components, u64 value_num_components, bool is_abs = false) {
+ std::string swizzle = ".";
+ swizzle += "xyzw"[elem];
+
+ std::string dest = reg + (dest_num_components != 1 ? swizzle : "");
+ std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : "");
+ src = is_abs ? "abs(" + src + ")" : src;
+
+ shader.AddLine(dest + " = " + src + ";");
+ }
+
+ /*
+ * Writes code that assigns a predicate boolean variable.
+ * @param pred The id of the predicate to write to.
+ * @param value The expression value to assign to the predicate.
+ */
+ void SetPredicate(u64 pred, const std::string& value) {
+ using Tegra::Shader::Pred;
+ // Can't assign to the constant predicate.
+ ASSERT(pred != static_cast<u64>(Pred::UnusedIndex));
+
+ std::string variable = 'p' + std::to_string(pred);
+ shader.AddLine(variable + " = " + value + ';');
+ declr_predicates.insert(std::move(variable));
+ }
+
+ /*
+ * Returns the condition to use in the 'if' for a predicated instruction.
+ * @param instr Instruction to generate the if condition for.
+ * @returns string containing the predicate condition.
+ */
+ std::string GetPredicateCondition(Instruction instr) const {
+ using Tegra::Shader::Pred;
+ ASSERT(instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex));
+
+ std::string variable =
+ 'p' + std::to_string(static_cast<u64>(instr.pred.pred_index.Value()));
+
+ if (instr.negate_pred) {
+ return "!(" + variable + ')';
+ }
+
+ return variable;
+ }
+
+ /*
+ * Returns whether the instruction at the specified offset is a 'sched' instruction.
+ * Sched instructions always appear before a sequence of 3 instructions.
+ */
+ bool IsSchedInstruction(u32 offset) const {
+ // sched instructions appear once every 4 instructions.
+ static constexpr size_t SchedPeriod = 4;
+ u32 absolute_offset = offset - main_offset;
+
+ return (absolute_offset % SchedPeriod) == 0;
+ }
+
+ /**
+ * Compiles a single instruction from Tegra to GLSL.
+ * @param offset the offset of the Tegra shader instruction.
+ * @return the offset of the next instruction to execute. Usually it is the current offset
+ * + 1. If the current instruction always terminates the program, returns PROGRAM_END.
+ */
+ u32 CompileInstr(u32 offset) {
+ // Ignore sched instructions when generating code.
+ if (IsSchedInstruction(offset)) {
+ return offset + 1;
+ }
+
+ const Instruction instr = {program_code[offset]};
+ const auto opcode = OpCode::Decode(instr);
+
+ // Decoding failure
+ if (!opcode) {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {0:x}", instr.value);
+ UNREACHABLE();
+ }
+
+ shader.AddLine("// " + std::to_string(offset) + ": " + opcode->GetName());
+
+ using Tegra::Shader::Pred;
+ ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
+ "NeverExecute predicate not implemented");
+
+ if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
+ shader.AddLine("if (" + GetPredicateCondition(instr) + ')');
+ shader.AddLine('{');
+ ++shader.scope;
+ }
+
+ switch (opcode->GetType()) {
+ case OpCode::Type::Arithmetic: {
+ std::string dest = GetRegister(instr.gpr0);
+ std::string op_a = instr.alu.negate_a ? "-" : "";
+ op_a += GetRegister(instr.gpr8);
+ if (instr.alu.abs_a) {
+ op_a = "abs(" + op_a + ")";
+ }
+
+ std::string op_b = instr.alu.negate_b ? "-" : "";
+
+ if (instr.is_b_imm) {
+ op_b += GetImmediate19(instr);
+ } else {
+ if (instr.is_b_gpr) {
+ op_b += GetRegister(instr.gpr20);
+ } else {
+ op_b += GetUniform(instr.uniform);
+ }
+ }
+
+ if (instr.alu.abs_b) {
+ op_b = "abs(" + op_b + ")";
+ }
+
+ switch (opcode->GetId()) {
+ case OpCode::Id::FMUL_C:
+ case OpCode::Id::FMUL_R:
+ case OpCode::Id::FMUL_IMM: {
+ SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
+ break;
+ }
+ case OpCode::Id::FMUL32_IMM: {
+ // fmul32i doesn't have abs or neg bits.
+ SetDest(0, dest, GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1);
+ break;
+ }
+ case OpCode::Id::FADD_C:
+ case OpCode::Id::FADD_R:
+ case OpCode::Id::FADD_IMM: {
+ SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
+ break;
+ }
+ case OpCode::Id::MUFU: {
+ switch (instr.sub_op) {
+ case SubOp::Cos:
+ SetDest(0, dest, "cos(" + op_a + ")", 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Sin:
+ SetDest(0, dest, "sin(" + op_a + ")", 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Ex2:
+ SetDest(0, dest, "exp2(" + op_a + ")", 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Lg2:
+ SetDest(0, dest, "log2(" + op_a + ")", 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Rcp:
+ SetDest(0, dest, "1.0 / " + op_a, 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Rsq:
+ SetDest(0, dest, "inversesqrt(" + op_a + ")", 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Min:
+ SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d);
+ break;
+ default:
+ NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}",
+ static_cast<unsigned>(instr.sub_op.Value()));
+ UNREACHABLE();
+ }
+ break;
+ }
+ case OpCode::Id::RRO: {
+ NGLOG_DEBUG(HW_GPU, "Skipping RRO instruction");
+ break;
+ }
+ default: {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {}", opcode->GetName());
+ UNREACHABLE();
+ }
+ }
+ break;
+ }
+ case OpCode::Type::Ffma: {
+ std::string dest = GetRegister(instr.gpr0);
+ std::string op_a = GetRegister(instr.gpr8);
+ std::string op_b = instr.ffma.negate_b ? "-" : "";
+ std::string op_c = instr.ffma.negate_c ? "-" : "";
+
+ switch (opcode->GetId()) {
+ case OpCode::Id::FFMA_CR: {
+ op_b += GetUniform(instr.uniform);
+ op_c += GetRegister(instr.gpr39);
+ break;
+ }
+ case OpCode::Id::FFMA_RR: {
+ op_b += GetRegister(instr.gpr20);
+ op_c += GetRegister(instr.gpr39);
+ break;
+ }
+ case OpCode::Id::FFMA_RC: {
+ op_b += GetRegister(instr.gpr39);
+ op_c += GetUniform(instr.uniform);
+ break;
+ }
+ case OpCode::Id::FFMA_IMM: {
+ op_b += GetImmediate19(instr);
+ op_c += GetRegister(instr.gpr39);
+ break;
+ }
+ default: {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {}", opcode->GetName());
+ UNREACHABLE();
+ }
+ }
+
+ SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
+ break;
+ }
+ case OpCode::Type::Memory: {
+ std::string gpr0 = GetRegister(instr.gpr0);
+ const Attribute::Index attribute = instr.attribute.fmt20.index;
+
+ switch (opcode->GetId()) {
+ case OpCode::Id::LD_A: {
+ ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
+ SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4);
+ break;
+ }
+ case OpCode::Id::ST_A: {
+ ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
+ SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1);
+ break;
+ }
+ case OpCode::Id::TEXS: {
+ ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
+ const std::string op_a = GetRegister(instr.gpr8);
+ const std::string op_b = GetRegister(instr.gpr20);
+ const std::string sampler = GetSampler(instr.sampler);
+ const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
+ // Add an extra scope and declare the texture coords inside to prevent overwriting
+ // them in case they are used as outputs of the texs instruction.
+ shader.AddLine("{");
+ ++shader.scope;
+ shader.AddLine(coord);
+ const std::string texture = "texture(" + sampler + ", coords)";
+ for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
+ SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4);
+ }
+ --shader.scope;
+ shader.AddLine("}");
+ break;
+ }
+ default: {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName());
+ UNREACHABLE();
+ }
+ }
+ break;
+ }
+ case OpCode::Type::FloatPredicate: {
+ std::string op_a = instr.fsetp.neg_a ? "-" : "";
+ op_a += GetRegister(instr.gpr8);
+
+ if (instr.fsetp.abs_a) {
+ op_a = "abs(" + op_a + ')';
+ }
+
+ std::string op_b{};
+
+ if (instr.is_b_imm) {
+ if (instr.fsetp.neg_b) {
+ // Only the immediate version of fsetp has a neg_b bit.
+ op_b += '-';
+ }
+ op_b += '(' + GetImmediate19(instr) + ')';
+ } else {
+ if (instr.is_b_gpr) {
+ op_b += GetRegister(instr.gpr20);
+ } else {
+ op_b += GetUniform(instr.uniform);
+ }
+ }
+
+ if (instr.fsetp.abs_b) {
+ op_b = "abs(" + op_b + ')';
+ }
+
+ using Tegra::Shader::Pred;
+ ASSERT_MSG(instr.fsetp.pred0 == static_cast<u64>(Pred::UnusedIndex) &&
+ instr.fsetp.pred39 == static_cast<u64>(Pred::UnusedIndex),
+ "Compound predicates are not implemented");
+
+ // We can't use the constant predicate as destination.
+ ASSERT(instr.fsetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
+
+ using Tegra::Shader::PredCondition;
+ switch (instr.fsetp.cond) {
+ case PredCondition::LessThan:
+ SetPredicate(instr.fsetp.pred3, '(' + op_a + ") < (" + op_b + ')');
+ break;
+ case PredCondition::Equal:
+ SetPredicate(instr.fsetp.pred3, '(' + op_a + ") == (" + op_b + ')');
+ break;
+ default:
+ NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})",
+ static_cast<unsigned>(instr.fsetp.cond.Value()), op_a, op_b);
+ UNREACHABLE();
+ }
+ break;
+ }
+ default: {
+ switch (opcode->GetId()) {
+ case OpCode::Id::EXIT: {
+ ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex),
+ "Predicated exits not implemented");
+ shader.AddLine("return true;");
+ offset = PROGRAM_END - 1;
+ break;
+ }
+ case OpCode::Id::KIL: {
+ shader.AddLine("discard;");
+ break;
+ }
+ case OpCode::Id::IPA: {
+ const auto& attribute = instr.attribute.fmt28;
+ std::string dest = GetRegister(instr.gpr0);
+ SetDest(attribute.element, dest, GetInputAttribute(attribute.index), 1, 4);
+ break;
+ }
+ default: {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->GetName());
+ UNREACHABLE();
+ }
+ }
+
+ break;
+ }
+ }
+
+ // Close the predicate condition scope.
+ if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
+ --shader.scope;
+ shader.AddLine('}');
+ }
+
+ return offset + 1;
+ }
+
+ /**
+ * Compiles a range of instructions from Tegra to GLSL.
+ * @param begin the offset of the starting instruction.
+ * @param end the offset where the compilation should stop (exclusive).
+ * @return the offset of the next instruction to compile. PROGRAM_END if the program
+ * terminates.
+ */
+ u32 CompileRange(u32 begin, u32 end) {
+ u32 program_counter;
+ for (program_counter = begin; program_counter < (begin > end ? PROGRAM_END : end);) {
+ program_counter = CompileInstr(program_counter);
+ }
+ return program_counter;
+ }
+
+ void Generate() {
+ // Add declarations for all subroutines
+ for (const auto& subroutine : subroutines) {
+ shader.AddLine("bool " + subroutine.GetName() + "();");
+ }
+ shader.AddNewLine();
+
+ // Add the main entry point
+ shader.AddLine("bool exec_shader() {");
+ ++shader.scope;
+ CallSubroutine(GetSubroutine(main_offset, PROGRAM_END));
+ --shader.scope;
+ shader.AddLine("}\n");
+
+ // Add definitions for all subroutines
+ for (const auto& subroutine : subroutines) {
+ std::set<u32> labels = subroutine.labels;
+
+ shader.AddLine("bool " + subroutine.GetName() + "() {");
+ ++shader.scope;
+
+ if (labels.empty()) {
+ if (CompileRange(subroutine.begin, subroutine.end) != PROGRAM_END) {
+ shader.AddLine("return false;");
+ }
+ } else {
+ labels.insert(subroutine.begin);
+ shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
+ shader.AddLine("while (true) {");
+ ++shader.scope;
+
+ shader.AddLine("switch (jmp_to) {");
+
+ for (auto label : labels) {
+ shader.AddLine("case " + std::to_string(label) + "u: {");
+ ++shader.scope;
+
+ auto next_it = labels.lower_bound(label + 1);
+ u32 next_label = next_it == labels.end() ? subroutine.end : *next_it;
+
+ u32 compile_end = CompileRange(label, next_label);
+ if (compile_end > next_label && compile_end != PROGRAM_END) {
+ // This happens only when there is a label inside a IF/LOOP block
+ shader.AddLine("{ jmp_to = " + std::to_string(compile_end) + "u; break; }");
+ labels.emplace(compile_end);
+ }
+
+ --shader.scope;
+ shader.AddLine('}');
+ }
+
+ shader.AddLine("default: return false;");
+ shader.AddLine('}');
+
+ --shader.scope;
+ shader.AddLine('}');
+
+ shader.AddLine("return false;");
+ }
+
+ --shader.scope;
+ shader.AddLine("}\n");
+
+ DEBUG_ASSERT(shader.scope == 0);
+ }
+
+ GenerateDeclarations();
+ }
+
+ /// Returns a list of constant buffer declarations
+ std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const {
+ std::vector<ConstBufferEntry> result;
+ std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(),
+ std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); });
+ return result;
+ }
+
+ /// Add declarations for registers
+ void GenerateDeclarations() {
+ for (const auto& reg : declr_register) {
+ declarations.AddLine("float " + reg + " = 0.0;");
+ }
+ declarations.AddNewLine();
+
+ for (const auto& index : declr_input_attribute) {
+ // TODO(bunnei): Use proper number of elements for these
+ declarations.AddLine("layout(location = " +
+ std::to_string(static_cast<u32>(index) -
+ static_cast<u32>(Attribute::Index::Attribute_0)) +
+ ") in vec4 " + GetInputAttribute(index) + ";");
+ }
+ declarations.AddNewLine();
+
+ for (const auto& index : declr_output_attribute) {
+ // TODO(bunnei): Use proper number of elements for these
+ declarations.AddLine("layout(location = " +
+ std::to_string(static_cast<u32>(index) -
+ static_cast<u32>(Attribute::Index::Attribute_0)) +
+ ") out vec4 " + GetOutputAttribute(index) + ";");
+ }
+ declarations.AddNewLine();
+
+ unsigned const_buffer_layout = 0;
+ for (const auto& entry : GetConstBuffersDeclarations()) {
+ declarations.AddLine("layout(std430) buffer " + entry.GetName());
+ declarations.AddLine('{');
+ declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];");
+ declarations.AddLine("};");
+ declarations.AddNewLine();
+ ++const_buffer_layout;
+ }
+
+ declarations.AddNewLine();
+ for (const auto& pred : declr_predicates) {
+ declarations.AddLine("bool " + pred + " = false;");
+ }
+ declarations.AddNewLine();
+ }
+
+private:
+ const std::set<Subroutine>& subroutines;
+ const ProgramCode& program_code;
+ const u32 main_offset;
+ Maxwell3D::Regs::ShaderStage stage;
+
+ ShaderWriter shader;
+ ShaderWriter declarations;
+
+ // Declarations
+ std::set<std::string> declr_register;
+ std::set<std::string> declr_predicates;
+ std::set<Attribute::Index> declr_input_attribute;
+ std::set<Attribute::Index> declr_output_attribute;
+ std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;
+}; // namespace Decompiler
+
+std::string GetCommonDeclarations() {
+ return "bool exec_shader();";
+}
+
+boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
+ Maxwell3D::Regs::ShaderStage stage) {
+ try {
+ auto subroutines = ControlFlowAnalyzer(program_code, main_offset).GetSubroutines();
+ GLSLGenerator generator(subroutines, program_code, main_offset, stage);
+ return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
+ } catch (const DecompileFail& exception) {
+ NGLOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
+ }
+ return boost::none;
}
} // namespace Decompiler
-} // namespace Shader
-} // namespace Maxwell3D
+} // namespace GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h
index 02ebfcbe8..382c76b7a 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.h
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h
@@ -2,26 +2,25 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <array>
#include <functional>
#include <string>
+#include <boost/optional.hpp>
#include "common/common_types.h"
+#include "video_core/engines/maxwell_3d.h"
+#include "video_core/renderer_opengl/gl_shader_gen.h"
-namespace Maxwell3D {
-namespace Shader {
+namespace GLShader {
namespace Decompiler {
-constexpr size_t MAX_PROGRAM_CODE_LENGTH{0x100000};
-constexpr size_t MAX_SWIZZLE_DATA_LENGTH{0x100000};
+using Tegra::Engines::Maxwell3D;
+
+std::string GetCommonDeclarations();
-std::string DecompileProgram(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code,
- const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data,
- u32 main_offset,
- const std::function<std::string(u32)>& inputreg_getter,
- const std::function<std::string(u32)>& outputreg_getter,
- bool sanitize_mul, const std::string& emit_cb = "",
- const std::string& setemit_cb = "");
+boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
+ Maxwell3D::Regs::ShaderStage stage);
} // namespace Decompiler
-} // namespace Shader
-} // namespace Maxwell3D
+} // namespace GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 8f3c98800..254f6e2c3 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -3,18 +3,74 @@
// Refer to the license.txt file included.
#include "common/assert.h"
+#include "video_core/engines/maxwell_3d.h"
+#include "video_core/renderer_opengl/gl_shader_decompiler.h"
#include "video_core/renderer_opengl/gl_shader_gen.h"
namespace GLShader {
-std::string GenerateVertexShader(const MaxwellVSConfig& config) {
- UNREACHABLE();
- return {};
+using Tegra::Engines::Maxwell3D;
+
+static constexpr u32 PROGRAM_OFFSET{10};
+
+ProgramResult GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config) {
+ std::string out = "#version 430 core\n";
+ out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
+ out += Decompiler::GetCommonDeclarations();
+
+ ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET,
+ Maxwell3D::Regs::ShaderStage::Vertex)
+ .get_value_or({});
+ out += R"(
+
+out gl_PerVertex {
+ vec4 gl_Position;
+};
+
+out vec4 position;
+
+layout (std140) uniform vs_config {
+ vec4 viewport_flip;
+};
+
+void main() {
+ exec_shader();
+
+ // Viewport can be flipped, which is unsupported by glViewport
+ position.xy *= viewport_flip.xy;
+ gl_Position = position;
+}
+)";
+ out += program.first;
+ return {out, program.second};
+}
+
+ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config) {
+ std::string out = "#version 430 core\n";
+ out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
+ out += Decompiler::GetCommonDeclarations();
+
+ ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET,
+ Maxwell3D::Regs::ShaderStage::Fragment)
+ .get_value_or({});
+ out += R"(
+
+in vec4 position;
+out vec4 color;
+
+layout (std140) uniform fs_config {
+ vec4 viewport_flip;
+};
+
+uniform sampler2D tex[32];
+
+void main() {
+ exec_shader();
}
-std::string GenerateFragmentShader(const MaxwellFSConfig& config) {
- UNREACHABLE();
- return {};
+)";
+ out += program.first;
+ return {out, program.second};
}
} // namespace GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index 5101e7d30..458032b5c 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -4,46 +4,113 @@
#pragma once
-#include <cstring>
+#include <array>
#include <string>
#include <type_traits>
+#include <utility>
+#include <vector>
+#include "common/common_types.h"
#include "common/hash.h"
namespace GLShader {
-enum Attributes {
- ATTRIBUTE_POSITION,
- ATTRIBUTE_COLOR,
- ATTRIBUTE_TEXCOORD0,
- ATTRIBUTE_TEXCOORD1,
- ATTRIBUTE_TEXCOORD2,
- ATTRIBUTE_TEXCOORD0_W,
- ATTRIBUTE_NORMQUAT,
- ATTRIBUTE_VIEW,
+constexpr size_t MAX_PROGRAM_CODE_LENGTH{0x1000};
+
+using ProgramCode = std::array<u64, MAX_PROGRAM_CODE_LENGTH>;
+
+class ConstBufferEntry {
+ using Maxwell = Tegra::Engines::Maxwell3D::Regs;
+
+public:
+ void MarkAsUsed(unsigned index, unsigned offset, Maxwell::ShaderStage stage) {
+ is_used = true;
+ this->index = index;
+ this->stage = stage;
+ max_offset = std::max(max_offset, offset);
+ }
+
+ bool IsUsed() const {
+ return is_used;
+ }
+
+ unsigned GetIndex() const {
+ return index;
+ }
+
+ unsigned GetSize() const {
+ return max_offset + 1;
+ }
+
+ std::string GetName() const {
+ return BufferBaseNames[static_cast<size_t>(stage)] + std::to_string(index);
+ }
+
+private:
+ static constexpr std::array<const char*, Maxwell::MaxShaderStage> BufferBaseNames = {
+ "buffer_vs_c", "buffer_tessc_c", "buffer_tesse_c", "buffer_gs_c", "buffer_fs_c",
+ };
+
+ bool is_used{};
+ unsigned index{};
+ unsigned max_offset{};
+ Maxwell::ShaderStage stage;
};
-struct MaxwellShaderConfigCommon {
- explicit MaxwellShaderConfigCommon(){};
+struct ShaderEntries {
+ std::vector<ConstBufferEntry> const_buffer_entries;
};
-struct MaxwellVSConfig : MaxwellShaderConfigCommon {
- explicit MaxwellVSConfig() : MaxwellShaderConfigCommon() {}
+using ProgramResult = std::pair<std::string, ShaderEntries>;
- bool operator==(const MaxwellVSConfig& o) const {
- return std::memcmp(this, &o, sizeof(MaxwellVSConfig)) == 0;
- };
+struct ShaderSetup {
+ ShaderSetup(ProgramCode&& program_code) : program_code(std::move(program_code)) {}
+
+ ProgramCode program_code;
+ bool program_code_hash_dirty = true;
+
+ u64 GetProgramCodeHash() {
+ if (program_code_hash_dirty) {
+ program_code_hash = Common::ComputeHash64(&program_code, sizeof(program_code));
+ program_code_hash_dirty = false;
+ }
+ return program_code_hash;
+ }
+
+private:
+ u64 program_code_hash{};
};
-struct MaxwellFSConfig : MaxwellShaderConfigCommon {
- explicit MaxwellFSConfig() : MaxwellShaderConfigCommon() {}
+struct MaxwellShaderConfigCommon {
+ void Init(ShaderSetup& setup) {
+ program_hash = setup.GetProgramCodeHash();
+ }
- bool operator==(const MaxwellFSConfig& o) const {
- return std::memcmp(this, &o, sizeof(MaxwellFSConfig)) == 0;
- };
+ u64 program_hash;
};
-std::string GenerateVertexShader(const MaxwellVSConfig& config);
-std::string GenerateFragmentShader(const MaxwellFSConfig& config);
+struct MaxwellVSConfig : Common::HashableStruct<MaxwellShaderConfigCommon> {
+ explicit MaxwellVSConfig(ShaderSetup& setup) {
+ state.Init(setup);
+ }
+};
+
+struct MaxwellFSConfig : Common::HashableStruct<MaxwellShaderConfigCommon> {
+ explicit MaxwellFSConfig(ShaderSetup& setup) {
+ state.Init(setup);
+ }
+};
+
+/**
+ * Generates the GLSL vertex shader program source code for the given VS program
+ * @returns String of the shader source code
+ */
+ProgramResult GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config);
+
+/**
+ * Generates the GLSL fragment shader program source code for the given FS program
+ * @returns String of the shader source code
+ */
+ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config);
} // namespace GLShader
@@ -52,14 +119,14 @@ namespace std {
template <>
struct hash<GLShader::MaxwellVSConfig> {
size_t operator()(const GLShader::MaxwellVSConfig& k) const {
- return Common::ComputeHash64(&k, sizeof(GLShader::MaxwellVSConfig));
+ return k.Hash();
}
};
template <>
struct hash<GLShader::MaxwellFSConfig> {
size_t operator()(const GLShader::MaxwellFSConfig& k) const {
- return Common::ComputeHash64(&k, sizeof(GLShader::MaxwellFSConfig));
+ return k.Hash();
}
};
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
new file mode 100644
index 000000000..17b3925a0
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -0,0 +1,64 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/core.h"
+#include "core/hle/kernel/process.h"
+#include "video_core/engines/maxwell_3d.h"
+#include "video_core/renderer_opengl/gl_shader_manager.h"
+
+namespace GLShader {
+
+namespace Impl {
+void SetShaderUniformBlockBinding(GLuint shader, const char* name,
+ Maxwell3D::Regs::ShaderStage binding, size_t expected_size) {
+ GLuint ub_index = glGetUniformBlockIndex(shader, name);
+ if (ub_index != GL_INVALID_INDEX) {
+ GLint ub_size = 0;
+ glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size);
+ ASSERT_MSG(ub_size == expected_size,
+ "Uniform block size did not match! Got %d, expected %zu",
+ static_cast<int>(ub_size), expected_size);
+ glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding));
+ }
+}
+
+void SetShaderUniformBlockBindings(GLuint shader) {
+ SetShaderUniformBlockBinding(shader, "vs_config", Maxwell3D::Regs::ShaderStage::Vertex,
+ sizeof(MaxwellUniformData));
+ SetShaderUniformBlockBinding(shader, "gs_config", Maxwell3D::Regs::ShaderStage::Geometry,
+ sizeof(MaxwellUniformData));
+ SetShaderUniformBlockBinding(shader, "fs_config", Maxwell3D::Regs::ShaderStage::Fragment,
+ sizeof(MaxwellUniformData));
+}
+
+void SetShaderSamplerBindings(GLuint shader) {
+ OpenGLState cur_state = OpenGLState::GetCurState();
+ GLuint old_program = std::exchange(cur_state.draw.shader_program, shader);
+ cur_state.Apply();
+
+ // Set the texture samplers to correspond to different texture units
+ for (u32 texture = 0; texture < NumTextureSamplers; ++texture) {
+ // Set the texture samplers to correspond to different texture units
+ std::string uniform_name = "tex[" + std::to_string(texture) + "]";
+ GLint uniform_tex = glGetUniformLocation(shader, uniform_name.c_str());
+ if (uniform_tex != -1) {
+ glUniform1i(uniform_tex, TextureUnits::MaxwellTexture(texture).id);
+ }
+ }
+
+ cur_state.draw.shader_program = old_program;
+ cur_state.Apply();
+}
+
+} // namespace Impl
+
+void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage) {
+ const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
+
+ // TODO(bunnei): Support more than one viewport
+ viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0 : 1.0;
+ viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0 : 1.0;
+}
+
+} // namespace GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
new file mode 100644
index 000000000..e963b4b7e
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -0,0 +1,175 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <tuple>
+#include <unordered_map>
+#include <boost/functional/hash.hpp>
+#include <glad/glad.h>
+#include "video_core/renderer_opengl/gl_resource_manager.h"
+#include "video_core/renderer_opengl/gl_shader_gen.h"
+#include "video_core/renderer_opengl/maxwell_to_gl.h"
+
+namespace GLShader {
+
+/// Number of OpenGL texture samplers that can be used in the fragment shader
+static constexpr size_t NumTextureSamplers = 32;
+
+using Tegra::Engines::Maxwell3D;
+
+namespace Impl {
+void SetShaderUniformBlockBindings(GLuint shader);
+void SetShaderSamplerBindings(GLuint shader);
+} // namespace Impl
+
+/// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
+// NOTE: Always keep a vec4 at the end. The GL spec is not clear wether the alignment at
+// the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not.
+// Not following that rule will cause problems on some AMD drivers.
+struct MaxwellUniformData {
+ void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage);
+ alignas(16) GLvec4 viewport_flip;
+};
+static_assert(sizeof(MaxwellUniformData) == 16, "MaxwellUniformData structure size is incorrect");
+static_assert(sizeof(MaxwellUniformData) < 16384,
+ "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");
+
+class OGLShaderStage {
+public:
+ OGLShaderStage() = default;
+
+ void Create(const ProgramResult& program_result, GLenum type) {
+ OGLShader shader;
+ shader.Create(program_result.first.c_str(), type);
+ program.Create(true, shader.handle);
+ Impl::SetShaderUniformBlockBindings(program.handle);
+ Impl::SetShaderSamplerBindings(program.handle);
+ entries = program_result.second;
+ }
+ GLuint GetHandle() const {
+ return program.handle;
+ }
+
+ ShaderEntries GetEntries() const {
+ return entries;
+ }
+
+private:
+ OGLProgram program;
+ ShaderEntries entries;
+};
+
+// TODO(wwylele): beautify this doc
+// This is a shader cache designed for translating PICA shader to GLSL shader.
+// The double cache is needed because diffent KeyConfigType, which includes a hash of the code
+// region (including its leftover unused code) can generate the same GLSL code.
+template <typename KeyConfigType,
+ ProgramResult (*CodeGenerator)(const ShaderSetup&, const KeyConfigType&),
+ GLenum ShaderType>
+class ShaderCache {
+public:
+ ShaderCache() = default;
+
+ using Result = std::pair<GLuint, ShaderEntries>;
+
+ Result Get(const KeyConfigType& key, const ShaderSetup& setup) {
+ auto map_it = shader_map.find(key);
+ if (map_it == shader_map.end()) {
+ ProgramResult program = CodeGenerator(setup, key);
+
+ auto [iter, new_shader] = shader_cache.emplace(program.first, OGLShaderStage{});
+ OGLShaderStage& cached_shader = iter->second;
+ if (new_shader) {
+ cached_shader.Create(program, ShaderType);
+ }
+ shader_map[key] = &cached_shader;
+ return {cached_shader.GetHandle(), program.second};
+ } else {
+ return {map_it->second->GetHandle(), map_it->second->GetEntries()};
+ }
+ }
+
+private:
+ std::unordered_map<KeyConfigType, OGLShaderStage*> shader_map;
+ std::unordered_map<std::string, OGLShaderStage> shader_cache;
+};
+
+using VertexShaders = ShaderCache<MaxwellVSConfig, &GenerateVertexShader, GL_VERTEX_SHADER>;
+
+using FragmentShaders = ShaderCache<MaxwellFSConfig, &GenerateFragmentShader, GL_FRAGMENT_SHADER>;
+
+class ProgramManager {
+public:
+ ProgramManager() {
+ pipeline.Create();
+ }
+
+ ShaderEntries UseProgrammableVertexShader(const MaxwellVSConfig& config,
+ const ShaderSetup setup) {
+ ShaderEntries result;
+ std::tie(current.vs, result) = vertex_shaders.Get(config, setup);
+ return result;
+ }
+
+ ShaderEntries UseProgrammableFragmentShader(const MaxwellFSConfig& config,
+ const ShaderSetup setup) {
+ ShaderEntries result;
+ std::tie(current.fs, result) = fragment_shaders.Get(config, setup);
+ return result;
+ }
+
+ GLuint GetCurrentProgramStage(Maxwell3D::Regs::ShaderStage stage) {
+ switch (stage) {
+ case Maxwell3D::Regs::ShaderStage::Vertex:
+ return current.vs;
+ case Maxwell3D::Regs::ShaderStage::Fragment:
+ return current.fs;
+ }
+
+ UNREACHABLE();
+ }
+
+ void UseTrivialGeometryShader() {
+ current.gs = 0;
+ }
+
+ void ApplyTo(OpenGLState& state) {
+ // Workaround for AMD bug
+ glUseProgramStages(pipeline.handle,
+ GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | GL_FRAGMENT_SHADER_BIT,
+ 0);
+
+ glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, current.vs);
+ glUseProgramStages(pipeline.handle, GL_GEOMETRY_SHADER_BIT, current.gs);
+ glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, current.fs);
+ state.draw.shader_program = 0;
+ state.draw.program_pipeline = pipeline.handle;
+ }
+
+private:
+ struct ShaderTuple {
+ GLuint vs = 0, gs = 0, fs = 0;
+ bool operator==(const ShaderTuple& rhs) const {
+ return std::tie(vs, gs, fs) == std::tie(rhs.vs, rhs.gs, rhs.fs);
+ }
+ struct Hash {
+ std::size_t operator()(const ShaderTuple& tuple) const {
+ std::size_t hash = 0;
+ boost::hash_combine(hash, tuple.vs);
+ boost::hash_combine(hash, tuple.gs);
+ boost::hash_combine(hash, tuple.fs);
+ return hash;
+ }
+ };
+ };
+ ShaderTuple current;
+ VertexShaders vertex_shaders;
+ FragmentShaders fragment_shaders;
+
+ std::unordered_map<ShaderTuple, OGLProgram, ShaderTuple::Hash> program_cache;
+ OGLPipeline pipeline;
+};
+
+} // namespace GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index a6c6204d5..8568fface 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -10,156 +10,41 @@
namespace GLShader {
-GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader,
- const char* fragment_shader, const std::vector<const char*>& feedback_vars,
- bool separable_program) {
- // Create the shaders
- GLuint vertex_shader_id = vertex_shader ? glCreateShader(GL_VERTEX_SHADER) : 0;
- GLuint geometry_shader_id = geometry_shader ? glCreateShader(GL_GEOMETRY_SHADER) : 0;
- GLuint fragment_shader_id = fragment_shader ? glCreateShader(GL_FRAGMENT_SHADER) : 0;
+GLuint LoadShader(const char* source, GLenum type) {
+ const char* debug_type;
+ switch (type) {
+ case GL_VERTEX_SHADER:
+ debug_type = "vertex";
+ break;
+ case GL_GEOMETRY_SHADER:
+ debug_type = "geometry";
+ break;
+ case GL_FRAGMENT_SHADER:
+ debug_type = "fragment";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ GLuint shader_id = glCreateShader(type);
+ glShaderSource(shader_id, 1, &source, nullptr);
+ NGLOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type);
+ glCompileShader(shader_id);
GLint result = GL_FALSE;
- int info_log_length;
-
- if (vertex_shader) {
- // Compile Vertex Shader
- LOG_DEBUG(Render_OpenGL, "Compiling vertex shader...");
-
- glShaderSource(vertex_shader_id, 1, &vertex_shader, nullptr);
- glCompileShader(vertex_shader_id);
-
- // Check Vertex Shader
- glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result);
- glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
-
- if (info_log_length > 1) {
- std::vector<char> vertex_shader_error(info_log_length);
- glGetShaderInfoLog(vertex_shader_id, info_log_length, nullptr, &vertex_shader_error[0]);
- if (result == GL_TRUE) {
- LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]);
- } else {
- LOG_CRITICAL(Render_OpenGL, "Error compiling vertex shader:\n%s",
- &vertex_shader_error[0]);
- }
- }
- }
-
- if (geometry_shader) {
- // Compile Geometry Shader
- LOG_DEBUG(Render_OpenGL, "Compiling geometry shader...");
-
- glShaderSource(geometry_shader_id, 1, &geometry_shader, nullptr);
- glCompileShader(geometry_shader_id);
-
- // Check Geometry Shader
- glGetShaderiv(geometry_shader_id, GL_COMPILE_STATUS, &result);
- glGetShaderiv(geometry_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
-
- if (info_log_length > 1) {
- std::vector<char> geometry_shader_error(info_log_length);
- glGetShaderInfoLog(geometry_shader_id, info_log_length, nullptr,
- &geometry_shader_error[0]);
- if (result == GL_TRUE) {
- LOG_DEBUG(Render_OpenGL, "%s", &geometry_shader_error[0]);
- } else {
- LOG_CRITICAL(Render_OpenGL, "Error compiling geometry shader:\n%s",
- &geometry_shader_error[0]);
- }
- }
- }
-
- if (fragment_shader) {
- // Compile Fragment Shader
- LOG_DEBUG(Render_OpenGL, "Compiling fragment shader...");
-
- glShaderSource(fragment_shader_id, 1, &fragment_shader, nullptr);
- glCompileShader(fragment_shader_id);
-
- // Check Fragment Shader
- glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result);
- glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
-
- if (info_log_length > 1) {
- std::vector<char> fragment_shader_error(info_log_length);
- glGetShaderInfoLog(fragment_shader_id, info_log_length, nullptr,
- &fragment_shader_error[0]);
- if (result == GL_TRUE) {
- LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]);
- } else {
- LOG_CRITICAL(Render_OpenGL, "Error compiling fragment shader:\n%s",
- &fragment_shader_error[0]);
- }
- }
- }
-
- // Link the program
- LOG_DEBUG(Render_OpenGL, "Linking program...");
-
- GLuint program_id = glCreateProgram();
- if (vertex_shader) {
- glAttachShader(program_id, vertex_shader_id);
- }
- if (geometry_shader) {
- glAttachShader(program_id, geometry_shader_id);
- }
- if (fragment_shader) {
- glAttachShader(program_id, fragment_shader_id);
- }
-
- if (!feedback_vars.empty()) {
- auto varyings = feedback_vars;
- glTransformFeedbackVaryings(program_id, static_cast<GLsizei>(feedback_vars.size()),
- &varyings[0], GL_INTERLEAVED_ATTRIBS);
- }
-
- if (separable_program) {
- glProgramParameteri(program_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
- }
-
- glLinkProgram(program_id);
-
- // Check the program
- glGetProgramiv(program_id, GL_LINK_STATUS, &result);
- glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
+ GLint info_log_length;
+ glGetShaderiv(shader_id, GL_COMPILE_STATUS, &result);
+ glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
if (info_log_length > 1) {
- std::vector<char> program_error(info_log_length);
- glGetProgramInfoLog(program_id, info_log_length, nullptr, &program_error[0]);
+ std::string shader_error(info_log_length, ' ');
+ glGetShaderInfoLog(shader_id, info_log_length, nullptr, &shader_error[0]);
if (result == GL_TRUE) {
- LOG_DEBUG(Render_OpenGL, "%s", &program_error[0]);
+ NGLOG_DEBUG(Render_OpenGL, "{}", shader_error);
} else {
- LOG_CRITICAL(Render_OpenGL, "Error linking shader:\n%s", &program_error[0]);
+ NGLOG_ERROR(Render_OpenGL, "Error compiling {} shader:\n{}", debug_type, shader_error);
}
}
-
- // If the program linking failed at least one of the shaders was probably bad
- if (result == GL_FALSE) {
- if (vertex_shader) {
- LOG_CRITICAL(Render_OpenGL, "Vertex shader:\n%s", vertex_shader);
- }
- if (geometry_shader) {
- LOG_CRITICAL(Render_OpenGL, "Geometry shader:\n%s", geometry_shader);
- }
- if (fragment_shader) {
- LOG_CRITICAL(Render_OpenGL, "Fragment shader:\n%s", fragment_shader);
- }
- }
- ASSERT_MSG(result == GL_TRUE, "Shader not linked");
-
- if (vertex_shader) {
- glDetachShader(program_id, vertex_shader_id);
- glDeleteShader(vertex_shader_id);
- }
- if (geometry_shader) {
- glDetachShader(program_id, geometry_shader_id);
- glDeleteShader(geometry_shader_id);
- }
- if (fragment_shader) {
- glDetachShader(program_id, fragment_shader_id);
- glDeleteShader(fragment_shader_id);
- }
-
- return program_id;
+ return shader_id;
}
} // namespace GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h
index fc7b5e080..a1fa9e814 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.h
+++ b/src/video_core/renderer_opengl/gl_shader_util.h
@@ -6,18 +6,60 @@
#include <vector>
#include <glad/glad.h>
+#include "common/assert.h"
+#include "common/logging/log.h"
namespace GLShader {
/**
+ * Utility function to create and compile an OpenGL GLSL shader
+ * @param source String of the GLSL shader program
+ * @param type Type of the shader (GL_VERTEX_SHADER, GL_GEOMETRY_SHADER or GL_FRAGMENT_SHADER)
+ */
+GLuint LoadShader(const char* source, GLenum type);
+
+/**
* Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader)
- * @param vertex_shader String of the GLSL vertex shader program
- * @param geometry_shader String of the GLSL geometry shader program
- * @param fragment_shader String of the GLSL fragment shader program
- * @returns Handle of the newly created OpenGL shader object
+ * @param separable_program whether to create a separable program
+ * @param shaders ID of shaders to attach to the program
+ * @returns Handle of the newly created OpenGL program object
*/
-GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader,
- const char* fragment_shader, const std::vector<const char*>& feedback_vars = {},
- bool separable_program = false);
+template <typename... T>
+GLuint LoadProgram(bool separable_program, T... shaders) {
+ // Link the program
+ NGLOG_DEBUG(Render_OpenGL, "Linking program...");
+
+ GLuint program_id = glCreateProgram();
+
+ ((shaders == 0 ? (void)0 : glAttachShader(program_id, shaders)), ...);
+
+ if (separable_program) {
+ glProgramParameteri(program_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
+ }
+
+ glLinkProgram(program_id);
+
+ // Check the program
+ GLint result = GL_FALSE;
+ GLint info_log_length;
+ glGetProgramiv(program_id, GL_LINK_STATUS, &result);
+ glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
+
+ if (info_log_length > 1) {
+ std::string program_error(info_log_length, ' ');
+ glGetProgramInfoLog(program_id, info_log_length, nullptr, &program_error[0]);
+ if (result == GL_TRUE) {
+ NGLOG_DEBUG(Render_OpenGL, "{}", program_error);
+ } else {
+ NGLOG_ERROR(Render_OpenGL, "Error linking shader:\n{}", program_error);
+ }
+ }
+
+ ASSERT_MSG(result == GL_TRUE, "Shader not linked");
+
+ ((shaders == 0 ? (void)0 : glDetachShader(program_id, shaders)), ...);
+
+ return program_id;
+}
} // namespace GLShader
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 6da3a7781..f91dfe36a 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -2,8 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <iterator>
#include <glad/glad.h>
-#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "video_core/renderer_opengl/gl_state.h"
@@ -192,7 +192,7 @@ void OpenGLState::Apply() const {
}
// Textures
- for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) {
+ for (size_t i = 0; i < std::size(texture_units); ++i) {
if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) {
glActiveTexture(TextureUnits::MaxwellTexture(i).Enum());
glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d);
@@ -202,6 +202,20 @@ void OpenGLState::Apply() const {
}
}
+ // Constbuffers
+ for (u32 stage = 0; stage < draw.const_buffers.size(); ++stage) {
+ for (u32 buffer_id = 0; buffer_id < draw.const_buffers[stage].size(); ++buffer_id) {
+ auto& current = cur_state.draw.const_buffers[stage][buffer_id];
+ auto& new_state = draw.const_buffers[stage][buffer_id];
+ if (current.enabled != new_state.enabled || current.bindpoint != new_state.bindpoint ||
+ current.ssbo != new_state.ssbo) {
+ if (new_state.enabled) {
+ glBindBufferBase(GL_SHADER_STORAGE_BUFFER, new_state.bindpoint, new_state.ssbo);
+ }
+ }
+ }
+ }
+
// Lighting LUTs
if (lighting_lut.texture_buffer != cur_state.lighting_lut.texture_buffer) {
glActiveTexture(TextureUnits::LightingLUT.Enum());
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index b18af14bb..75c08e645 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -123,6 +123,12 @@ public:
GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING
GLuint shader_program; // GL_CURRENT_PROGRAM
GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
+ struct ConstBufferConfig {
+ bool enabled = false;
+ GLuint bindpoint;
+ GLuint ssbo;
+ };
+ std::array<std::array<ConstBufferConfig, 16>, 5> const_buffers{};
} draw;
struct {
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.h b/src/video_core/renderer_opengl/gl_stream_buffer.h
index 4bc2f52e0..e78dc5784 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.h
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <memory>
#include <glad/glad.h>
#include "common/common_types.h"
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 48ee80125..a49265b38 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -10,6 +10,14 @@
#include "common/logging/log.h"
#include "video_core/engines/maxwell_3d.h"
+using GLvec2 = std::array<GLfloat, 2>;
+using GLvec3 = std::array<GLfloat, 3>;
+using GLvec4 = std::array<GLfloat, 4>;
+
+using GLuvec2 = std::array<GLuint, 2>;
+using GLuvec3 = std::array<GLuint, 3>;
+using GLuvec4 = std::array<GLuint, 4>;
+
namespace MaxwellToGL {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
@@ -23,7 +31,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
return GL_UNSIGNED_BYTE;
}
- LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size=%s", attrib.SizeString().c_str());
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
UNREACHABLE();
return {};
}
@@ -32,17 +40,33 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
return GL_FLOAT;
}
- LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type=%s", attrib.TypeString().c_str());
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString());
+ UNREACHABLE();
+ return {};
+}
+
+inline GLenum IndexFormat(Maxwell::IndexFormat index_format) {
+ switch (index_format) {
+ case Maxwell::IndexFormat::UnsignedByte:
+ return GL_UNSIGNED_BYTE;
+ case Maxwell::IndexFormat::UnsignedShort:
+ return GL_UNSIGNED_SHORT;
+ case Maxwell::IndexFormat::UnsignedInt:
+ return GL_UNSIGNED_INT;
+ }
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented index_format={}", static_cast<u32>(index_format));
UNREACHABLE();
return {};
}
inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
switch (topology) {
+ case Maxwell::PrimitiveTopology::Triangles:
+ return GL_TRIANGLES;
case Maxwell::PrimitiveTopology::TriangleStrip:
return GL_TRIANGLE_STRIP;
}
- LOG_CRITICAL(Render_OpenGL, "Unimplemented primitive topology=%d", topology);
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology));
UNREACHABLE();
return {};
}
@@ -54,18 +78,90 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) {
case Tegra::Texture::TextureFilter::Nearest:
return GL_NEAREST;
}
- LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode=%u",
- static_cast<u32>(filter_mode));
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}",
+ static_cast<u32>(filter_mode));
UNREACHABLE();
return {};
}
inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
switch (wrap_mode) {
+ case Tegra::Texture::WrapMode::Wrap:
+ return GL_REPEAT;
case Tegra::Texture::WrapMode::ClampToEdge:
return GL_CLAMP_TO_EDGE;
+ case Tegra::Texture::WrapMode::ClampOGL:
+ // TODO(Subv): GL_CLAMP was removed as of OpenGL 3.1, to implement GL_CLAMP, we can use
+ // GL_CLAMP_TO_BORDER to get the border color of the texture, and then sample the edge to
+ // manually mix them. However the shader part of this is not yet implemented.
+ return GL_CLAMP_TO_BORDER;
+ }
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}",
+ static_cast<u32>(wrap_mode));
+ UNREACHABLE();
+ return {};
+}
+
+inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
+ switch (equation) {
+ case Maxwell::Blend::Equation::Add:
+ return GL_FUNC_ADD;
+ case Maxwell::Blend::Equation::Subtract:
+ return GL_FUNC_SUBTRACT;
+ case Maxwell::Blend::Equation::ReverseSubtract:
+ return GL_FUNC_REVERSE_SUBTRACT;
+ case Maxwell::Blend::Equation::Min:
+ return GL_MIN;
+ case Maxwell::Blend::Equation::Max:
+ return GL_MAX;
+ }
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation));
+ UNREACHABLE();
+ return {};
+}
+
+inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
+ switch (factor) {
+ case Maxwell::Blend::Factor::Zero:
+ return GL_ZERO;
+ case Maxwell::Blend::Factor::One:
+ return GL_ONE;
+ case Maxwell::Blend::Factor::SourceColor:
+ return GL_SRC_COLOR;
+ case Maxwell::Blend::Factor::OneMinusSourceColor:
+ return GL_ONE_MINUS_SRC_COLOR;
+ case Maxwell::Blend::Factor::SourceAlpha:
+ return GL_SRC_ALPHA;
+ case Maxwell::Blend::Factor::OneMinusSourceAlpha:
+ return GL_ONE_MINUS_SRC_ALPHA;
+ case Maxwell::Blend::Factor::DestAlpha:
+ return GL_DST_ALPHA;
+ case Maxwell::Blend::Factor::OneMinusDestAlpha:
+ return GL_ONE_MINUS_DST_ALPHA;
+ case Maxwell::Blend::Factor::DestColor:
+ return GL_DST_COLOR;
+ case Maxwell::Blend::Factor::OneMinusDestColor:
+ return GL_ONE_MINUS_DST_COLOR;
+ case Maxwell::Blend::Factor::SourceAlphaSaturate:
+ return GL_SRC_ALPHA_SATURATE;
+ case Maxwell::Blend::Factor::Source1Color:
+ return GL_SRC1_COLOR;
+ case Maxwell::Blend::Factor::OneMinusSource1Color:
+ return GL_ONE_MINUS_SRC1_COLOR;
+ case Maxwell::Blend::Factor::Source1Alpha:
+ return GL_SRC1_ALPHA;
+ case Maxwell::Blend::Factor::OneMinusSource1Alpha:
+ return GL_ONE_MINUS_SRC1_ALPHA;
+ case Maxwell::Blend::Factor::ConstantColor:
+ return GL_CONSTANT_COLOR;
+ case Maxwell::Blend::Factor::OneMinusConstantColor:
+ return GL_ONE_MINUS_CONSTANT_COLOR;
+ case Maxwell::Blend::Factor::ConstantAlpha:
+ return GL_CONSTANT_ALPHA;
+ case Maxwell::Blend::Factor::OneMinusConstantAlpha:
+ return GL_ONE_MINUS_CONSTANT_ALPHA;
}
- LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode=%u", static_cast<u32>(wrap_mode));
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));
UNREACHABLE();
return {};
}
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 78b50b227..ab0acb20a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -9,13 +9,10 @@
#include <memory>
#include <glad/glad.h>
#include "common/assert.h"
-#include "common/bit_field.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
-#include "core/hw/hw.h"
-#include "core/hw/lcd.h"
#include "core/memory.h"
#include "core/settings.h"
#include "core/tracer/recorder.h"
@@ -57,7 +54,7 @@ uniform sampler2D color_texture;
void main() {
// Swap RGBA -> ABGR so we don't have to do this on the CPU. This needs to change if we have to
// support more framebuffer pixel formats.
- color = texture(color_texture, frag_tex_coord).abgr;
+ color = texture(color_texture, frag_tex_coord);
}
)";
@@ -210,7 +207,7 @@ void RendererOpenGL::InitOpenGLObjects() {
0.0f);
// Link shaders and get variable locations
- shader.Create(vertex_shader, nullptr, fragment_shader);
+ shader.CreateFromSource(vertex_shader, nullptr, fragment_shader);
state.draw.shader_program = shader.handle;
state.Apply();
uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix");
@@ -311,10 +308,10 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
}
std::array<ScreenRectVertex, 4> vertices = {{
- ScreenRectVertex(x, y, texcoords.top, right),
- ScreenRectVertex(x + w, y, texcoords.bottom, right),
- ScreenRectVertex(x, y + h, texcoords.top, left),
- ScreenRectVertex(x + w, y + h, texcoords.bottom, left),
+ ScreenRectVertex(x, y, texcoords.top, left),
+ ScreenRectVertex(x + w, y, texcoords.bottom, left),
+ ScreenRectVertex(x, y + h, texcoords.top, right),
+ ScreenRectVertex(x + w, y + h, texcoords.bottom, right),
}};
state.texture_units[0].texture_2d = screen_info.display_texture;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index c52f40037..2cc6d9a00 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -72,7 +72,7 @@ private:
// OpenGL object IDs
OGLVertexArray vertex_array;
OGLBuffer vertex_buffer;
- OGLShader shader;
+ OGLProgram shader;
/// Display information for Switch screen
ScreenInfo screen_info;
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 2e87281eb..4df687786 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -48,31 +48,39 @@ u32 BytesPerPixel(TextureFormat format) {
case TextureFormat::DXT1:
// In this case a 'pixel' actually refers to a 4x4 tile.
return 8;
+ case TextureFormat::DXT23:
+ case TextureFormat::DXT45:
+ // In this case a 'pixel' actually refers to a 4x4 tile.
+ return 16;
case TextureFormat::A8R8G8B8:
return 4;
+ case TextureFormat::B5G6R5:
+ return 2;
default:
UNIMPLEMENTED_MSG("Format not implemented");
break;
}
}
-std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height) {
+std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
+ u32 block_height) {
u8* data = Memory::GetPointer(address);
u32 bytes_per_pixel = BytesPerPixel(format);
- static constexpr u32 DefaultBlockHeight = 16;
-
std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
switch (format) {
case TextureFormat::DXT1:
- // In the DXT1 format, each 4x4 tile is swizzled instead of just individual pixel values.
+ case TextureFormat::DXT23:
+ case TextureFormat::DXT45:
+ // In the DXT formats, each 4x4 tile is swizzled instead of just individual pixel values.
CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data,
- unswizzled_data.data(), true, DefaultBlockHeight);
+ unswizzled_data.data(), true, block_height);
break;
case TextureFormat::A8R8G8B8:
+ case TextureFormat::B5G6R5:
CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data,
- unswizzled_data.data(), true, DefaultBlockHeight);
+ unswizzled_data.data(), true, block_height);
break;
default:
UNIMPLEMENTED_MSG("Format not implemented");
@@ -89,7 +97,10 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
// TODO(Subv): Implement.
switch (format) {
case TextureFormat::DXT1:
+ case TextureFormat::DXT23:
+ case TextureFormat::DXT45:
case TextureFormat::A8R8G8B8:
+ case TextureFormat::B5G6R5:
// TODO(Subv): For the time being just forward the same data without any decoding.
rgba_data = texture_data;
break;
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index 0c21694ff..a700911cf 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -14,7 +14,8 @@ namespace Texture {
/**
* Unswizzles a swizzled texture without changing its format.
*/
-std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height);
+std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
+ u32 block_height = TICEntry::DefaultBlockHeight);
/**
* Decodes an unswizzled texture into a A8R8G8B8 texture.
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index c12ed6e1d..86e45aa88 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -4,6 +4,7 @@
#pragma once
+#include "common/assert.h"
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
@@ -13,8 +14,11 @@ namespace Tegra {
namespace Texture {
enum class TextureFormat : u32 {
- A8R8G8B8 = 8,
+ A8R8G8B8 = 0x8,
+ B5G6R5 = 0x15,
DXT1 = 0x24,
+ DXT23 = 0x25,
+ DXT45 = 0x26,
};
enum class TextureType : u32 {
@@ -55,6 +59,8 @@ union TextureHandle {
static_assert(sizeof(TextureHandle) == 4, "TextureHandle has wrong size");
struct TICEntry {
+ static constexpr u32 DefaultBlockHeight = 16;
+
union {
u32 raw;
BitField<0, 7, TextureFormat> format;
@@ -68,7 +74,12 @@ struct TICEntry {
BitField<0, 16, u32> address_high;
BitField<21, 3, TICHeaderVersion> header_version;
};
- INSERT_PADDING_BYTES(4);
+ union {
+ BitField<3, 3, u32> block_height;
+
+ // High 16 bits of the pitch value
+ BitField<0, 16, u32> pitch_high;
+ };
union {
BitField<0, 16, u32> width_minus_1;
BitField<23, 4, TextureType> texture_type;
@@ -80,6 +91,13 @@ struct TICEntry {
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low);
}
+ u32 Pitch() const {
+ ASSERT(header_version == TICHeaderVersion::Pitch ||
+ header_version == TICHeaderVersion::PitchColorKey);
+ // The pitch value is 21 bits, and is 32B aligned.
+ return pitch_high << 5;
+ }
+
u32 Width() const {
return width_minus_1 + 1;
}
@@ -88,6 +106,13 @@ struct TICEntry {
return height_minus_1 + 1;
}
+ u32 BlockHeight() const {
+ ASSERT(header_version == TICHeaderVersion::BlockLinear ||
+ header_version == TICHeaderVersion::BlockLinearColorKey);
+ // The block height is stored in log2 format.
+ return 1 << block_height;
+ }
+
bool IsTiled() const {
return header_version == TICHeaderVersion::BlockLinear ||
header_version == TICHeaderVersion::BlockLinearColorKey;
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index be0f7e22b..e0a14d48f 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -151,7 +151,7 @@ static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixe
const u32 coarse_y = y & ~127;
u32 morton_offset =
GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
- u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel;
+ u32 gl_pixel_index = (x + y * width) * gl_bytes_per_pixel;
data_ptrs[morton_to_gl] = morton_data + morton_offset;
data_ptrs[!morton_to_gl] = &gl_data[gl_pixel_index];
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 34e33170e..20796e92c 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -44,6 +44,15 @@
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
#endif
+#ifdef _WIN32
+extern "C" {
+// tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable
+// graphics
+__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
+__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
+}
+#endif
+
/**
* "Callouts" are one-time instructional messages shown to the user. In the config settings, there
* is a bitfield "callout_flags" options, used to track if a message has already been shown to the
@@ -776,9 +785,11 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
return;
}
- UISettings::values.geometry = saveGeometry();
+ if (ui.action_Fullscreen->isChecked()) {
+ UISettings::values.geometry = saveGeometry();
+ UISettings::values.renderwindow_geometry = render_window->saveGeometry();
+ }
UISettings::values.state = saveState();
- UISettings::values.renderwindow_geometry = render_window->saveGeometry();
#if MICROPROFILE_ENABLED
UISettings::values.microprofile_geometry = microProfileDialog->saveGeometry();
UISettings::values.microprofile_visible = microProfileDialog->isVisible();
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 0a4644500..39603e881 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -37,6 +37,15 @@
#include "yuzu_cmd/config.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
+#ifdef _WIN32
+extern "C" {
+// tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable
+// graphics
+__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
+__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
+}
+#endif
+
static void PrintHelp(const char* argv0) {
std::cout << "Usage: " << argv0
<< " [options] <filename>\n"