summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--README.md2
m---------externals/dynarmic0
-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
199 files changed, 3980 insertions, 1711 deletions
diff --git a/README.md b/README.md
index 4b0b151a4..1d5ee58cc 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ yuzu is an experimental open-source emulator for the Nintendo Switch from the cr
It is written in C++ with portability in mind, with builds actively maintained for Windows, Linux and macOS. The emulator is currently only useful for homebrew development and research purposes.
-yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu does not run any commercial Switch games. yuzu can boot some games, to varying degrees of success, but does not implement any of the necessary GPU features to render 3D graphics.
+yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu cannot play any commercial games without major problems. yuzu can boot some games, to varying degrees of success, but does not implement any of the necessary GPU features to render 3D graphics.
yuzu is licensed under the GPLv2 (or any later version). Refer to the license.txt file included.
diff --git a/externals/dynarmic b/externals/dynarmic
-Subproject 9cc12d80b984be5a383af8f471e65b52cc1895f
+Subproject 51912ca6ab2626757d9e16c6b72562a03f3942a
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"