summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/audio_core/CMakeLists.txt8
-rw-r--r--src/audio_core/algorithm/filter.cpp79
-rw-r--r--src/audio_core/algorithm/filter.h62
-rw-r--r--src/audio_core/algorithm/interpolate.cpp71
-rw-r--r--src/audio_core/algorithm/interpolate.h43
-rw-r--r--src/audio_core/audio_renderer.cpp5
-rw-r--r--src/audio_core/audio_renderer.h2
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/break_points.cpp90
-rw-r--r--src/common/break_points.h49
-rw-r--r--src/common/logging/backend.cpp5
-rw-r--r--src/common/misc.cpp2
-rw-r--r--src/common/x64/xbyak_abi.h20
-rw-r--r--src/common/x64/xbyak_util.h6
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp4
-rw-r--r--src/core/frontend/emu_window.h6
-rw-r--r--src/core/hle/kernel/server_session.cpp2
-rw-r--r--src/core/hle/kernel/server_session.h7
-rw-r--r--src/core/hle/kernel/svc.cpp7
-rw-r--r--src/core/hle/service/audio/audout_u.cpp2
-rw-r--r--src/core/hle/service/mm/mm_u.cpp83
-rw-r--r--src/core/hle/service/mm/mm_u.h15
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp34
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h36
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp34
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h36
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp4
-rw-r--r--src/core/hle/service/sm/controller.cpp4
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp1
-rw-r--r--src/core/loader/elf.cpp1
-rw-r--r--src/core/loader/loader.cpp6
-rw-r--r--src/core/loader/loader.h7
-rw-r--r--src/core/loader/nro.cpp1
-rw-r--r--src/core/loader/nso.cpp1
-rw-r--r--src/video_core/gpu.cpp3
-rw-r--r--src/video_core/gpu.h3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp6
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp55
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h217
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp101
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h26
43 files changed, 793 insertions, 359 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ff8385e3a..59c610732 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -66,10 +66,12 @@ if (NOT ENABLE_GENERIC)
66 detect_architecture("_M_AMD64" x86_64) 66 detect_architecture("_M_AMD64" x86_64)
67 detect_architecture("_M_IX86" x86) 67 detect_architecture("_M_IX86" x86)
68 detect_architecture("_M_ARM" ARM) 68 detect_architecture("_M_ARM" ARM)
69 detect_architecture("_M_ARM64" ARM64)
69 else() 70 else()
70 detect_architecture("__x86_64__" x86_64) 71 detect_architecture("__x86_64__" x86_64)
71 detect_architecture("__i386__" x86) 72 detect_architecture("__i386__" x86)
72 detect_architecture("__arm__" ARM) 73 detect_architecture("__arm__" ARM)
74 detect_architecture("__aarch64__" ARM64)
73 endif() 75 endif()
74endif() 76endif()
75 77
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index ec71524a3..82e4850f7 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -1,4 +1,8 @@
1add_library(audio_core STATIC 1add_library(audio_core STATIC
2 algorithm/filter.cpp
3 algorithm/filter.h
4 algorithm/interpolate.cpp
5 algorithm/interpolate.h
2 audio_out.cpp 6 audio_out.cpp
3 audio_out.h 7 audio_out.h
4 audio_renderer.cpp 8 audio_renderer.cpp
@@ -7,12 +11,12 @@ add_library(audio_core STATIC
7 codec.cpp 11 codec.cpp
8 codec.h 12 codec.h
9 null_sink.h 13 null_sink.h
10 stream.cpp
11 stream.h
12 sink.h 14 sink.h
13 sink_details.cpp 15 sink_details.cpp
14 sink_details.h 16 sink_details.h
15 sink_stream.h 17 sink_stream.h
18 stream.cpp
19 stream.h
16 20
17 $<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h> 21 $<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h>
18) 22)
diff --git a/src/audio_core/algorithm/filter.cpp b/src/audio_core/algorithm/filter.cpp
new file mode 100644
index 000000000..403b8503f
--- /dev/null
+++ b/src/audio_core/algorithm/filter.cpp
@@ -0,0 +1,79 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#define _USE_MATH_DEFINES
6
7#include <algorithm>
8#include <array>
9#include <cmath>
10#include <vector>
11#include "audio_core/algorithm/filter.h"
12#include "common/common_types.h"
13
14namespace AudioCore {
15
16Filter Filter::LowPass(double cutoff, double Q) {
17 const double w0 = 2.0 * M_PI * cutoff;
18 const double sin_w0 = std::sin(w0);
19 const double cos_w0 = std::cos(w0);
20 const double alpha = sin_w0 / (2 * Q);
21
22 const double a0 = 1 + alpha;
23 const double a1 = -2.0 * cos_w0;
24 const double a2 = 1 - alpha;
25 const double b0 = 0.5 * (1 - cos_w0);
26 const double b1 = 1.0 * (1 - cos_w0);
27 const double b2 = 0.5 * (1 - cos_w0);
28
29 return {a0, a1, a2, b0, b1, b2};
30}
31
32Filter::Filter() : Filter(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) {}
33
34Filter::Filter(double a0, double a1, double a2, double b0, double b1, double b2)
35 : a1(a1 / a0), a2(a2 / a0), b0(b0 / a0), b1(b1 / a0), b2(b2 / a0) {}
36
37void Filter::Process(std::vector<s16>& signal) {
38 const size_t num_frames = signal.size() / 2;
39 for (size_t i = 0; i < num_frames; i++) {
40 std::rotate(in.begin(), in.end() - 1, in.end());
41 std::rotate(out.begin(), out.end() - 1, out.end());
42
43 for (size_t ch = 0; ch < channel_count; ch++) {
44 in[0][ch] = signal[i * channel_count + ch];
45
46 out[0][ch] = b0 * in[0][ch] + b1 * in[1][ch] + b2 * in[2][ch] - a1 * out[1][ch] -
47 a2 * out[2][ch];
48
49 signal[i * 2 + ch] = std::clamp(out[0][ch], -32768.0, 32767.0);
50 }
51 }
52}
53
54/// Calculates the appropriate Q for each biquad in a cascading filter.
55/// @param total_count The total number of biquads to be cascaded.
56/// @param index 0-index of the biquad to calculate the Q value for.
57static double CascadingBiquadQ(size_t total_count, size_t index) {
58 const double pole = M_PI * (2 * index + 1) / (4.0 * total_count);
59 return 1.0 / (2.0 * std::cos(pole));
60}
61
62CascadingFilter CascadingFilter::LowPass(double cutoff, size_t cascade_size) {
63 std::vector<Filter> cascade(cascade_size);
64 for (size_t i = 0; i < cascade_size; i++) {
65 cascade[i] = Filter::LowPass(cutoff, CascadingBiquadQ(cascade_size, i));
66 }
67 return CascadingFilter{std::move(cascade)};
68}
69
70CascadingFilter::CascadingFilter() = default;
71CascadingFilter::CascadingFilter(std::vector<Filter> filters) : filters(std::move(filters)) {}
72
73void CascadingFilter::Process(std::vector<s16>& signal) {
74 for (auto& filter : filters) {
75 filter.Process(signal);
76 }
77}
78
79} // namespace AudioCore
diff --git a/src/audio_core/algorithm/filter.h b/src/audio_core/algorithm/filter.h
new file mode 100644
index 000000000..a41beef98
--- /dev/null
+++ b/src/audio_core/algorithm/filter.h
@@ -0,0 +1,62 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <vector>
9#include "common/common_types.h"
10
11namespace AudioCore {
12
13/// Digital biquad filter:
14///
15/// b0 + b1 z^-1 + b2 z^-2
16/// H(z) = ------------------------
17/// a0 + a1 z^-1 + b2 z^-2
18class Filter {
19public:
20 /// Creates a low-pass filter.
21 /// @param cutoff Determines the cutoff frequency. A value from 0.0 to 1.0.
22 /// @param Q Determines the quality factor of this filter.
23 static Filter LowPass(double cutoff, double Q = 0.7071);
24
25 /// Passthrough filter.
26 Filter();
27
28 Filter(double a0, double a1, double a2, double b0, double b1, double b2);
29
30 void Process(std::vector<s16>& signal);
31
32private:
33 static constexpr size_t channel_count = 2;
34
35 /// Coefficients are in normalized form (a0 = 1.0).
36 double a1, a2, b0, b1, b2;
37 /// Input History
38 std::array<std::array<double, channel_count>, 3> in;
39 /// Output History
40 std::array<std::array<double, channel_count>, 3> out;
41};
42
43/// Cascade filters to build up higher-order filters from lower-order ones.
44class CascadingFilter {
45public:
46 /// Creates a cascading low-pass filter.
47 /// @param cutoff Determines the cutoff frequency. A value from 0.0 to 1.0.
48 /// @param cascade_size Number of biquads in cascade.
49 static CascadingFilter LowPass(double cutoff, size_t cascade_size);
50
51 /// Passthrough.
52 CascadingFilter();
53
54 explicit CascadingFilter(std::vector<Filter> filters);
55
56 void Process(std::vector<s16>& signal);
57
58private:
59 std::vector<Filter> filters;
60};
61
62} // namespace AudioCore
diff --git a/src/audio_core/algorithm/interpolate.cpp b/src/audio_core/algorithm/interpolate.cpp
new file mode 100644
index 000000000..11459821f
--- /dev/null
+++ b/src/audio_core/algorithm/interpolate.cpp
@@ -0,0 +1,71 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#define _USE_MATH_DEFINES
6
7#include <algorithm>
8#include <cmath>
9#include <vector>
10#include "audio_core/algorithm/interpolate.h"
11#include "common/common_types.h"
12#include "common/logging/log.h"
13
14namespace AudioCore {
15
16/// The Lanczos kernel
17static double Lanczos(size_t a, double x) {
18 if (x == 0.0)
19 return 1.0;
20 const double px = M_PI * x;
21 return a * std::sin(px) * std::sin(px / a) / (px * px);
22}
23
24std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input, double ratio) {
25 if (input.size() < 2)
26 return {};
27
28 if (ratio <= 0) {
29 LOG_CRITICAL(Audio, "Nonsensical interpolation ratio {}", ratio);
30 ratio = 1.0;
31 }
32
33 if (ratio != state.current_ratio) {
34 const double cutoff_frequency = std::min(0.5 / ratio, 0.5 * ratio);
35 state.nyquist = CascadingFilter::LowPass(std::clamp(cutoff_frequency, 0.0, 0.4), 3);
36 state.current_ratio = ratio;
37 }
38 state.nyquist.Process(input);
39
40 constexpr size_t taps = InterpolationState::lanczos_taps;
41 const size_t num_frames = input.size() / 2;
42
43 std::vector<s16> output;
44 output.reserve(static_cast<size_t>(input.size() / ratio + 4));
45
46 double& pos = state.position;
47 auto& h = state.history;
48 for (size_t i = 0; i < num_frames; ++i) {
49 std::rotate(h.begin(), h.end() - 1, h.end());
50 h[0][0] = input[i * 2 + 0];
51 h[0][1] = input[i * 2 + 1];
52
53 while (pos <= 1.0) {
54 double l = 0.0;
55 double r = 0.0;
56 for (size_t j = 0; j < h.size(); j++) {
57 l += Lanczos(taps, pos + j - taps + 1) * h[j][0];
58 r += Lanczos(taps, pos + j - taps + 1) * h[j][1];
59 }
60 output.emplace_back(static_cast<s16>(std::clamp(l, -32768.0, 32767.0)));
61 output.emplace_back(static_cast<s16>(std::clamp(r, -32768.0, 32767.0)));
62
63 pos += ratio;
64 }
65 pos -= 1.0;
66 }
67
68 return output;
69}
70
71} // namespace AudioCore
diff --git a/src/audio_core/algorithm/interpolate.h b/src/audio_core/algorithm/interpolate.h
new file mode 100644
index 000000000..c79c2eef4
--- /dev/null
+++ b/src/audio_core/algorithm/interpolate.h
@@ -0,0 +1,43 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <vector>
9#include "audio_core/algorithm/filter.h"
10#include "common/common_types.h"
11
12namespace AudioCore {
13
14struct InterpolationState {
15 static constexpr size_t lanczos_taps = 4;
16 static constexpr size_t history_size = lanczos_taps * 2 - 1;
17
18 double current_ratio = 0.0;
19 CascadingFilter nyquist;
20 std::array<std::array<s16, 2>, history_size> history = {};
21 double position = 0;
22};
23
24/// Interpolates input signal to produce output signal.
25/// @param input The signal to interpolate.
26/// @param ratio Interpolation ratio.
27/// ratio > 1.0 results in fewer output samples.
28/// ratio < 1.0 results in more output samples.
29/// @returns Output signal.
30std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input, double ratio);
31
32/// Interpolates input signal to produce output signal.
33/// @param input The signal to interpolate.
34/// @param input_rate The sample rate of input.
35/// @param output_rate The desired sample rate of the output.
36/// @returns Output signal.
37inline std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
38 u32 input_rate, u32 output_rate) {
39 const double ratio = static_cast<double>(input_rate) / static_cast<double>(output_rate);
40 return Interpolate(state, std::move(input), ratio);
41}
42
43} // namespace AudioCore
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 6ebed3fb0..397b107f5 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "audio_core/algorithm/interpolate.h"
5#include "audio_core/audio_renderer.h" 6#include "audio_core/audio_renderer.h"
6#include "common/assert.h" 7#include "common/assert.h"
7#include "common/logging/log.h" 8#include "common/logging/log.h"
@@ -199,6 +200,8 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
199 break; 200 break;
200 } 201 }
201 202
203 samples = Interpolate(interp_state, std::move(samples), Info().sample_rate, STREAM_SAMPLE_RATE);
204
202 is_refresh_pending = false; 205 is_refresh_pending = false;
203} 206}
204 207
@@ -224,7 +227,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
224 break; 227 break;
225 } 228 }
226 229
227 samples_remaining -= samples.size(); 230 samples_remaining -= samples.size() / stream->GetNumChannels();
228 231
229 for (const auto& sample : samples) { 232 for (const auto& sample : samples) {
230 const s32 buffer_sample{buffer[offset]}; 233 const s32 buffer_sample{buffer[offset]};
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 13c5d0adc..eba67f28e 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -8,6 +8,7 @@
8#include <memory> 8#include <memory>
9#include <vector> 9#include <vector>
10 10
11#include "audio_core/algorithm/interpolate.h"
11#include "audio_core/audio_out.h" 12#include "audio_core/audio_out.h"
12#include "audio_core/codec.h" 13#include "audio_core/codec.h"
13#include "audio_core/stream.h" 14#include "audio_core/stream.h"
@@ -194,6 +195,7 @@ private:
194 size_t wave_index{}; 195 size_t wave_index{};
195 size_t offset{}; 196 size_t offset{};
196 Codec::ADPCMState adpcm_state{}; 197 Codec::ADPCMState adpcm_state{};
198 InterpolationState interp_state{};
197 std::vector<s16> samples; 199 std::vector<s16> samples;
198 VoiceOutStatus out_status{}; 200 VoiceOutStatus out_status{};
199 VoiceInfo info{}; 201 VoiceInfo info{};
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index d5d4f6f82..939b8a7d3 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -29,8 +29,6 @@ add_library(common STATIC
29 assert.h 29 assert.h
30 bit_field.h 30 bit_field.h
31 bit_set.h 31 bit_set.h
32 break_points.cpp
33 break_points.h
34 cityhash.cpp 32 cityhash.cpp
35 cityhash.h 33 cityhash.h
36 color.h 34 color.h
diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp
deleted file mode 100644
index fa367a4ca..000000000
--- a/src/common/break_points.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <sstream>
7#include "common/break_points.h"
8
9bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const {
10 auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; };
11 auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
12 return it != m_BreakPoints.end();
13}
14
15bool BreakPoints::IsTempBreakPoint(u32 iAddress) const {
16 auto cond = [&iAddress](const TBreakPoint& bp) {
17 return bp.iAddress == iAddress && bp.bTemporary;
18 };
19 auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
20 return it != m_BreakPoints.end();
21}
22
23BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const {
24 TBreakPointsStr bps;
25 for (auto breakpoint : m_BreakPoints) {
26 if (!breakpoint.bTemporary) {
27 std::stringstream bp;
28 bp << std::hex << breakpoint.iAddress << " " << (breakpoint.bOn ? "n" : "");
29 bps.push_back(bp.str());
30 }
31 }
32
33 return bps;
34}
35
36void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) {
37 for (auto bps_item : bps) {
38 TBreakPoint bp;
39 std::stringstream bpstr;
40 bpstr << std::hex << bps_item;
41 bpstr >> bp.iAddress;
42 bp.bOn = bps_item.find("n") != bps_item.npos;
43 bp.bTemporary = false;
44 Add(bp);
45 }
46}
47
48void BreakPoints::Add(const TBreakPoint& bp) {
49 if (!IsAddressBreakPoint(bp.iAddress)) {
50 m_BreakPoints.push_back(bp);
51 // if (jit)
52 // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4);
53 }
54}
55
56void BreakPoints::Add(u32 em_address, bool temp) {
57 if (!IsAddressBreakPoint(em_address)) // only add new addresses
58 {
59 TBreakPoint pt; // breakpoint settings
60 pt.bOn = true;
61 pt.bTemporary = temp;
62 pt.iAddress = em_address;
63
64 m_BreakPoints.push_back(pt);
65
66 // if (jit)
67 // jit->GetBlockCache()->InvalidateICache(em_address, 4);
68 }
69}
70
71void BreakPoints::Remove(u32 em_address) {
72 auto cond = [&em_address](const TBreakPoint& bp) { return bp.iAddress == em_address; };
73 auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
74 if (it != m_BreakPoints.end())
75 m_BreakPoints.erase(it);
76}
77
78void BreakPoints::Clear() {
79 // if (jit)
80 //{
81 // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(),
82 // [](const TBreakPoint& bp)
83 // {
84 // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4);
85 // }
86 // );
87 //}
88
89 m_BreakPoints.clear();
90}
diff --git a/src/common/break_points.h b/src/common/break_points.h
deleted file mode 100644
index e15b9f842..000000000
--- a/src/common/break_points.h
+++ /dev/null
@@ -1,49 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <string>
8#include <vector>
9#include "common/common_types.h"
10
11class DebugInterface;
12
13struct TBreakPoint {
14 u32 iAddress;
15 bool bOn;
16 bool bTemporary;
17};
18
19// Code breakpoints.
20class BreakPoints {
21public:
22 typedef std::vector<TBreakPoint> TBreakPoints;
23 typedef std::vector<std::string> TBreakPointsStr;
24
25 const TBreakPoints& GetBreakPoints() {
26 return m_BreakPoints;
27 }
28
29 TBreakPointsStr GetStrings() const;
30 void AddFromStrings(const TBreakPointsStr& bps);
31
32 // is address breakpoint
33 bool IsAddressBreakPoint(u32 iAddress) const;
34 bool IsTempBreakPoint(u32 iAddress) const;
35
36 // Add BreakPoint
37 void Add(u32 em_address, bool temp = false);
38 void Add(const TBreakPoint& bp);
39
40 // Remove Breakpoint
41 void Remove(u32 iAddress);
42 void Clear();
43
44 void DeleteByAddress(u32 Address);
45
46private:
47 TBreakPoints m_BreakPoints;
48 u32 m_iBreakOnCount;
49};
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index e80784c3c..1323f8d0f 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -302,13 +302,14 @@ Backend* GetBackend(std::string_view backend_name) {
302void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, 302void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
303 unsigned int line_num, const char* function, const char* format, 303 unsigned int line_num, const char* function, const char* format,
304 const fmt::format_args& args) { 304 const fmt::format_args& args) {
305 auto filter = Impl::Instance().GetGlobalFilter(); 305 auto& instance = Impl::Instance();
306 const auto& filter = instance.GetGlobalFilter();
306 if (!filter.CheckMessage(log_class, log_level)) 307 if (!filter.CheckMessage(log_class, log_level))
307 return; 308 return;
308 309
309 Entry entry = 310 Entry entry =
310 CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args)); 311 CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args));
311 312
312 Impl::Instance().PushEntry(std::move(entry)); 313 instance.PushEntry(std::move(entry));
313} 314}
314} // namespace Log 315} // namespace Log
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index 217a87098..3fa8a3bc4 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -4,7 +4,7 @@
4 4
5#include <cstddef> 5#include <cstddef>
6#ifdef _WIN32 6#ifdef _WIN32
7#include <Windows.h> 7#include <windows.h>
8#else 8#else
9#include <cerrno> 9#include <cerrno>
10#include <cstring> 10#include <cstring>
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h
index fd3fbdd4b..927da9187 100644
--- a/src/common/x64/xbyak_abi.h
+++ b/src/common/x64/xbyak_abi.h
@@ -9,10 +9,9 @@
9#include "common/assert.h" 9#include "common/assert.h"
10#include "common/bit_set.h" 10#include "common/bit_set.h"
11 11
12namespace Common { 12namespace Common::X64 {
13namespace X64 {
14 13
15int RegToIndex(const Xbyak::Reg& reg) { 14inline int RegToIndex(const Xbyak::Reg& reg) {
16 using Kind = Xbyak::Reg::Kind; 15 using Kind = Xbyak::Reg::Kind;
17 ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0, 16 ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
18 "RegSet only support GPRs and XMM registers."); 17 "RegSet only support GPRs and XMM registers.");
@@ -152,8 +151,8 @@ constexpr size_t ABI_SHADOW_SPACE = 0;
152 151
153#endif 152#endif
154 153
155void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t needed_frame_size, 154inline void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t needed_frame_size,
156 s32* out_subtraction, s32* out_xmm_offset) { 155 s32* out_subtraction, s32* out_xmm_offset) {
157 int count = (regs & ABI_ALL_GPRS).Count(); 156 int count = (regs & ABI_ALL_GPRS).Count();
158 rsp_alignment -= count * 8; 157 rsp_alignment -= count * 8;
159 size_t subtraction = 0; 158 size_t subtraction = 0;
@@ -174,8 +173,8 @@ void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t needed_f
174 *out_xmm_offset = (s32)(subtraction - xmm_base_subtraction); 173 *out_xmm_offset = (s32)(subtraction - xmm_base_subtraction);
175} 174}
176 175
177size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, 176inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
178 size_t rsp_alignment, size_t needed_frame_size = 0) { 177 size_t rsp_alignment, size_t needed_frame_size = 0) {
179 s32 subtraction, xmm_offset; 178 s32 subtraction, xmm_offset;
180 ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset); 179 ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
181 180
@@ -195,8 +194,8 @@ size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs
195 return ABI_SHADOW_SPACE; 194 return ABI_SHADOW_SPACE;
196} 195}
197 196
198void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, size_t rsp_alignment, 197inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
199 size_t needed_frame_size = 0) { 198 size_t rsp_alignment, size_t needed_frame_size = 0) {
200 s32 subtraction, xmm_offset; 199 s32 subtraction, xmm_offset;
201 ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset); 200 ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
202 201
@@ -217,5 +216,4 @@ void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, s
217 } 216 }
218} 217}
219 218
220} // namespace X64 219} // namespace Common::X64
221} // namespace Common
diff --git a/src/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h
index ec76e0a47..02323a017 100644
--- a/src/common/x64/xbyak_util.h
+++ b/src/common/x64/xbyak_util.h
@@ -8,8 +8,7 @@
8#include <xbyak.h> 8#include <xbyak.h>
9#include "common/x64/xbyak_abi.h" 9#include "common/x64/xbyak_abi.h"
10 10
11namespace Common { 11namespace Common::X64 {
12namespace X64 {
13 12
14// Constants for use with cmpps/cmpss 13// Constants for use with cmpps/cmpss
15enum { 14enum {
@@ -45,5 +44,4 @@ inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
45 } 44 }
46} 45}
47 46
48} // namespace X64 47} // namespace Common::X64
49} // namespace Common
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index cceb1564b..0b0ae5ccc 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -249,6 +249,10 @@ add_library(core STATIC
249 hle/service/nvdrv/devices/nvhost_gpu.h 249 hle/service/nvdrv/devices/nvhost_gpu.h
250 hle/service/nvdrv/devices/nvhost_nvdec.cpp 250 hle/service/nvdrv/devices/nvhost_nvdec.cpp
251 hle/service/nvdrv/devices/nvhost_nvdec.h 251 hle/service/nvdrv/devices/nvhost_nvdec.h
252 hle/service/nvdrv/devices/nvhost_nvjpg.cpp
253 hle/service/nvdrv/devices/nvhost_nvjpg.h
254 hle/service/nvdrv/devices/nvhost_vic.cpp
255 hle/service/nvdrv/devices/nvhost_vic.h
252 hle/service/nvdrv/devices/nvmap.cpp 256 hle/service/nvdrv/devices/nvmap.cpp
253 hle/service/nvdrv/devices/nvmap.h 257 hle/service/nvdrv/devices/nvmap.h
254 hle/service/nvdrv/interface.cpp 258 hle/service/nvdrv/interface.cpp
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 0996f129c..20e5200a8 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -243,9 +243,7 @@ void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
243} 243}
244 244
245void ARM_Dynarmic::PrepareReschedule() { 245void ARM_Dynarmic::PrepareReschedule() {
246 if (jit->IsExecuting()) { 246 jit->HaltExecution();
247 jit->HaltExecution();
248 }
249} 247}
250 248
251void ARM_Dynarmic::ClearInstructionCache() { 249void ARM_Dynarmic::ClearInstructionCache() {
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 384dc7822..7006a37b3 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -34,9 +34,9 @@ class EmuWindow {
34public: 34public:
35 /// Data structure to store emuwindow configuration 35 /// Data structure to store emuwindow configuration
36 struct WindowConfig { 36 struct WindowConfig {
37 bool fullscreen; 37 bool fullscreen = false;
38 int res_width; 38 int res_width = 0;
39 int res_height; 39 int res_height = 0;
40 std::pair<unsigned, unsigned> min_client_area_size; 40 std::pair<unsigned, unsigned> min_client_area_size;
41 }; 41 };
42 42
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index d09ca5992..51a1ec160 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -152,7 +152,7 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
152 // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the 152 // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the
153 // end of the command such that only commands following this one are handled as domains 153 // end of the command such that only commands following this one are handled as domains
154 if (convert_to_domain) { 154 if (convert_to_domain) {
155 ASSERT_MSG(domain_request_handlers.empty(), "already a domain"); 155 ASSERT_MSG(IsSession(), "ServerSession is already a domain instance.");
156 domain_request_handlers = {hle_handler}; 156 domain_request_handlers = {hle_handler};
157 convert_to_domain = false; 157 convert_to_domain = false;
158 } 158 }
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 2bce54fee..1a88e66b9 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -97,7 +97,12 @@ public:
97 97
98 /// Returns true if the session has been converted to a domain, otherwise False 98 /// Returns true if the session has been converted to a domain, otherwise False
99 bool IsDomain() const { 99 bool IsDomain() const {
100 return !domain_request_handlers.empty(); 100 return !IsSession();
101 }
102
103 /// Returns true if this session has not been converted to a domain, otherwise false.
104 bool IsSession() const {
105 return domain_request_handlers.empty();
101 } 106 }
102 107
103 /// Converts the session to a domain at the end of the current command 108 /// Converts the session to a domain at the end of the current command
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index b24f409b3..6be5c474e 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -250,8 +250,11 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
250} 250}
251 251
252/// Break program execution 252/// Break program execution
253static void Break(u64 unk_0, u64 unk_1, u64 unk_2) { 253static void Break(u64 reason, u64 info1, u64 info2) {
254 LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); 254 LOG_CRITICAL(
255 Debug_Emulated,
256 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
257 reason, info1, info2);
255 ASSERT(false); 258 ASSERT(false);
256} 259}
257 260
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 108a7c6eb..ce709ccf4 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -28,7 +28,7 @@ constexpr int DefaultSampleRate{48000};
28class IAudioOut final : public ServiceFramework<IAudioOut> { 28class IAudioOut final : public ServiceFramework<IAudioOut> {
29public: 29public:
30 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) 30 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core)
31 : ServiceFramework("IAudioOut"), audio_params(audio_params), audio_core(audio_core) { 31 : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) {
32 32
33 static const FunctionInfo functions[] = { 33 static const FunctionInfo functions[] = {
34 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 34 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index 08f45b78a..7b91bb258 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -9,42 +9,63 @@
9 9
10namespace Service::MM { 10namespace Service::MM {
11 11
12void InstallInterfaces(SM::ServiceManager& service_manager) { 12class MM_U final : public ServiceFramework<MM_U> {
13 std::make_shared<MM_U>()->InstallAsService(service_manager); 13public:
14} 14 explicit MM_U() : ServiceFramework{"mm:u"} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, &MM_U::Initialize, "InitializeOld"},
18 {1, &MM_U::Finalize, "FinalizeOld"},
19 {2, &MM_U::SetAndWait, "SetAndWaitOld"},
20 {3, &MM_U::Get, "GetOld"},
21 {4, &MM_U::Initialize, "Initialize"},
22 {5, &MM_U::Finalize, "Finalize"},
23 {6, &MM_U::SetAndWait, "SetAndWait"},
24 {7, &MM_U::Get, "Get"},
25 };
26 // clang-format on
15 27
16void MM_U::Initialize(Kernel::HLERequestContext& ctx) { 28 RegisterHandlers(functions);
17 LOG_WARNING(Service_MM, "(STUBBED) called"); 29 }
18 IPC::ResponseBuilder rb{ctx, 2};
19 rb.Push(RESULT_SUCCESS);
20}
21 30
22void MM_U::SetAndWait(Kernel::HLERequestContext& ctx) { 31private:
23 IPC::RequestParser rp{ctx}; 32 void Initialize(Kernel::HLERequestContext& ctx) {
24 min = rp.Pop<u32>(); 33 LOG_WARNING(Service_MM, "(STUBBED) called");
25 max = rp.Pop<u32>(); 34 IPC::ResponseBuilder rb{ctx, 2};
26 current = min; 35 rb.Push(RESULT_SUCCESS);
36 }
27 37
28 LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); 38 void Finalize(Kernel::HLERequestContext& ctx) {
29 IPC::ResponseBuilder rb{ctx, 2}; 39 LOG_WARNING(Service_MM, "(STUBBED) called");
30 rb.Push(RESULT_SUCCESS); 40 IPC::ResponseBuilder rb{ctx, 2};
31} 41 rb.Push(RESULT_SUCCESS);
42 }
32 43
33void MM_U::Get(Kernel::HLERequestContext& ctx) { 44 void SetAndWait(Kernel::HLERequestContext& ctx) {
34 LOG_WARNING(Service_MM, "(STUBBED) called"); 45 IPC::RequestParser rp{ctx};
35 IPC::ResponseBuilder rb{ctx, 3}; 46 min = rp.Pop<u32>();
36 rb.Push(RESULT_SUCCESS); 47 max = rp.Pop<u32>();
37 rb.Push(current); 48 current = min;
38}
39 49
40MM_U::MM_U() : ServiceFramework("mm:u") { 50 LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
41 static const FunctionInfo functions[] = { 51 IPC::ResponseBuilder rb{ctx, 2};
42 {0, nullptr, "InitializeOld"}, {1, nullptr, "FinalizeOld"}, 52 rb.Push(RESULT_SUCCESS);
43 {2, nullptr, "SetAndWaitOld"}, {3, nullptr, "GetOld"}, 53 }
44 {4, &MM_U::Initialize, "Initialize"}, {5, nullptr, "Finalize"}, 54
45 {6, &MM_U::SetAndWait, "SetAndWait"}, {7, &MM_U::Get, "Get"}, 55 void Get(Kernel::HLERequestContext& ctx) {
46 }; 56 LOG_WARNING(Service_MM, "(STUBBED) called");
47 RegisterHandlers(functions); 57 IPC::ResponseBuilder rb{ctx, 3};
58 rb.Push(RESULT_SUCCESS);
59 rb.Push(current);
60 }
61
62 u32 min{0};
63 u32 max{0};
64 u32 current{0};
65};
66
67void InstallInterfaces(SM::ServiceManager& service_manager) {
68 std::make_shared<MM_U>()->InstallAsService(service_manager);
48} 69}
49 70
50} // namespace Service::MM 71} // namespace Service::MM
diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h
index 79eeedf9c..5439fa653 100644
--- a/src/core/hle/service/mm/mm_u.h
+++ b/src/core/hle/service/mm/mm_u.h
@@ -8,21 +8,6 @@
8 8
9namespace Service::MM { 9namespace Service::MM {
10 10
11class MM_U final : public ServiceFramework<MM_U> {
12public:
13 MM_U();
14 ~MM_U() = default;
15
16private:
17 void Initialize(Kernel::HLERequestContext& ctx);
18 void SetAndWait(Kernel::HLERequestContext& ctx);
19 void Get(Kernel::HLERequestContext& ctx);
20
21 u32 min{0};
22 u32 max{0};
23 u32 current{0};
24};
25
26/// Registers all MM services with the specified service manager. 11/// Registers all MM services with the specified service manager.
27void InstallInterfaces(SM::ServiceManager& service_manager); 12void InstallInterfaces(SM::ServiceManager& service_manager);
28 13
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
new file mode 100644
index 000000000..51f01077b
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -0,0 +1,34 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
10
11namespace Service::Nvidia::Devices {
12
13u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
14 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
15 command.raw, input.size(), output.size());
16
17 switch (static_cast<IoctlCommand>(command.raw)) {
18 case IoctlCommand::IocSetNVMAPfdCommand:
19 return SetNVMAPfd(input, output);
20 }
21
22 UNIMPLEMENTED_MSG("Unimplemented ioctl");
23 return 0;
24}
25
26u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
27 IoctlSetNvmapFD params{};
28 std::memcpy(&params, input.data(), input.size());
29 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
30 nvmap_fd = params.nvmap_fd;
31 return 0;
32}
33
34} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
new file mode 100644
index 000000000..2b0eb43ee
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -0,0 +1,36 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include "common/common_types.h"
9#include "common/swap.h"
10#include "core/hle/service/nvdrv/devices/nvdevice.h"
11
12namespace Service::Nvidia::Devices {
13
14class nvhost_nvjpg final : public nvdevice {
15public:
16 nvhost_nvjpg() = default;
17 ~nvhost_nvjpg() override = default;
18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20
21private:
22 enum class IoctlCommand : u32_le {
23 IocSetNVMAPfdCommand = 0x40044801,
24 };
25
26 struct IoctlSetNvmapFD {
27 u32_le nvmap_fd;
28 };
29 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
30
31 u32_le nvmap_fd{};
32
33 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
34};
35
36} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
new file mode 100644
index 000000000..fcb488d50
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -0,0 +1,34 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
10
11namespace Service::Nvidia::Devices {
12
13u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
14 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
15 command.raw, input.size(), output.size());
16
17 switch (static_cast<IoctlCommand>(command.raw)) {
18 case IoctlCommand::IocSetNVMAPfdCommand:
19 return SetNVMAPfd(input, output);
20 }
21
22 UNIMPLEMENTED_MSG("Unimplemented ioctl");
23 return 0;
24}
25
26u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
27 IoctlSetNvmapFD params{};
28 std::memcpy(&params, input.data(), input.size());
29 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
30 nvmap_fd = params.nvmap_fd;
31 return 0;
32}
33
34} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
new file mode 100644
index 000000000..c7d681e52
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -0,0 +1,36 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include "common/common_types.h"
9#include "common/swap.h"
10#include "core/hle/service/nvdrv/devices/nvdevice.h"
11
12namespace Service::Nvidia::Devices {
13
14class nvhost_vic final : public nvdevice {
15public:
16 nvhost_vic() = default;
17 ~nvhost_vic() override = default;
18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20
21private:
22 enum class IoctlCommand : u32_le {
23 IocSetNVMAPfdCommand = 0x40044801,
24 };
25
26 struct IoctlSetNvmapFD {
27 u32_le nvmap_fd;
28 };
29 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
30
31 u32_le nvmap_fd{};
32
33 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
34};
35
36} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 427f4b574..2de39822f 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -12,6 +12,8 @@
12#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" 12#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
13#include "core/hle/service/nvdrv/devices/nvhost_gpu.h" 13#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
14#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" 14#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
15#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
16#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
15#include "core/hle/service/nvdrv/devices/nvmap.h" 17#include "core/hle/service/nvdrv/devices/nvmap.h"
16#include "core/hle/service/nvdrv/interface.h" 18#include "core/hle/service/nvdrv/interface.h"
17#include "core/hle/service/nvdrv/nvdrv.h" 19#include "core/hle/service/nvdrv/nvdrv.h"
@@ -39,6 +41,8 @@ Module::Module() {
39 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev); 41 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);
40 devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(); 42 devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>();
41 devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(); 43 devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>();
44 devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>();
45 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>();
42} 46}
43 47
44u32 Module::Open(const std::string& device_name) { 48u32 Module::Open(const std::string& device_name) {
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 518a0cc46..1cef73216 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -10,7 +10,7 @@
10namespace Service::SM { 10namespace Service::SM {
11 11
12void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { 12void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
13 ASSERT_MSG(!ctx.Session()->IsDomain(), "session is alread a domain"); 13 ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
14 ctx.Session()->ConvertToDomain(); 14 ctx.Session()->ConvertToDomain();
15 15
16 IPC::ResponseBuilder rb{ctx, 3}; 16 IPC::ResponseBuilder rb{ctx, 3};
@@ -41,7 +41,7 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
41void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { 41void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
42 IPC::ResponseBuilder rb{ctx, 3}; 42 IPC::ResponseBuilder rb{ctx, 3};
43 rb.Push(RESULT_SUCCESS); 43 rb.Push(RESULT_SUCCESS);
44 rb.Push<u32>(0x500); 44 rb.Push<u16>(0x500);
45 45
46 LOG_WARNING(Service, "(STUBBED) called"); 46 LOG_WARNING(Service, "(STUBBED) called");
47} 47}
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index de05f21d8..d575a9bea 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -118,7 +118,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
118 118
119 process->program_id = metadata.GetTitleID(); 119 process->program_id = metadata.GetTitleID();
120 process->svc_access_mask.set(); 120 process->svc_access_mask.set();
121 process->address_mappings = default_address_mappings;
122 process->resource_limit = 121 process->resource_limit =
123 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 122 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
124 process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), 123 process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 401cad3ab..6420a7f11 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -398,7 +398,6 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
398 398
399 process->LoadModule(codeset, codeset->entrypoint); 399 process->LoadModule(codeset, codeset->entrypoint);
400 process->svc_access_mask.set(); 400 process->svc_access_mask.set();
401 process->address_mappings = default_address_mappings;
402 401
403 // Attach the default resource limit (APPLICATION) to the process 402 // Attach the default resource limit (APPLICATION) to the process
404 process->resource_limit = 403 process->resource_limit =
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 1f2f31535..b143f043c 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -17,12 +17,6 @@
17 17
18namespace Loader { 18namespace Loader {
19 19
20const std::initializer_list<Kernel::AddressMapping> default_address_mappings = {
21 {0x1FF50000, 0x8000, true}, // part of DSP RAM
22 {0x1FF70000, 0x8000, true}, // part of DSP RAM
23 {0x1F000000, 0x600000, false}, // entire VRAM
24};
25
26FileType IdentifyFile(FileSys::VirtualFile file) { 20FileType IdentifyFile(FileSys::VirtualFile file) {
27 FileType type; 21 FileType type;
28 22
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 285363549..6dffe451a 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <algorithm> 7#include <algorithm>
8#include <initializer_list>
9#include <memory> 8#include <memory>
10#include <string> 9#include <string>
11#include <utility> 10#include <utility>
@@ -208,12 +207,6 @@ protected:
208}; 207};
209 208
210/** 209/**
211 * Common address mappings found in most games, used for binary formats that don't have this
212 * information.
213 */
214extern const std::initializer_list<Kernel::AddressMapping> default_address_mappings;
215
216/**
217 * Identifies a bootable file and return a suitable loader 210 * Identifies a bootable file and return a suitable loader
218 * @param file The bootable file 211 * @param file The bootable file
219 * @return the best loader for this file 212 * @return the best loader for this file
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 908d91eab..2179cf2ea 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -186,7 +186,6 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
186 } 186 }
187 187
188 process->svc_access_mask.set(); 188 process->svc_access_mask.set();
189 process->address_mappings = default_address_mappings;
190 process->resource_limit = 189 process->resource_limit =
191 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 190 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
192 process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); 191 process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index fee7d58c6..a94558ac5 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -152,7 +152,6 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
152 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR); 152 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR);
153 153
154 process->svc_access_mask.set(); 154 process->svc_access_mask.set();
155 process->address_mappings = default_address_mappings;
156 process->resource_limit = 155 process->resource_limit =
157 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 156 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
158 process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); 157 process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 6f0343888..5a593c1f7 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -47,8 +47,10 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
47 case RenderTargetFormat::RGBA32_UINT: 47 case RenderTargetFormat::RGBA32_UINT:
48 return 16; 48 return 16;
49 case RenderTargetFormat::RGBA16_UINT: 49 case RenderTargetFormat::RGBA16_UINT:
50 case RenderTargetFormat::RGBA16_UNORM:
50 case RenderTargetFormat::RGBA16_FLOAT: 51 case RenderTargetFormat::RGBA16_FLOAT:
51 case RenderTargetFormat::RG32_FLOAT: 52 case RenderTargetFormat::RG32_FLOAT:
53 case RenderTargetFormat::RG32_UINT:
52 return 8; 54 return 8;
53 case RenderTargetFormat::RGBA8_UNORM: 55 case RenderTargetFormat::RGBA8_UNORM:
54 case RenderTargetFormat::RGBA8_SNORM: 56 case RenderTargetFormat::RGBA8_SNORM:
@@ -62,6 +64,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
62 case RenderTargetFormat::RG16_FLOAT: 64 case RenderTargetFormat::RG16_FLOAT:
63 case RenderTargetFormat::R32_FLOAT: 65 case RenderTargetFormat::R32_FLOAT:
64 case RenderTargetFormat::R11G11B10_FLOAT: 66 case RenderTargetFormat::R11G11B10_FLOAT:
67 case RenderTargetFormat::R32_UINT:
65 return 4; 68 return 4;
66 case RenderTargetFormat::R16_UNORM: 69 case RenderTargetFormat::R16_UNORM:
67 case RenderTargetFormat::R16_SNORM: 70 case RenderTargetFormat::R16_SNORM:
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 73abb7a18..97dcccb92 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -20,9 +20,11 @@ enum class RenderTargetFormat : u32 {
20 NONE = 0x0, 20 NONE = 0x0,
21 RGBA32_FLOAT = 0xC0, 21 RGBA32_FLOAT = 0xC0,
22 RGBA32_UINT = 0xC2, 22 RGBA32_UINT = 0xC2,
23 RGBA16_UNORM = 0xC6,
23 RGBA16_UINT = 0xC9, 24 RGBA16_UINT = 0xC9,
24 RGBA16_FLOAT = 0xCA, 25 RGBA16_FLOAT = 0xCA,
25 RG32_FLOAT = 0xCB, 26 RG32_FLOAT = 0xCB,
27 RG32_UINT = 0xCD,
26 BGRA8_UNORM = 0xCF, 28 BGRA8_UNORM = 0xCF,
27 RGB10_A2_UNORM = 0xD1, 29 RGB10_A2_UNORM = 0xD1,
28 RGBA8_UNORM = 0xD5, 30 RGBA8_UNORM = 0xD5,
@@ -34,6 +36,7 @@ enum class RenderTargetFormat : u32 {
34 RG16_UINT = 0xDD, 36 RG16_UINT = 0xDD,
35 RG16_FLOAT = 0xDE, 37 RG16_FLOAT = 0xDE,
36 R11G11B10_FLOAT = 0xE0, 38 R11G11B10_FLOAT = 0xE0,
39 R32_UINT = 0xE4,
37 R32_FLOAT = 0xE5, 40 R32_FLOAT = 0xE5,
38 B5G6R5_UNORM = 0xE8, 41 B5G6R5_UNORM = 0xE8,
39 RG8_UNORM = 0xEA, 42 RG8_UNORM = 0xEA,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 52a649e2f..9d1549fe9 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -648,11 +648,11 @@ std::tuple<u8*, GLintptr, u32> RasterizerOpenGL::SetupConstBuffers(
648 648
649 if (used_buffer.IsIndirect()) { 649 if (used_buffer.IsIndirect()) {
650 // Buffer is accessed indirectly, so upload the entire thing 650 // Buffer is accessed indirectly, so upload the entire thing
651 size = buffer.size * sizeof(float); 651 size = buffer.size;
652 652
653 if (size > MaxConstbufferSize) { 653 if (size > MaxConstbufferSize) {
654 LOG_ERROR(HW_GPU, "indirect constbuffer size {} exceeds maximum {}", size, 654 LOG_CRITICAL(HW_GPU, "indirect constbuffer size {} exceeds maximum {}", size,
655 MaxConstbufferSize); 655 MaxConstbufferSize);
656 size = MaxConstbufferSize; 656 size = MaxConstbufferSize;
657 } 657 }
658 } else { 658 } else {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index d635550d2..b6947b97b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -94,13 +94,14 @@ struct FormatTuple {
94static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{ 94static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
95 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U 95 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
96 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S 96 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
97 {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5 97 {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U
98 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm, 98 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm,
99 false}, // A2B10G10R10 99 false}, // A2B10G10R10U
100 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5 100 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5U
101 {GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8 101 {GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8U
102 {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // R8UI 102 {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // R8UI
103 {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBA16F 103 {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBA16F
104 {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // RGBA16U
104 {GL_RGBA16UI, GL_RGBA, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // RGBA16UI 105 {GL_RGBA16UI, GL_RGBA, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // RGBA16UI
105 {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float, 106 {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float,
106 false}, // R11FG11FB10F 107 false}, // R11FG11FB10F
@@ -115,16 +116,17 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
115 {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 116 {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
116 true}, // DXN2UNORM 117 true}, // DXN2UNORM
117 {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM 118 {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM
118 {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 119 {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
119 true}, // BC7U 120 true}, // BC7U
120 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 121 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
121 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8 122 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U
123 {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // G8R8S
122 {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 124 {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8
123 {GL_RGBA32F, GL_RGBA, GL_FLOAT, ComponentType::Float, false}, // RGBA32F 125 {GL_RGBA32F, GL_RGBA, GL_FLOAT, ComponentType::Float, false}, // RGBA32F
124 {GL_RG32F, GL_RG, GL_FLOAT, ComponentType::Float, false}, // RG32F 126 {GL_RG32F, GL_RG, GL_FLOAT, ComponentType::Float, false}, // RG32F
125 {GL_R32F, GL_RED, GL_FLOAT, ComponentType::Float, false}, // R32F 127 {GL_R32F, GL_RED, GL_FLOAT, ComponentType::Float, false}, // R32F
126 {GL_R16F, GL_RED, GL_HALF_FLOAT, ComponentType::Float, false}, // R16F 128 {GL_R16F, GL_RED, GL_HALF_FLOAT, ComponentType::Float, false}, // R16F
127 {GL_R16, GL_RED, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // R16UNORM 129 {GL_R16, GL_RED, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // R16U
128 {GL_R16_SNORM, GL_RED, GL_SHORT, ComponentType::SNorm, false}, // R16S 130 {GL_R16_SNORM, GL_RED, GL_SHORT, ComponentType::SNorm, false}, // R16S
129 {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // R16UI 131 {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, ComponentType::UInt, false}, // R16UI
130 {GL_R16I, GL_RED_INTEGER, GL_SHORT, ComponentType::SInt, false}, // R16I 132 {GL_R16I, GL_RED_INTEGER, GL_SHORT, ComponentType::SInt, false}, // R16I
@@ -137,6 +139,8 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
137 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // SRGBA8 139 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // SRGBA8
138 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // RG8U 140 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // RG8U
139 {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S 141 {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S
142 {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI
143 {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI
140 144
141 // DepthStencil formats 145 // DepthStencil formats
142 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, 146 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
@@ -239,12 +243,13 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
239 // clang-format off 243 // clang-format off
240 MortonCopy<true, PixelFormat::ABGR8U>, 244 MortonCopy<true, PixelFormat::ABGR8U>,
241 MortonCopy<true, PixelFormat::ABGR8S>, 245 MortonCopy<true, PixelFormat::ABGR8S>,
242 MortonCopy<true, PixelFormat::B5G6R5>, 246 MortonCopy<true, PixelFormat::B5G6R5U>,
243 MortonCopy<true, PixelFormat::A2B10G10R10>, 247 MortonCopy<true, PixelFormat::A2B10G10R10U>,
244 MortonCopy<true, PixelFormat::A1B5G5R5>, 248 MortonCopy<true, PixelFormat::A1B5G5R5U>,
245 MortonCopy<true, PixelFormat::R8>, 249 MortonCopy<true, PixelFormat::R8U>,
246 MortonCopy<true, PixelFormat::R8UI>, 250 MortonCopy<true, PixelFormat::R8UI>,
247 MortonCopy<true, PixelFormat::RGBA16F>, 251 MortonCopy<true, PixelFormat::RGBA16F>,
252 MortonCopy<true, PixelFormat::RGBA16U>,
248 MortonCopy<true, PixelFormat::RGBA16UI>, 253 MortonCopy<true, PixelFormat::RGBA16UI>,
249 MortonCopy<true, PixelFormat::R11FG11FB10F>, 254 MortonCopy<true, PixelFormat::R11FG11FB10F>,
250 MortonCopy<true, PixelFormat::RGBA32UI>, 255 MortonCopy<true, PixelFormat::RGBA32UI>,
@@ -256,13 +261,14 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
256 MortonCopy<true, PixelFormat::DXN2SNORM>, 261 MortonCopy<true, PixelFormat::DXN2SNORM>,
257 MortonCopy<true, PixelFormat::BC7U>, 262 MortonCopy<true, PixelFormat::BC7U>,
258 MortonCopy<true, PixelFormat::ASTC_2D_4X4>, 263 MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
259 MortonCopy<true, PixelFormat::G8R8>, 264 MortonCopy<true, PixelFormat::G8R8U>,
265 MortonCopy<true, PixelFormat::G8R8S>,
260 MortonCopy<true, PixelFormat::BGRA8>, 266 MortonCopy<true, PixelFormat::BGRA8>,
261 MortonCopy<true, PixelFormat::RGBA32F>, 267 MortonCopy<true, PixelFormat::RGBA32F>,
262 MortonCopy<true, PixelFormat::RG32F>, 268 MortonCopy<true, PixelFormat::RG32F>,
263 MortonCopy<true, PixelFormat::R32F>, 269 MortonCopy<true, PixelFormat::R32F>,
264 MortonCopy<true, PixelFormat::R16F>, 270 MortonCopy<true, PixelFormat::R16F>,
265 MortonCopy<true, PixelFormat::R16UNORM>, 271 MortonCopy<true, PixelFormat::R16U>,
266 MortonCopy<true, PixelFormat::R16S>, 272 MortonCopy<true, PixelFormat::R16S>,
267 MortonCopy<true, PixelFormat::R16UI>, 273 MortonCopy<true, PixelFormat::R16UI>,
268 MortonCopy<true, PixelFormat::R16I>, 274 MortonCopy<true, PixelFormat::R16I>,
@@ -275,6 +281,8 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
275 MortonCopy<true, PixelFormat::SRGBA8>, 281 MortonCopy<true, PixelFormat::SRGBA8>,
276 MortonCopy<true, PixelFormat::RG8U>, 282 MortonCopy<true, PixelFormat::RG8U>,
277 MortonCopy<true, PixelFormat::RG8S>, 283 MortonCopy<true, PixelFormat::RG8S>,
284 MortonCopy<true, PixelFormat::RG32UI>,
285 MortonCopy<true, PixelFormat::R32UI>,
278 MortonCopy<true, PixelFormat::Z24S8>, 286 MortonCopy<true, PixelFormat::Z24S8>,
279 MortonCopy<true, PixelFormat::S8Z24>, 287 MortonCopy<true, PixelFormat::S8Z24>,
280 MortonCopy<true, PixelFormat::Z32F>, 288 MortonCopy<true, PixelFormat::Z32F>,
@@ -289,12 +297,13 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
289 // clang-format off 297 // clang-format off
290 MortonCopy<false, PixelFormat::ABGR8U>, 298 MortonCopy<false, PixelFormat::ABGR8U>,
291 MortonCopy<false, PixelFormat::ABGR8S>, 299 MortonCopy<false, PixelFormat::ABGR8S>,
292 MortonCopy<false, PixelFormat::B5G6R5>, 300 MortonCopy<false, PixelFormat::B5G6R5U>,
293 MortonCopy<false, PixelFormat::A2B10G10R10>, 301 MortonCopy<false, PixelFormat::A2B10G10R10U>,
294 MortonCopy<false, PixelFormat::A1B5G5R5>, 302 MortonCopy<false, PixelFormat::A1B5G5R5U>,
295 MortonCopy<false, PixelFormat::R8>, 303 MortonCopy<false, PixelFormat::R8U>,
296 MortonCopy<false, PixelFormat::R8UI>, 304 MortonCopy<false, PixelFormat::R8UI>,
297 MortonCopy<false, PixelFormat::RGBA16F>, 305 MortonCopy<false, PixelFormat::RGBA16F>,
306 MortonCopy<false, PixelFormat::RGBA16U>,
298 MortonCopy<false, PixelFormat::RGBA16UI>, 307 MortonCopy<false, PixelFormat::RGBA16UI>,
299 MortonCopy<false, PixelFormat::R11FG11FB10F>, 308 MortonCopy<false, PixelFormat::R11FG11FB10F>,
300 MortonCopy<false, PixelFormat::RGBA32UI>, 309 MortonCopy<false, PixelFormat::RGBA32UI>,
@@ -308,13 +317,14 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
308 nullptr, 317 nullptr,
309 nullptr, 318 nullptr,
310 nullptr, 319 nullptr,
311 MortonCopy<false, PixelFormat::G8R8>, 320 MortonCopy<false, PixelFormat::G8R8U>,
321 MortonCopy<false, PixelFormat::G8R8S>,
312 MortonCopy<false, PixelFormat::BGRA8>, 322 MortonCopy<false, PixelFormat::BGRA8>,
313 MortonCopy<false, PixelFormat::RGBA32F>, 323 MortonCopy<false, PixelFormat::RGBA32F>,
314 MortonCopy<false, PixelFormat::RG32F>, 324 MortonCopy<false, PixelFormat::RG32F>,
315 MortonCopy<false, PixelFormat::R32F>, 325 MortonCopy<false, PixelFormat::R32F>,
316 MortonCopy<false, PixelFormat::R16F>, 326 MortonCopy<false, PixelFormat::R16F>,
317 MortonCopy<false, PixelFormat::R16UNORM>, 327 MortonCopy<false, PixelFormat::R16U>,
318 MortonCopy<false, PixelFormat::R16S>, 328 MortonCopy<false, PixelFormat::R16S>,
319 MortonCopy<false, PixelFormat::R16UI>, 329 MortonCopy<false, PixelFormat::R16UI>,
320 MortonCopy<false, PixelFormat::R16I>, 330 MortonCopy<false, PixelFormat::R16I>,
@@ -327,6 +337,8 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
327 MortonCopy<false, PixelFormat::SRGBA8>, 337 MortonCopy<false, PixelFormat::SRGBA8>,
328 MortonCopy<false, PixelFormat::RG8U>, 338 MortonCopy<false, PixelFormat::RG8U>,
329 MortonCopy<false, PixelFormat::RG8S>, 339 MortonCopy<false, PixelFormat::RG8S>,
340 MortonCopy<false, PixelFormat::RG32UI>,
341 MortonCopy<false, PixelFormat::R32UI>,
330 MortonCopy<false, PixelFormat::Z24S8>, 342 MortonCopy<false, PixelFormat::Z24S8>,
331 MortonCopy<false, PixelFormat::S8Z24>, 343 MortonCopy<false, PixelFormat::S8Z24>,
332 MortonCopy<false, PixelFormat::Z32F>, 344 MortonCopy<false, PixelFormat::Z32F>,
@@ -452,7 +464,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
452} 464}
453 465
454static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) { 466static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
455 const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8)}; 467 const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8U)};
456 for (size_t y = 0; y < height; ++y) { 468 for (size_t y = 0; y < height; ++y) {
457 for (size_t x = 0; x < width; ++x) { 469 for (size_t x = 0; x < width; ++x) {
458 const size_t offset{bpp * (y * width + x)}; 470 const size_t offset{bpp * (y * width + x)};
@@ -484,7 +496,8 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
484 ConvertS8Z24ToZ24S8(data, width, height); 496 ConvertS8Z24ToZ24S8(data, width, height);
485 break; 497 break;
486 498
487 case PixelFormat::G8R8: 499 case PixelFormat::G8R8U:
500 case PixelFormat::G8R8S:
488 // Convert the G8R8 color format to R8G8, as OpenGL does not support G8R8. 501 // Convert the G8R8 color format to R8G8, as OpenGL does not support G8R8.
489 ConvertG8R8ToR8G8(data, width, height); 502 ConvertG8R8ToR8G8(data, width, height);
490 break; 503 break;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 4ab74342e..55cf3782c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -25,51 +25,55 @@ struct SurfaceParams {
25 enum class PixelFormat { 25 enum class PixelFormat {
26 ABGR8U = 0, 26 ABGR8U = 0,
27 ABGR8S = 1, 27 ABGR8S = 1,
28 B5G6R5 = 2, 28 B5G6R5U = 2,
29 A2B10G10R10 = 3, 29 A2B10G10R10U = 3,
30 A1B5G5R5 = 4, 30 A1B5G5R5U = 4,
31 R8 = 5, 31 R8U = 5,
32 R8UI = 6, 32 R8UI = 6,
33 RGBA16F = 7, 33 RGBA16F = 7,
34 RGBA16UI = 8, 34 RGBA16U = 8,
35 R11FG11FB10F = 9, 35 RGBA16UI = 9,
36 RGBA32UI = 10, 36 R11FG11FB10F = 10,
37 DXT1 = 11, 37 RGBA32UI = 11,
38 DXT23 = 12, 38 DXT1 = 12,
39 DXT45 = 13, 39 DXT23 = 13,
40 DXN1 = 14, // This is also known as BC4 40 DXT45 = 14,
41 DXN2UNORM = 15, 41 DXN1 = 15, // This is also known as BC4
42 DXN2SNORM = 16, 42 DXN2UNORM = 16,
43 BC7U = 17, 43 DXN2SNORM = 17,
44 ASTC_2D_4X4 = 18, 44 BC7U = 18,
45 G8R8 = 19, 45 ASTC_2D_4X4 = 19,
46 BGRA8 = 20, 46 G8R8U = 20,
47 RGBA32F = 21, 47 G8R8S = 21,
48 RG32F = 22, 48 BGRA8 = 22,
49 R32F = 23, 49 RGBA32F = 23,
50 R16F = 24, 50 RG32F = 24,
51 R16UNORM = 25, 51 R32F = 25,
52 R16S = 26, 52 R16F = 26,
53 R16UI = 27, 53 R16U = 27,
54 R16I = 28, 54 R16S = 28,
55 RG16 = 29, 55 R16UI = 29,
56 RG16F = 30, 56 R16I = 30,
57 RG16UI = 31, 57 RG16 = 31,
58 RG16I = 32, 58 RG16F = 32,
59 RG16S = 33, 59 RG16UI = 33,
60 RGB32F = 34, 60 RG16I = 34,
61 SRGBA8 = 35, 61 RG16S = 35,
62 RG8U = 36, 62 RGB32F = 36,
63 RG8S = 37, 63 SRGBA8 = 37,
64 RG8U = 38,
65 RG8S = 39,
66 RG32UI = 40,
67 R32UI = 41,
64 68
65 MaxColorFormat, 69 MaxColorFormat,
66 70
67 // DepthStencil formats 71 // DepthStencil formats
68 Z24S8 = 38, 72 Z24S8 = 42,
69 S8Z24 = 39, 73 S8Z24 = 43,
70 Z32F = 40, 74 Z32F = 44,
71 Z16 = 41, 75 Z16 = 45,
72 Z32FS8 = 42, 76 Z32FS8 = 46,
73 77
74 MaxDepthStencilFormat, 78 MaxDepthStencilFormat,
75 79
@@ -109,12 +113,13 @@ struct SurfaceParams {
109 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{ 113 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
110 1, // ABGR8U 114 1, // ABGR8U
111 1, // ABGR8S 115 1, // ABGR8S
112 1, // B5G6R5 116 1, // B5G6R5U
113 1, // A2B10G10R10 117 1, // A2B10G10R10U
114 1, // A1B5G5R5 118 1, // A1B5G5R5U
115 1, // R8 119 1, // R8U
116 1, // R8UI 120 1, // R8UI
117 1, // RGBA16F 121 1, // RGBA16F
122 1, // RGBA16U
118 1, // RGBA16UI 123 1, // RGBA16UI
119 1, // R11FG11FB10F 124 1, // R11FG11FB10F
120 1, // RGBA32UI 125 1, // RGBA32UI
@@ -126,13 +131,14 @@ struct SurfaceParams {
126 4, // DXN2SNORM 131 4, // DXN2SNORM
127 4, // BC7U 132 4, // BC7U
128 4, // ASTC_2D_4X4 133 4, // ASTC_2D_4X4
129 1, // G8R8 134 1, // G8R8U
135 1, // G8R8S
130 1, // BGRA8 136 1, // BGRA8
131 1, // RGBA32F 137 1, // RGBA32F
132 1, // RG32F 138 1, // RG32F
133 1, // R32F 139 1, // R32F
134 1, // R16F 140 1, // R16F
135 1, // R16UNORM 141 1, // R16U
136 1, // R16S 142 1, // R16S
137 1, // R16UI 143 1, // R16UI
138 1, // R16I 144 1, // R16I
@@ -145,6 +151,8 @@ struct SurfaceParams {
145 1, // SRGBA8 151 1, // SRGBA8
146 1, // RG8U 152 1, // RG8U
147 1, // RG8S 153 1, // RG8S
154 1, // RG32UI
155 1, // R32UI
148 1, // Z24S8 156 1, // Z24S8
149 1, // S8Z24 157 1, // S8Z24
150 1, // Z32F 158 1, // Z32F
@@ -163,12 +171,13 @@ struct SurfaceParams {
163 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{ 171 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
164 32, // ABGR8U 172 32, // ABGR8U
165 32, // ABGR8S 173 32, // ABGR8S
166 16, // B5G6R5 174 16, // B5G6R5U
167 32, // A2B10G10R10 175 32, // A2B10G10R10U
168 16, // A1B5G5R5 176 16, // A1B5G5R5U
169 8, // R8 177 8, // R8U
170 8, // R8UI 178 8, // R8UI
171 64, // RGBA16F 179 64, // RGBA16F
180 64, // RGBA16U
172 64, // RGBA16UI 181 64, // RGBA16UI
173 32, // R11FG11FB10F 182 32, // R11FG11FB10F
174 128, // RGBA32UI 183 128, // RGBA32UI
@@ -180,13 +189,14 @@ struct SurfaceParams {
180 128, // DXN2SNORM 189 128, // DXN2SNORM
181 128, // BC7U 190 128, // BC7U
182 32, // ASTC_2D_4X4 191 32, // ASTC_2D_4X4
183 16, // G8R8 192 16, // G8R8U
193 16, // G8R8S
184 32, // BGRA8 194 32, // BGRA8
185 128, // RGBA32F 195 128, // RGBA32F
186 64, // RG32F 196 64, // RG32F
187 32, // R32F 197 32, // R32F
188 16, // R16F 198 16, // R16F
189 16, // R16UNORM 199 16, // R16U
190 16, // R16S 200 16, // R16S
191 16, // R16UI 201 16, // R16UI
192 16, // R16I 202 16, // R16I
@@ -199,6 +209,8 @@ struct SurfaceParams {
199 32, // SRGBA8 209 32, // SRGBA8
200 16, // RG8U 210 16, // RG8U
201 16, // RG8S 211 16, // RG8S
212 64, // RG32UI
213 32, // R32UI
202 32, // Z24S8 214 32, // Z24S8
203 32, // S8Z24 215 32, // S8Z24
204 32, // Z32F 216 32, // Z32F
@@ -244,9 +256,11 @@ struct SurfaceParams {
244 case Tegra::RenderTargetFormat::BGRA8_UNORM: 256 case Tegra::RenderTargetFormat::BGRA8_UNORM:
245 return PixelFormat::BGRA8; 257 return PixelFormat::BGRA8;
246 case Tegra::RenderTargetFormat::RGB10_A2_UNORM: 258 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
247 return PixelFormat::A2B10G10R10; 259 return PixelFormat::A2B10G10R10U;
248 case Tegra::RenderTargetFormat::RGBA16_FLOAT: 260 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
249 return PixelFormat::RGBA16F; 261 return PixelFormat::RGBA16F;
262 case Tegra::RenderTargetFormat::RGBA16_UNORM:
263 return PixelFormat::RGBA16U;
250 case Tegra::RenderTargetFormat::RGBA16_UINT: 264 case Tegra::RenderTargetFormat::RGBA16_UINT:
251 return PixelFormat::RGBA16UI; 265 return PixelFormat::RGBA16UI;
252 case Tegra::RenderTargetFormat::RGBA32_FLOAT: 266 case Tegra::RenderTargetFormat::RGBA32_FLOAT:
@@ -256,11 +270,11 @@ struct SurfaceParams {
256 case Tegra::RenderTargetFormat::R11G11B10_FLOAT: 270 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
257 return PixelFormat::R11FG11FB10F; 271 return PixelFormat::R11FG11FB10F;
258 case Tegra::RenderTargetFormat::B5G6R5_UNORM: 272 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
259 return PixelFormat::B5G6R5; 273 return PixelFormat::B5G6R5U;
260 case Tegra::RenderTargetFormat::RGBA32_UINT: 274 case Tegra::RenderTargetFormat::RGBA32_UINT:
261 return PixelFormat::RGBA32UI; 275 return PixelFormat::RGBA32UI;
262 case Tegra::RenderTargetFormat::R8_UNORM: 276 case Tegra::RenderTargetFormat::R8_UNORM:
263 return PixelFormat::R8; 277 return PixelFormat::R8U;
264 case Tegra::RenderTargetFormat::R8_UINT: 278 case Tegra::RenderTargetFormat::R8_UINT:
265 return PixelFormat::R8UI; 279 return PixelFormat::R8UI;
266 case Tegra::RenderTargetFormat::RG16_FLOAT: 280 case Tegra::RenderTargetFormat::RG16_FLOAT:
@@ -280,7 +294,7 @@ struct SurfaceParams {
280 case Tegra::RenderTargetFormat::R16_FLOAT: 294 case Tegra::RenderTargetFormat::R16_FLOAT:
281 return PixelFormat::R16F; 295 return PixelFormat::R16F;
282 case Tegra::RenderTargetFormat::R16_UNORM: 296 case Tegra::RenderTargetFormat::R16_UNORM:
283 return PixelFormat::R16UNORM; 297 return PixelFormat::R16U;
284 case Tegra::RenderTargetFormat::R16_SNORM: 298 case Tegra::RenderTargetFormat::R16_SNORM:
285 return PixelFormat::R16S; 299 return PixelFormat::R16S;
286 case Tegra::RenderTargetFormat::R16_UINT: 300 case Tegra::RenderTargetFormat::R16_UINT:
@@ -289,6 +303,10 @@ struct SurfaceParams {
289 return PixelFormat::R16I; 303 return PixelFormat::R16I;
290 case Tegra::RenderTargetFormat::R32_FLOAT: 304 case Tegra::RenderTargetFormat::R32_FLOAT:
291 return PixelFormat::R32F; 305 return PixelFormat::R32F;
306 case Tegra::RenderTargetFormat::R32_UINT:
307 return PixelFormat::R32UI;
308 case Tegra::RenderTargetFormat::RG32_UINT:
309 return PixelFormat::RG32UI;
292 default: 310 default:
293 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); 311 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
294 UNREACHABLE(); 312 UNREACHABLE();
@@ -310,15 +328,33 @@ struct SurfaceParams {
310 static_cast<u32>(component_type)); 328 static_cast<u32>(component_type));
311 UNREACHABLE(); 329 UNREACHABLE();
312 case Tegra::Texture::TextureFormat::B5G6R5: 330 case Tegra::Texture::TextureFormat::B5G6R5:
313 return PixelFormat::B5G6R5; 331 switch (component_type) {
332 case Tegra::Texture::ComponentType::UNORM:
333 return PixelFormat::B5G6R5U;
334 }
335 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
336 static_cast<u32>(component_type));
337 UNREACHABLE();
314 case Tegra::Texture::TextureFormat::A2B10G10R10: 338 case Tegra::Texture::TextureFormat::A2B10G10R10:
315 return PixelFormat::A2B10G10R10; 339 switch (component_type) {
340 case Tegra::Texture::ComponentType::UNORM:
341 return PixelFormat::A2B10G10R10U;
342 }
343 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
344 static_cast<u32>(component_type));
345 UNREACHABLE();
316 case Tegra::Texture::TextureFormat::A1B5G5R5: 346 case Tegra::Texture::TextureFormat::A1B5G5R5:
317 return PixelFormat::A1B5G5R5; 347 switch (component_type) {
348 case Tegra::Texture::ComponentType::UNORM:
349 return PixelFormat::A1B5G5R5U;
350 }
351 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
352 static_cast<u32>(component_type));
353 UNREACHABLE();
318 case Tegra::Texture::TextureFormat::R8: 354 case Tegra::Texture::TextureFormat::R8:
319 switch (component_type) { 355 switch (component_type) {
320 case Tegra::Texture::ComponentType::UNORM: 356 case Tegra::Texture::ComponentType::UNORM:
321 return PixelFormat::R8; 357 return PixelFormat::R8U;
322 case Tegra::Texture::ComponentType::UINT: 358 case Tegra::Texture::ComponentType::UINT:
323 return PixelFormat::R8UI; 359 return PixelFormat::R8UI;
324 } 360 }
@@ -326,11 +362,33 @@ struct SurfaceParams {
326 static_cast<u32>(component_type)); 362 static_cast<u32>(component_type));
327 UNREACHABLE(); 363 UNREACHABLE();
328 case Tegra::Texture::TextureFormat::G8R8: 364 case Tegra::Texture::TextureFormat::G8R8:
329 return PixelFormat::G8R8; 365 switch (component_type) {
366 case Tegra::Texture::ComponentType::UNORM:
367 return PixelFormat::G8R8U;
368 case Tegra::Texture::ComponentType::SNORM:
369 return PixelFormat::G8R8S;
370 }
371 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
372 static_cast<u32>(component_type));
373 UNREACHABLE();
330 case Tegra::Texture::TextureFormat::R16_G16_B16_A16: 374 case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
331 return PixelFormat::RGBA16F; 375 switch (component_type) {
376 case Tegra::Texture::ComponentType::UNORM:
377 return PixelFormat::RGBA16U;
378 case Tegra::Texture::ComponentType::FLOAT:
379 return PixelFormat::RGBA16F;
380 }
381 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
382 static_cast<u32>(component_type));
383 UNREACHABLE();
332 case Tegra::Texture::TextureFormat::BF10GF11RF11: 384 case Tegra::Texture::TextureFormat::BF10GF11RF11:
333 return PixelFormat::R11FG11FB10F; 385 switch (component_type) {
386 case Tegra::Texture::ComponentType::FLOAT:
387 return PixelFormat::R11FG11FB10F;
388 }
389 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
390 static_cast<u32>(component_type));
391 UNREACHABLE();
334 case Tegra::Texture::TextureFormat::R32_G32_B32_A32: 392 case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
335 switch (component_type) { 393 switch (component_type) {
336 case Tegra::Texture::ComponentType::FLOAT: 394 case Tegra::Texture::ComponentType::FLOAT:
@@ -342,15 +400,29 @@ struct SurfaceParams {
342 static_cast<u32>(component_type)); 400 static_cast<u32>(component_type));
343 UNREACHABLE(); 401 UNREACHABLE();
344 case Tegra::Texture::TextureFormat::R32_G32: 402 case Tegra::Texture::TextureFormat::R32_G32:
345 return PixelFormat::RG32F; 403 switch (component_type) {
404 case Tegra::Texture::ComponentType::FLOAT:
405 return PixelFormat::RG32F;
406 case Tegra::Texture::ComponentType::UINT:
407 return PixelFormat::RG32UI;
408 }
409 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
410 static_cast<u32>(component_type));
411 UNREACHABLE();
346 case Tegra::Texture::TextureFormat::R32_G32_B32: 412 case Tegra::Texture::TextureFormat::R32_G32_B32:
347 return PixelFormat::RGB32F; 413 switch (component_type) {
414 case Tegra::Texture::ComponentType::FLOAT:
415 return PixelFormat::RGB32F;
416 }
417 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
418 static_cast<u32>(component_type));
419 UNREACHABLE();
348 case Tegra::Texture::TextureFormat::R16: 420 case Tegra::Texture::TextureFormat::R16:
349 switch (component_type) { 421 switch (component_type) {
350 case Tegra::Texture::ComponentType::FLOAT: 422 case Tegra::Texture::ComponentType::FLOAT:
351 return PixelFormat::R16F; 423 return PixelFormat::R16F;
352 case Tegra::Texture::ComponentType::UNORM: 424 case Tegra::Texture::ComponentType::UNORM:
353 return PixelFormat::R16UNORM; 425 return PixelFormat::R16U;
354 case Tegra::Texture::ComponentType::SNORM: 426 case Tegra::Texture::ComponentType::SNORM:
355 return PixelFormat::R16S; 427 return PixelFormat::R16S;
356 case Tegra::Texture::ComponentType::UINT: 428 case Tegra::Texture::ComponentType::UINT:
@@ -362,9 +434,19 @@ struct SurfaceParams {
362 static_cast<u32>(component_type)); 434 static_cast<u32>(component_type));
363 UNREACHABLE(); 435 UNREACHABLE();
364 case Tegra::Texture::TextureFormat::R32: 436 case Tegra::Texture::TextureFormat::R32:
365 return PixelFormat::R32F; 437 switch (component_type) {
438 case Tegra::Texture::ComponentType::FLOAT:
439 return PixelFormat::R32F;
440 case Tegra::Texture::ComponentType::UINT:
441 return PixelFormat::R32UI;
442 }
443 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
444 static_cast<u32>(component_type));
445 UNREACHABLE();
366 case Tegra::Texture::TextureFormat::ZF32: 446 case Tegra::Texture::TextureFormat::ZF32:
367 return PixelFormat::Z32F; 447 return PixelFormat::Z32F;
448 case Tegra::Texture::TextureFormat::Z16:
449 return PixelFormat::Z16;
368 case Tegra::Texture::TextureFormat::Z24S8: 450 case Tegra::Texture::TextureFormat::Z24S8:
369 return PixelFormat::Z24S8; 451 return PixelFormat::Z24S8;
370 case Tegra::Texture::TextureFormat::DXT1: 452 case Tegra::Texture::TextureFormat::DXT1:
@@ -443,6 +525,7 @@ struct SurfaceParams {
443 case Tegra::RenderTargetFormat::R16_UNORM: 525 case Tegra::RenderTargetFormat::R16_UNORM:
444 case Tegra::RenderTargetFormat::B5G6R5_UNORM: 526 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
445 case Tegra::RenderTargetFormat::RG8_UNORM: 527 case Tegra::RenderTargetFormat::RG8_UNORM:
528 case Tegra::RenderTargetFormat::RGBA16_UNORM:
446 return ComponentType::UNorm; 529 return ComponentType::UNorm;
447 case Tegra::RenderTargetFormat::RGBA8_SNORM: 530 case Tegra::RenderTargetFormat::RGBA8_SNORM:
448 case Tegra::RenderTargetFormat::RG16_SNORM: 531 case Tegra::RenderTargetFormat::RG16_SNORM:
@@ -462,6 +545,8 @@ struct SurfaceParams {
462 case Tegra::RenderTargetFormat::RG16_UINT: 545 case Tegra::RenderTargetFormat::RG16_UINT:
463 case Tegra::RenderTargetFormat::R8_UINT: 546 case Tegra::RenderTargetFormat::R8_UINT:
464 case Tegra::RenderTargetFormat::R16_UINT: 547 case Tegra::RenderTargetFormat::R16_UINT:
548 case Tegra::RenderTargetFormat::RG32_UINT:
549 case Tegra::RenderTargetFormat::R32_UINT:
465 return ComponentType::UInt; 550 return ComponentType::UInt;
466 case Tegra::RenderTargetFormat::RG16_SINT: 551 case Tegra::RenderTargetFormat::RG16_SINT:
467 case Tegra::RenderTargetFormat::R16_SINT: 552 case Tegra::RenderTargetFormat::R16_SINT:
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 6834d7085..e0dfdbb9f 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -367,31 +367,32 @@ public:
367 } 367 }
368 368
369 /// Generates code representing a uniform (C buffer) register, interpreted as the input type. 369 /// Generates code representing a uniform (C buffer) register, interpreted as the input type.
370 std::string GetUniform(u64 index, u64 offset, GLSLRegister::Type type) { 370 std::string GetUniform(u64 index, u64 offset, GLSLRegister::Type type,
371 Register::Size size = Register::Size::Word) {
371 declr_const_buffers[index].MarkAsUsed(index, offset, stage); 372 declr_const_buffers[index].MarkAsUsed(index, offset, stage);
372 std::string value = 'c' + std::to_string(index) + '[' + std::to_string(offset / 4) + "][" + 373 std::string value = 'c' + std::to_string(index) + '[' + std::to_string(offset / 4) + "][" +
373 std::to_string(offset % 4) + ']'; 374 std::to_string(offset % 4) + ']';
374 375
375 if (type == GLSLRegister::Type::Float) { 376 if (type == GLSLRegister::Type::Float) {
376 return value; 377 // Do nothing, default
377 } else if (type == GLSLRegister::Type::Integer) { 378 } else if (type == GLSLRegister::Type::Integer) {
378 return "floatBitsToInt(" + value + ')'; 379 value = "floatBitsToInt(" + value + ')';
379 } else if (type == GLSLRegister::Type::UnsignedInteger) { 380 } else if (type == GLSLRegister::Type::UnsignedInteger) {
380 return "floatBitsToUint(" + value + ')'; 381 value = "floatBitsToUint(" + value + ')';
381 } else { 382 } else {
382 UNREACHABLE(); 383 UNREACHABLE();
383 } 384 }
385
386 return ConvertIntegerSize(value, size);
384 } 387 }
385 388
386 std::string GetUniformIndirect(u64 index, s64 offset, const Register& index_reg, 389 std::string GetUniformIndirect(u64 cbuf_index, s64 offset, const std::string& index_str,
387 GLSLRegister::Type type) { 390 GLSLRegister::Type type) {
388 declr_const_buffers[index].MarkAsUsedIndirect(index, stage); 391 declr_const_buffers[cbuf_index].MarkAsUsedIndirect(cbuf_index, stage);
389
390 std::string final_offset = "((floatBitsToInt(" + GetRegister(index_reg, 0) + ") + " +
391 std::to_string(offset) + ") / 4)";
392 392
393 std::string value = 393 std::string final_offset = fmt::format("({} + {})", index_str, offset / 4);
394 'c' + std::to_string(index) + '[' + final_offset + " / 4][" + final_offset + " % 4]"; 394 std::string value = 'c' + std::to_string(cbuf_index) + '[' + final_offset + " / 4][" +
395 final_offset + " % 4]";
395 396
396 if (type == GLSLRegister::Type::Float) { 397 if (type == GLSLRegister::Type::Float) {
397 return value; 398 return value;
@@ -1249,20 +1250,41 @@ private:
1249 op_a = "abs(" + op_a + ')'; 1250 op_a = "abs(" + op_a + ')';
1250 } 1251 }
1251 1252
1253 if (instr.conversion.negate_a) {
1254 op_a = "-(" + op_a + ')';
1255 }
1256
1252 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, 1257 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
1253 1, instr.alu.saturate_d, 0, instr.conversion.dest_size); 1258 1, instr.alu.saturate_d, 0, instr.conversion.dest_size);
1254 break; 1259 break;
1255 } 1260 }
1256 case OpCode::Id::I2F_R: { 1261 case OpCode::Id::I2F_R:
1262 case OpCode::Id::I2F_C: {
1257 ASSERT_MSG(instr.conversion.dest_size == Register::Size::Word, "Unimplemented"); 1263 ASSERT_MSG(instr.conversion.dest_size == Register::Size::Word, "Unimplemented");
1258 ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); 1264 ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
1259 std::string op_a = regs.GetRegisterAsInteger( 1265
1260 instr.gpr20, 0, instr.conversion.is_input_signed, instr.conversion.src_size); 1266 std::string op_a{};
1267
1268 if (instr.is_b_gpr) {
1269 op_a =
1270 regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_input_signed,
1271 instr.conversion.src_size);
1272 } else {
1273 op_a = regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
1274 instr.conversion.is_input_signed
1275 ? GLSLRegister::Type::Integer
1276 : GLSLRegister::Type::UnsignedInteger,
1277 instr.conversion.src_size);
1278 }
1261 1279
1262 if (instr.conversion.abs_a) { 1280 if (instr.conversion.abs_a) {
1263 op_a = "abs(" + op_a + ')'; 1281 op_a = "abs(" + op_a + ')';
1264 } 1282 }
1265 1283
1284 if (instr.conversion.negate_a) {
1285 op_a = "-(" + op_a + ')';
1286 }
1287
1266 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); 1288 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
1267 break; 1289 break;
1268 } 1290 }
@@ -1271,6 +1293,14 @@ private:
1271 ASSERT_MSG(instr.conversion.src_size == Register::Size::Word, "Unimplemented"); 1293 ASSERT_MSG(instr.conversion.src_size == Register::Size::Word, "Unimplemented");
1272 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); 1294 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
1273 1295
1296 if (instr.conversion.abs_a) {
1297 op_a = "abs(" + op_a + ')';
1298 }
1299
1300 if (instr.conversion.negate_a) {
1301 op_a = "-(" + op_a + ')';
1302 }
1303
1274 switch (instr.conversion.f2f.rounding) { 1304 switch (instr.conversion.f2f.rounding) {
1275 case Tegra::Shader::F2fRoundingOp::None: 1305 case Tegra::Shader::F2fRoundingOp::None:
1276 break; 1306 break;
@@ -1293,21 +1323,29 @@ private:
1293 break; 1323 break;
1294 } 1324 }
1295 1325
1296 if (instr.conversion.abs_a) {
1297 op_a = "abs(" + op_a + ')';
1298 }
1299
1300 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d); 1326 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
1301 break; 1327 break;
1302 } 1328 }
1303 case OpCode::Id::F2I_R: { 1329 case OpCode::Id::F2I_R:
1330 case OpCode::Id::F2I_C: {
1304 ASSERT_MSG(instr.conversion.src_size == Register::Size::Word, "Unimplemented"); 1331 ASSERT_MSG(instr.conversion.src_size == Register::Size::Word, "Unimplemented");
1305 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); 1332 std::string op_a{};
1333
1334 if (instr.is_b_gpr) {
1335 op_a = regs.GetRegisterAsFloat(instr.gpr20);
1336 } else {
1337 op_a = regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
1338 GLSLRegister::Type::Float);
1339 }
1306 1340
1307 if (instr.conversion.abs_a) { 1341 if (instr.conversion.abs_a) {
1308 op_a = "abs(" + op_a + ')'; 1342 op_a = "abs(" + op_a + ')';
1309 } 1343 }
1310 1344
1345 if (instr.conversion.negate_a) {
1346 op_a = "-(" + op_a + ')';
1347 }
1348
1311 switch (instr.conversion.f2i.rounding) { 1349 switch (instr.conversion.f2i.rounding) {
1312 case Tegra::Shader::F2iRoundingOp::None: 1350 case Tegra::Shader::F2iRoundingOp::None:
1313 break; 1351 break;
@@ -1355,11 +1393,16 @@ private:
1355 case OpCode::Id::LD_C: { 1393 case OpCode::Id::LD_C: {
1356 ASSERT_MSG(instr.ld_c.unknown == 0, "Unimplemented"); 1394 ASSERT_MSG(instr.ld_c.unknown == 0, "Unimplemented");
1357 1395
1396 // Add an extra scope and declare the index register inside to prevent
1397 // overwriting it in case it is used as an output of the LD instruction.
1398 shader.AddLine("{");
1399 ++shader.scope;
1400
1401 shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) +
1402 " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);");
1403
1358 std::string op_a = 1404 std::string op_a =
1359 regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 0, instr.gpr8, 1405 regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 0, "index",
1360 GLSLRegister::Type::Float);
1361 std::string op_b =
1362 regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 4, instr.gpr8,
1363 GLSLRegister::Type::Float); 1406 GLSLRegister::Type::Float);
1364 1407
1365 switch (instr.ld_c.type.Value()) { 1408 switch (instr.ld_c.type.Value()) {
@@ -1367,16 +1410,22 @@ private:
1367 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); 1410 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
1368 break; 1411 break;
1369 1412
1370 case Tegra::Shader::UniformType::Double: 1413 case Tegra::Shader::UniformType::Double: {
1414 std::string op_b =
1415 regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 4,
1416 "index", GLSLRegister::Type::Float);
1371 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); 1417 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
1372 regs.SetRegisterToFloat(instr.gpr0.Value() + 1, 0, op_b, 1, 1); 1418 regs.SetRegisterToFloat(instr.gpr0.Value() + 1, 0, op_b, 1, 1);
1373 break; 1419 break;
1374 1420 }
1375 default: 1421 default:
1376 LOG_CRITICAL(HW_GPU, "Unhandled type: {}", 1422 LOG_CRITICAL(HW_GPU, "Unhandled type: {}",
1377 static_cast<unsigned>(instr.ld_c.type.Value())); 1423 static_cast<unsigned>(instr.ld_c.type.Value()));
1378 UNREACHABLE(); 1424 UNREACHABLE();
1379 } 1425 }
1426
1427 --shader.scope;
1428 shader.AddLine("}");
1380 break; 1429 break;
1381 } 1430 }
1382 case OpCode::Id::ST_A: { 1431 case OpCode::Id::ST_A: {
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 679e5ceb2..8f719fdd8 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -24,15 +24,25 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs;
24 24
25inline GLenum VertexType(Maxwell::VertexAttribute attrib) { 25inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
26 switch (attrib.type) { 26 switch (attrib.type) {
27 case Maxwell::VertexAttribute::Type::UnsignedInt:
27 case Maxwell::VertexAttribute::Type::UnsignedNorm: { 28 case Maxwell::VertexAttribute::Type::UnsignedNorm: {
28 29
29 switch (attrib.size) { 30 switch (attrib.size) {
31 case Maxwell::VertexAttribute::Size::Size_8:
30 case Maxwell::VertexAttribute::Size::Size_8_8: 32 case Maxwell::VertexAttribute::Size::Size_8_8:
33 case Maxwell::VertexAttribute::Size::Size_8_8_8:
31 case Maxwell::VertexAttribute::Size::Size_8_8_8_8: 34 case Maxwell::VertexAttribute::Size::Size_8_8_8_8:
32 return GL_UNSIGNED_BYTE; 35 return GL_UNSIGNED_BYTE;
36 case Maxwell::VertexAttribute::Size::Size_16:
33 case Maxwell::VertexAttribute::Size::Size_16_16: 37 case Maxwell::VertexAttribute::Size::Size_16_16:
38 case Maxwell::VertexAttribute::Size::Size_16_16_16:
34 case Maxwell::VertexAttribute::Size::Size_16_16_16_16: 39 case Maxwell::VertexAttribute::Size::Size_16_16_16_16:
35 return GL_UNSIGNED_SHORT; 40 return GL_UNSIGNED_SHORT;
41 case Maxwell::VertexAttribute::Size::Size_32:
42 case Maxwell::VertexAttribute::Size::Size_32_32:
43 case Maxwell::VertexAttribute::Size::Size_32_32_32:
44 case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
45 return GL_UNSIGNED_INT;
36 case Maxwell::VertexAttribute::Size::Size_10_10_10_2: 46 case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
37 return GL_UNSIGNED_INT_2_10_10_10_REV; 47 return GL_UNSIGNED_INT_2_10_10_10_REV;
38 } 48 }
@@ -42,16 +52,25 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
42 return {}; 52 return {};
43 } 53 }
44 54
55 case Maxwell::VertexAttribute::Type::SignedInt:
45 case Maxwell::VertexAttribute::Type::SignedNorm: { 56 case Maxwell::VertexAttribute::Type::SignedNorm: {
46 57
47 switch (attrib.size) { 58 switch (attrib.size) {
48 case Maxwell::VertexAttribute::Size::Size_32_32_32: 59 case Maxwell::VertexAttribute::Size::Size_8:
49 return GL_INT;
50 case Maxwell::VertexAttribute::Size::Size_8_8: 60 case Maxwell::VertexAttribute::Size::Size_8_8:
61 case Maxwell::VertexAttribute::Size::Size_8_8_8:
51 case Maxwell::VertexAttribute::Size::Size_8_8_8_8: 62 case Maxwell::VertexAttribute::Size::Size_8_8_8_8:
52 return GL_BYTE; 63 return GL_BYTE;
64 case Maxwell::VertexAttribute::Size::Size_16:
53 case Maxwell::VertexAttribute::Size::Size_16_16: 65 case Maxwell::VertexAttribute::Size::Size_16_16:
66 case Maxwell::VertexAttribute::Size::Size_16_16_16:
67 case Maxwell::VertexAttribute::Size::Size_16_16_16_16:
54 return GL_SHORT; 68 return GL_SHORT;
69 case Maxwell::VertexAttribute::Size::Size_32:
70 case Maxwell::VertexAttribute::Size::Size_32_32:
71 case Maxwell::VertexAttribute::Size::Size_32_32_32:
72 case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
73 return GL_INT;
55 case Maxwell::VertexAttribute::Size::Size_10_10_10_2: 74 case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
56 return GL_INT_2_10_10_10_REV; 75 return GL_INT_2_10_10_10_REV;
57 } 76 }
@@ -61,9 +80,6 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
61 return {}; 80 return {};
62 } 81 }
63 82
64 case Maxwell::VertexAttribute::Type::UnsignedInt:
65 return GL_UNSIGNED_INT;
66
67 case Maxwell::VertexAttribute::Type::Float: 83 case Maxwell::VertexAttribute::Type::Float:
68 return GL_FLOAT; 84 return GL_FLOAT;
69 } 85 }