summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/audio_core/CMakeLists.txt16
-rw-r--r--src/audio_core/audio_core.cpp53
-rw-r--r--src/audio_core/audio_core.h26
-rw-r--r--src/audio_core/hle/dsp.cpp42
-rw-r--r--src/audio_core/hle/dsp.h502
-rw-r--r--src/audio_core/hle/pipe.cpp55
-rw-r--r--src/audio_core/hle/pipe.h38
-rw-r--r--src/audio_core/sink.h34
-rw-r--r--src/citra/CMakeLists.txt2
-rw-r--r--src/citra_qt/CMakeLists.txt2
-rw-r--r--src/citra_qt/main.cpp18
-rw-r--r--src/citra_qt/main.h8
-rw-r--r--src/common/bit_field.h44
-rw-r--r--src/common/color.h16
-rw-r--r--src/common/emu_window.cpp4
-rw-r--r--src/common/key_map.h14
-rw-r--r--src/common/logging/backend.cpp3
-rw-r--r--src/common/logging/backend.h20
-rw-r--r--src/common/logging/log.h3
-rw-r--r--src/common/x64/emitter.cpp4
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/arm/disassembler/arm_disasm.cpp18
-rw-r--r--src/core/file_sys/archive_backend.cpp8
-rw-r--r--src/core/file_sys/archive_backend.h8
-rw-r--r--src/core/hle/kernel/memory.cpp5
-rw-r--r--src/core/hle/kernel/process.cpp2
-rw-r--r--src/core/hle/kernel/vm_manager.cpp7
-rw-r--r--src/core/hle/kernel/vm_manager.h5
-rw-r--r--src/core/hle/result.h8
-rw-r--r--src/core/hle/service/ac_u.cpp1
-rw-r--r--src/core/hle/service/act_u.cpp1
-rw-r--r--src/core/hle/service/am/am.cpp4
-rw-r--r--src/core/hle/service/am/am.h6
-rw-r--r--src/core/hle/service/am/am_app.cpp1
-rw-r--r--src/core/hle/service/am/am_net.cpp1
-rw-r--r--src/core/hle/service/am/am_sys.cpp1
-rw-r--r--src/core/hle/service/am/am_u.cpp1
-rw-r--r--src/core/hle/service/apt/apt.cpp2
-rw-r--r--src/core/hle/service/apt/apt_a.cpp1
-rw-r--r--src/core/hle/service/apt/apt_s.cpp2
-rw-r--r--src/core/hle/service/apt/apt_u.cpp3
-rw-r--r--src/core/hle/service/boss/boss.cpp4
-rw-r--r--src/core/hle/service/boss/boss.h3
-rw-r--r--src/core/hle/service/boss/boss_p.cpp2
-rw-r--r--src/core/hle/service/boss/boss_u.cpp2
-rw-r--r--src/core/hle/service/cam/cam.cpp4
-rw-r--r--src/core/hle/service/cam/cam.h3
-rw-r--r--src/core/hle/service/cam/cam_c.cpp2
-rw-r--r--src/core/hle/service/cam/cam_q.cpp2
-rw-r--r--src/core/hle/service/cam/cam_s.cpp2
-rw-r--r--src/core/hle/service/cam/cam_u.cpp2
-rw-r--r--src/core/hle/service/cecd/cecd.cpp4
-rw-r--r--src/core/hle/service/cecd/cecd.h3
-rw-r--r--src/core/hle/service/cecd/cecd_s.cpp2
-rw-r--r--src/core/hle/service/cecd/cecd_u.cpp9
-rw-r--r--src/core/hle/service/cfg/cfg.cpp27
-rw-r--r--src/core/hle/service/cfg/cfg.h9
-rw-r--r--src/core/hle/service/cfg/cfg_i.cpp1
-rw-r--r--src/core/hle/service/cfg/cfg_s.cpp1
-rw-r--r--src/core/hle/service/cfg/cfg_u.cpp1
-rw-r--r--src/core/hle/service/dsp_dsp.cpp136
-rw-r--r--src/core/hle/service/dsp_dsp.h12
-rw-r--r--src/core/hle/service/err_f.cpp3
-rw-r--r--src/core/hle/service/frd/frd.cpp4
-rw-r--r--src/core/hle/service/frd/frd.h3
-rw-r--r--src/core/hle/service/frd/frd_a.cpp2
-rw-r--r--src/core/hle/service/frd/frd_u.cpp2
-rw-r--r--src/core/hle/service/gsp_gpu.cpp6
-rw-r--r--src/core/hle/service/gsp_lcd.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp3
-rw-r--r--src/core/hle/service/hid/hid_spvr.cpp1
-rw-r--r--src/core/hle/service/hid/hid_user.cpp1
-rw-r--r--src/core/hle/service/http_c.cpp1
-rw-r--r--src/core/hle/service/ir/ir.cpp73
-rw-r--r--src/core/hle/service/ir/ir.h53
-rw-r--r--src/core/hle/service/ir/ir_rst.cpp1
-rw-r--r--src/core/hle/service/ir/ir_u.cpp2
-rw-r--r--src/core/hle/service/ir/ir_user.cpp41
-rw-r--r--src/core/hle/service/ldr_ro.cpp2
-rw-r--r--src/core/hle/service/mic_u.cpp1
-rw-r--r--src/core/hle/service/ndm_u.cpp3
-rw-r--r--src/core/hle/service/news/news.cpp4
-rw-r--r--src/core/hle/service/news/news.h3
-rw-r--r--src/core/hle/service/news/news_s.cpp1
-rw-r--r--src/core/hle/service/news/news_u.cpp2
-rw-r--r--src/core/hle/service/nim/nim.cpp5
-rw-r--r--src/core/hle/service/nim/nim.h6
-rw-r--r--src/core/hle/service/nim/nim_aoc.cpp2
-rw-r--r--src/core/hle/service/nim/nim_s.cpp2
-rw-r--r--src/core/hle/service/nim/nim_u.cpp1
-rw-r--r--src/core/hle/service/ns_s.cpp11
-rw-r--r--src/core/hle/service/nwm_uds.cpp2
-rw-r--r--src/core/hle/service/pm_app.cpp1
-rw-r--r--src/core/hle/service/ptm/ptm.cpp4
-rw-r--r--src/core/hle/service/ptm/ptm.h7
-rw-r--r--src/core/hle/service/ptm/ptm_play.cpp1
-rw-r--r--src/core/hle/service/ptm/ptm_sysm.cpp1
-rw-r--r--src/core/hle/service/ptm/ptm_u.cpp3
-rw-r--r--src/core/hle/service/soc_u.cpp12
-rw-r--r--src/core/hle/service/srv.cpp2
-rw-r--r--src/core/hle/service/ssl_c.cpp2
-rw-r--r--src/core/hle/service/y2r_u.cpp4
-rw-r--r--src/core/hw/gpu.cpp22
-rw-r--r--src/core/loader/elf.cpp6
-rw-r--r--src/core/memory.cpp86
-rw-r--r--src/core/memory_setup.h7
-rw-r--r--src/core/mmio.h34
-rw-r--r--src/core/system.cpp7
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/clipper.cpp10
-rw-r--r--src/video_core/command_processor.cpp63
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp8
-rw-r--r--src/video_core/pica.cpp522
-rw-r--r--src/video_core/pica.h401
-rw-r--r--src/video_core/pica_types.h146
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp409
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h155
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp223
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.h2
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_state.h4
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h12
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp6
-rw-r--r--src/video_core/shader/shader.cpp6
-rw-r--r--src/video_core/shader/shader.h8
-rw-r--r--src/video_core/shader/shader_interpreter.cpp3
-rw-r--r--src/video_core/shader/shader_jit_x64.cpp14
-rw-r--r--src/video_core/shader/shader_jit_x64.h2
129 files changed, 3042 insertions, 629 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cb09f3cd1..2bb411492 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,6 +4,7 @@ include_directories(.)
4add_subdirectory(common) 4add_subdirectory(common)
5add_subdirectory(core) 5add_subdirectory(core)
6add_subdirectory(video_core) 6add_subdirectory(video_core)
7add_subdirectory(audio_core)
7if (ENABLE_GLFW) 8if (ENABLE_GLFW)
8 add_subdirectory(citra) 9 add_subdirectory(citra)
9endif() 10endif()
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
new file mode 100644
index 000000000..b0d1c7eb6
--- /dev/null
+++ b/src/audio_core/CMakeLists.txt
@@ -0,0 +1,16 @@
1set(SRCS
2 audio_core.cpp
3 hle/dsp.cpp
4 hle/pipe.cpp
5 )
6
7set(HEADERS
8 audio_core.h
9 hle/dsp.h
10 hle/pipe.h
11 sink.h
12 )
13
14create_directory_groups(${SRCS} ${HEADERS})
15
16add_library(audio_core STATIC ${SRCS} ${HEADERS}) \ No newline at end of file
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
new file mode 100644
index 000000000..894f46990
--- /dev/null
+++ b/src/audio_core/audio_core.cpp
@@ -0,0 +1,53 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "audio_core/audio_core.h"
6#include "audio_core/hle/dsp.h"
7
8#include "core/core_timing.h"
9#include "core/hle/kernel/vm_manager.h"
10#include "core/hle/service/dsp_dsp.h"
11
12namespace AudioCore {
13
14// Audio Ticks occur about every 5 miliseconds.
15static int tick_event; ///< CoreTiming event
16static constexpr u64 audio_frame_ticks = 1310252ull; ///< Units: ARM11 cycles
17
18static void AudioTickCallback(u64 /*userdata*/, int cycles_late) {
19 if (DSP::HLE::Tick()) {
20 // HACK: We're not signaling the interrups when they should be, but just firing them all off together.
21 // It should be only (interrupt_id = 2, channel_id = 2) that's signalled here.
22 // TODO(merry): Understand when the other interrupts are fired.
23 DSP_DSP::SignalAllInterrupts();
24 }
25
26 // Reschedule recurrent event
27 CoreTiming::ScheduleEvent(audio_frame_ticks - cycles_late, tick_event);
28}
29
30/// Initialise Audio
31void Init() {
32 DSP::HLE::Init();
33
34 tick_event = CoreTiming::RegisterEvent("AudioCore::tick_event", AudioTickCallback);
35 CoreTiming::ScheduleEvent(audio_frame_ticks, tick_event);
36}
37
38/// Add DSP address spaces to Process's address space.
39void AddAddressSpace(Kernel::VMManager& address_space) {
40 auto r0_vma = address_space.MapBackingMemory(DSP::HLE::region0_base, reinterpret_cast<u8*>(&DSP::HLE::g_region0), sizeof(DSP::HLE::SharedMemory), Kernel::MemoryState::IO).MoveFrom();
41 address_space.Reprotect(r0_vma, Kernel::VMAPermission::ReadWrite);
42
43 auto r1_vma = address_space.MapBackingMemory(DSP::HLE::region1_base, reinterpret_cast<u8*>(&DSP::HLE::g_region1), sizeof(DSP::HLE::SharedMemory), Kernel::MemoryState::IO).MoveFrom();
44 address_space.Reprotect(r1_vma, Kernel::VMAPermission::ReadWrite);
45}
46
47/// Shutdown Audio
48void Shutdown() {
49 CoreTiming::UnscheduleEvent(tick_event, 0);
50 DSP::HLE::Shutdown();
51}
52
53} //namespace
diff --git a/src/audio_core/audio_core.h b/src/audio_core/audio_core.h
new file mode 100644
index 000000000..64c330914
--- /dev/null
+++ b/src/audio_core/audio_core.h
@@ -0,0 +1,26 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace Kernel {
8class VMManager;
9}
10
11namespace AudioCore {
12
13constexpr int num_sources = 24;
14constexpr int samples_per_frame = 160; ///< Samples per audio frame at native sample rate
15constexpr int native_sample_rate = 32728; ///< 32kHz
16
17/// Initialise Audio Core
18void Init();
19
20/// Add DSP address spaces to a Process.
21void AddAddressSpace(Kernel::VMManager& vm_manager);
22
23/// Shutdown Audio Core
24void Shutdown();
25
26} // namespace
diff --git a/src/audio_core/hle/dsp.cpp b/src/audio_core/hle/dsp.cpp
new file mode 100644
index 000000000..c89356edc
--- /dev/null
+++ b/src/audio_core/hle/dsp.cpp
@@ -0,0 +1,42 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "audio_core/hle/dsp.h"
6#include "audio_core/hle/pipe.h"
7
8namespace DSP {
9namespace HLE {
10
11SharedMemory g_region0;
12SharedMemory g_region1;
13
14void Init() {
15 DSP::HLE::ResetPipes();
16}
17
18void Shutdown() {
19}
20
21bool Tick() {
22 return true;
23}
24
25SharedMemory& CurrentRegion() {
26 // The region with the higher frame counter is chosen unless there is wraparound.
27
28 if (g_region0.frame_counter == 0xFFFFu && g_region1.frame_counter != 0xFFFEu) {
29 // Wraparound has occured.
30 return g_region1;
31 }
32
33 if (g_region1.frame_counter == 0xFFFFu && g_region0.frame_counter != 0xFFFEu) {
34 // Wraparound has occured.
35 return g_region0;
36 }
37
38 return (g_region0.frame_counter > g_region1.frame_counter) ? g_region0 : g_region1;
39}
40
41} // namespace HLE
42} // namespace DSP
diff --git a/src/audio_core/hle/dsp.h b/src/audio_core/hle/dsp.h
new file mode 100644
index 000000000..14c4000c6
--- /dev/null
+++ b/src/audio_core/hle/dsp.h
@@ -0,0 +1,502 @@
1// Copyright 2016 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 <cstddef>
8#include <type_traits>
9
10#include "audio_core/audio_core.h"
11
12#include "common/bit_field.h"
13#include "common/common_funcs.h"
14#include "common/common_types.h"
15#include "common/swap.h"
16
17namespace DSP {
18namespace HLE {
19
20// The application-accessible region of DSP memory consists of two parts.
21// Both are marked as IO and have Read/Write permissions.
22//
23// First Region: 0x1FF50000 (Size: 0x8000)
24// Second Region: 0x1FF70000 (Size: 0x8000)
25//
26// The DSP reads from each region alternately based on the frame counter for each region much like a
27// double-buffer. The frame counter is located as the very last u16 of each region and is incremented
28// each audio tick.
29
30struct SharedMemory;
31
32constexpr VAddr region0_base = 0x1FF50000;
33extern SharedMemory g_region0;
34
35constexpr VAddr region1_base = 0x1FF70000;
36extern SharedMemory g_region1;
37
38/**
39 * The DSP is native 16-bit. The DSP also appears to be big-endian. When reading 32-bit numbers from
40 * its memory regions, the higher and lower 16-bit halves are swapped compared to the little-endian
41 * layout of the ARM11. Hence from the ARM11's point of view the memory space appears to be
42 * middle-endian.
43 *
44 * Unusually this does not appear to be an issue for floating point numbers. The DSP makes the more
45 * sensible choice of keeping that little-endian. There are also some exceptions such as the
46 * IntermediateMixSamples structure, which is little-endian.
47 *
48 * This struct implements the conversion to and from this middle-endianness.
49 */
50struct u32_dsp {
51 u32_dsp() = default;
52 operator u32() const {
53 return Convert(storage);
54 }
55 void operator=(u32 new_value) {
56 storage = Convert(new_value);
57 }
58private:
59 static constexpr u32 Convert(u32 value) {
60 return (value << 16) | (value >> 16);
61 }
62 u32_le storage;
63};
64#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
65static_assert(std::is_trivially_copyable<u32_dsp>::value, "u32_dsp isn't trivially copyable");
66#endif
67
68// There are 15 structures in each memory region. A table of them in the order they appear in memory
69// is presented below
70//
71// Pipe 2 # First Region DSP Address Purpose Control
72// 5 0x8400 DSP Status DSP
73// 9 0x8410 DSP Debug Info DSP
74// 6 0x8540 Final Mix Samples DSP
75// 2 0x8680 Source Status [24] DSP
76// 8 0x8710 Compressor Table Application
77// 4 0x9430 DSP Configuration Application
78// 7 0x9492 Intermediate Mix Samples DSP + App
79// 1 0x9E92 Source Configuration [24] Application
80// 3 0xA792 Source ADPCM Coefficients [24] Application
81// 10 0xA912 Surround Sound Related
82// 11 0xAA12 Surround Sound Related
83// 12 0xAAD2 Surround Sound Related
84// 13 0xAC52 Surround Sound Related
85// 14 0xAC5C Surround Sound Related
86// 0 0xBFFF Frame Counter Application
87//
88// Note that the above addresses do vary slightly between audio firmwares observed; the addresses are
89// not fixed in stone. The addresses above are only an examplar; they're what this implementation
90// does and provides to applications.
91//
92// Application requests the DSP service to convert DSP addresses into ARM11 virtual addresses using the
93// ConvertProcessAddressFromDspDram service call. Applications seem to derive the addresses for the
94// second region via:
95// second_region_dsp_addr = first_region_dsp_addr | 0x10000
96//
97// Applications maintain most of its own audio state, the memory region is used mainly for
98// communication and not storage of state.
99//
100// In the documentation below, filter and effect transfer functions are specified in the z domain.
101// (If you are more familiar with the Laplace transform, z = exp(sT). The z domain is the digital
102// frequency domain, just like how the s domain is the analog frequency domain.)
103
104#define INSERT_PADDING_DSPWORDS(num_words) INSERT_PADDING_BYTES(2 * (num_words))
105
106// GCC versions < 5.0 do not implement std::is_trivially_copyable.
107// Excluding MSVC because it has weird behaviour for std::is_trivially_copyable.
108#if (__GNUC__ >= 5) || defined(__clang__)
109 #define ASSERT_DSP_STRUCT(name, size) \
110 static_assert(std::is_standard_layout<name>::value, "DSP structure " #name " doesn't use standard layout"); \
111 static_assert(std::is_trivially_copyable<name>::value, "DSP structure " #name " isn't trivially copyable"); \
112 static_assert(sizeof(name) == (size), "Unexpected struct size for DSP structure " #name)
113#else
114 #define ASSERT_DSP_STRUCT(name, size) \
115 static_assert(std::is_standard_layout<name>::value, "DSP structure " #name " doesn't use standard layout"); \
116 static_assert(sizeof(name) == (size), "Unexpected struct size for DSP structure " #name)
117#endif
118
119struct SourceConfiguration {
120 struct Configuration {
121 /// These dirty flags are set by the application when it updates the fields in this struct.
122 /// The DSP clears these each audio frame.
123 union {
124 u32_le dirty_raw;
125
126 BitField<2, 1, u32_le> adpcm_coefficients_dirty;
127 BitField<3, 1, u32_le> partial_embedded_buffer_dirty; ///< Tends to be set when a looped buffer is queued.
128
129 BitField<16, 1, u32_le> enable_dirty;
130 BitField<17, 1, u32_le> interpolation_dirty;
131 BitField<18, 1, u32_le> rate_multiplier_dirty;
132 BitField<19, 1, u32_le> buffer_queue_dirty;
133 BitField<20, 1, u32_le> loop_related_dirty;
134 BitField<21, 1, u32_le> play_position_dirty; ///< Tends to also be set when embedded buffer is updated.
135 BitField<22, 1, u32_le> filters_enabled_dirty;
136 BitField<23, 1, u32_le> simple_filter_dirty;
137 BitField<24, 1, u32_le> biquad_filter_dirty;
138 BitField<25, 1, u32_le> gain_0_dirty;
139 BitField<26, 1, u32_le> gain_1_dirty;
140 BitField<27, 1, u32_le> gain_2_dirty;
141 BitField<28, 1, u32_le> sync_dirty;
142 BitField<29, 1, u32_le> reset_flag;
143
144 BitField<31, 1, u32_le> embedded_buffer_dirty;
145 };
146
147 // Gain control
148
149 /**
150 * Gain is between 0.0-1.0. This determines how much will this source appear on
151 * each of the 12 channels that feed into the intermediate mixers.
152 * Each of the three intermediate mixers is fed two left and two right channels.
153 */
154 float_le gain[3][4];
155
156 // Interpolation
157
158 /// Multiplier for sample rate. Resampling occurs with the selected interpolation method.
159 float_le rate_multiplier;
160
161 enum class InterpolationMode : u8 {
162 None = 0,
163 Linear = 1,
164 Polyphase = 2
165 };
166
167 InterpolationMode interpolation_mode;
168 INSERT_PADDING_BYTES(1); ///< Interpolation related
169
170 // Filters
171
172 /**
173 * This is the simplest normalized first-order digital recursive filter.
174 * The transfer function of this filter is:
175 * H(z) = b0 / (1 + a1 z^-1)
176 * Values are signed fixed point with 15 fractional bits.
177 */
178 struct SimpleFilter {
179 s16_le b0;
180 s16_le a1;
181 };
182
183 /**
184 * This is a normalised biquad filter (second-order).
185 * The transfer function of this filter is:
186 * H(z) = (b0 + b1 z^-1 + b2 z^-2) / (1 - a1 z^-1 - a2 z^-2)
187 * Nintendo chose to negate the feedbackward coefficients. This differs from standard notation
188 * as in: https://ccrma.stanford.edu/~jos/filters/Direct_Form_I.html
189 * Values are signed fixed point with 14 fractional bits.
190 */
191 struct BiquadFilter {
192 s16_le b0;
193 s16_le b1;
194 s16_le b2;
195 s16_le a1;
196 s16_le a2;
197 };
198
199 union {
200 u16_le filters_enabled;
201 BitField<0, 1, u16_le> simple_filter_enabled;
202 BitField<1, 1, u16_le> biquad_filter_enabled;
203 };
204
205 SimpleFilter simple_filter;
206 BiquadFilter biquad_filter;
207
208 // Buffer Queue
209
210 /// A buffer of audio data from the application, along with metadata about it.
211 struct Buffer {
212 /// Physical memory address of the start of the buffer
213 u32_dsp physical_address;
214
215 /// This is length in terms of samples.
216 /// Note that in different buffer formats a sample takes up different number of bytes.
217 u32_dsp length;
218
219 /// ADPCM Predictor (4 bits) and Scale (4 bits)
220 union {
221 u16_le adpcm_ps;
222 BitField<0, 4, u16_le> adpcm_scale;
223 BitField<4, 4, u16_le> adpcm_predictor;
224 };
225
226 /// ADPCM Historical Samples (y[n-1] and y[n-2])
227 u16_le adpcm_yn[2];
228
229 /// This is non-zero when the ADPCM values above are to be updated.
230 u8 adpcm_dirty;
231
232 /// Is a looping buffer.
233 u8 is_looping;
234
235 /// This value is shown in SourceStatus::previous_buffer_id when this buffer has finished.
236 /// This allows the emulated application to tell what buffer is currently playing
237 u16_le buffer_id;
238
239 INSERT_PADDING_DSPWORDS(1);
240 };
241
242 u16_le buffers_dirty; ///< Bitmap indicating which buffers are dirty (bit i -> buffers[i])
243 Buffer buffers[4]; ///< Queued Buffers
244
245 // Playback controls
246
247 u32_dsp loop_related;
248 u8 enable;
249 INSERT_PADDING_BYTES(1);
250 u16_le sync; ///< Application-side sync (See also: SourceStatus::sync)
251 u32_dsp play_position; ///< Position. (Units: number of samples)
252 INSERT_PADDING_DSPWORDS(2);
253
254 // Embedded Buffer
255 // This buffer is often the first buffer to be used when initiating audio playback,
256 // after which the buffer queue is used.
257
258 u32_dsp physical_address;
259
260 /// This is length in terms of samples.
261 /// Note a sample takes up different number of bytes in different buffer formats.
262 u32_dsp length;
263
264 enum class MonoOrStereo : u16_le {
265 Mono = 1,
266 Stereo = 2
267 };
268
269 enum class Format : u16_le {
270 PCM8 = 0,
271 PCM16 = 1,
272 ADPCM = 2
273 };
274
275 union {
276 u16_le flags1_raw;
277 BitField<0, 2, MonoOrStereo> mono_or_stereo;
278 BitField<2, 2, Format> format;
279 BitField<5, 1, u16_le> fade_in;
280 };
281
282 /// ADPCM Predictor (4 bit) and Scale (4 bit)
283 union {
284 u16_le adpcm_ps;
285 BitField<0, 4, u16_le> adpcm_scale;
286 BitField<4, 4, u16_le> adpcm_predictor;
287 };
288
289 /// ADPCM Historical Samples (y[n-1] and y[n-2])
290 u16_le adpcm_yn[2];
291
292 union {
293 u16_le flags2_raw;
294 BitField<0, 1, u16_le> adpcm_dirty; ///< Has the ADPCM info above been changed?
295 BitField<1, 1, u16_le> is_looping; ///< Is this a looping buffer?
296 };
297
298 /// Buffer id of embedded buffer (used as a buffer id in SourceStatus to reference this buffer).
299 u16_le buffer_id;
300 };
301
302 Configuration config[AudioCore::num_sources];
303};
304ASSERT_DSP_STRUCT(SourceConfiguration::Configuration, 192);
305ASSERT_DSP_STRUCT(SourceConfiguration::Configuration::Buffer, 20);
306
307struct SourceStatus {
308 struct Status {
309 u8 is_enabled; ///< Is this channel enabled? (Doesn't have to be playing anything.)
310 u8 previous_buffer_id_dirty; ///< Non-zero when previous_buffer_id changes
311 u16_le sync; ///< Is set by the DSP to the value of SourceConfiguration::sync
312 u32_dsp buffer_position; ///< Number of samples into the current buffer
313 u16_le previous_buffer_id; ///< Updated when a buffer finishes playing
314 INSERT_PADDING_DSPWORDS(1);
315 };
316
317 Status status[AudioCore::num_sources];
318};
319ASSERT_DSP_STRUCT(SourceStatus::Status, 12);
320
321struct DspConfiguration {
322 /// These dirty flags are set by the application when it updates the fields in this struct.
323 /// The DSP clears these each audio frame.
324 union {
325 u32_le dirty_raw;
326
327 BitField<8, 1, u32_le> mixer1_enabled_dirty;
328 BitField<9, 1, u32_le> mixer2_enabled_dirty;
329 BitField<10, 1, u32_le> delay_effect_0_dirty;
330 BitField<11, 1, u32_le> delay_effect_1_dirty;
331 BitField<12, 1, u32_le> reverb_effect_0_dirty;
332 BitField<13, 1, u32_le> reverb_effect_1_dirty;
333
334 BitField<16, 1, u32_le> volume_0_dirty;
335
336 BitField<24, 1, u32_le> volume_1_dirty;
337 BitField<25, 1, u32_le> volume_2_dirty;
338 BitField<26, 1, u32_le> output_format_dirty;
339 BitField<27, 1, u32_le> limiter_enabled_dirty;
340 BitField<28, 1, u32_le> headphones_connected_dirty;
341 };
342
343 /// The DSP has three intermediate audio mixers. This controls the volume level (0.0-1.0) for each at the final mixer
344 float_le volume[3];
345
346 INSERT_PADDING_DSPWORDS(3);
347
348 enum class OutputFormat : u16_le {
349 Mono = 0,
350 Stereo = 1,
351 Surround = 2
352 };
353
354 OutputFormat output_format;
355
356 u16_le limiter_enabled; ///< Not sure of the exact gain equation for the limiter.
357 u16_le headphones_connected; ///< Application updates the DSP on headphone status.
358 INSERT_PADDING_DSPWORDS(4); ///< TODO: Surround sound related
359 INSERT_PADDING_DSPWORDS(2); ///< TODO: Intermediate mixer 1/2 related
360 u16_le mixer1_enabled;
361 u16_le mixer2_enabled;
362
363 /**
364 * This is delay with feedback.
365 * Transfer function:
366 * H(z) = a z^-N / (1 - b z^-1 + a g z^-N)
367 * where
368 * N = frame_count * samples_per_frame
369 * g, a and b are fixed point with 7 fractional bits
370 */
371 struct DelayEffect {
372 /// These dirty flags are set by the application when it updates the fields in this struct.
373 /// The DSP clears these each audio frame.
374 union {
375 u16_le dirty_raw;
376 BitField<0, 1, u16_le> enable_dirty;
377 BitField<1, 1, u16_le> work_buffer_address_dirty;
378 BitField<2, 1, u16_le> other_dirty; ///< Set when anything else has been changed
379 };
380
381 u16_le enable;
382 INSERT_PADDING_DSPWORDS(1);
383 u16_le outputs;
384 u32_dsp work_buffer_address; ///< The application allocates a block of memory for the DSP to use as a work buffer.
385 u16_le frame_count; ///< Frames to delay by
386
387 // Coefficients
388 s16_le g; ///< Fixed point with 7 fractional bits
389 s16_le a; ///< Fixed point with 7 fractional bits
390 s16_le b; ///< Fixed point with 7 fractional bits
391 };
392
393 DelayEffect delay_effect[2];
394
395 struct ReverbEffect {
396 INSERT_PADDING_DSPWORDS(26); ///< TODO
397 };
398
399 ReverbEffect reverb_effect[2];
400
401 INSERT_PADDING_DSPWORDS(4);
402};
403ASSERT_DSP_STRUCT(DspConfiguration, 196);
404ASSERT_DSP_STRUCT(DspConfiguration::DelayEffect, 20);
405ASSERT_DSP_STRUCT(DspConfiguration::ReverbEffect, 52);
406
407struct AdpcmCoefficients {
408 /// Coefficients are signed fixed point with 11 fractional bits.
409 /// Each source has 16 coefficients associated with it.
410 s16_le coeff[AudioCore::num_sources][16];
411};
412ASSERT_DSP_STRUCT(AdpcmCoefficients, 768);
413
414struct DspStatus {
415 u16_le unknown;
416 u16_le dropped_frames;
417 INSERT_PADDING_DSPWORDS(0xE);
418};
419ASSERT_DSP_STRUCT(DspStatus, 32);
420
421/// Final mixed output in PCM16 stereo format, what you hear out of the speakers.
422/// When the application writes to this region it has no effect.
423struct FinalMixSamples {
424 s16_le pcm16[2 * AudioCore::samples_per_frame];
425};
426ASSERT_DSP_STRUCT(FinalMixSamples, 640);
427
428/// DSP writes output of intermediate mixers 1 and 2 here.
429/// Writes to this region by the application edits the output of the intermediate mixers.
430/// This seems to be intended to allow the application to do custom effects on the ARM11.
431/// Values that exceed s16 range will be clipped by the DSP after further processing.
432struct IntermediateMixSamples {
433 struct Samples {
434 s32_le pcm32[4][AudioCore::samples_per_frame]; ///< Little-endian as opposed to DSP middle-endian.
435 };
436
437 Samples mix1;
438 Samples mix2;
439};
440ASSERT_DSP_STRUCT(IntermediateMixSamples, 5120);
441
442/// Compressor table
443struct Compressor {
444 INSERT_PADDING_DSPWORDS(0xD20); ///< TODO
445};
446
447/// There is no easy way to implement this in a HLE implementation.
448struct DspDebug {
449 INSERT_PADDING_DSPWORDS(0x130);
450};
451ASSERT_DSP_STRUCT(DspDebug, 0x260);
452
453struct SharedMemory {
454 /// Padding
455 INSERT_PADDING_DSPWORDS(0x400);
456
457 DspStatus dsp_status;
458
459 DspDebug dsp_debug;
460
461 FinalMixSamples final_samples;
462
463 SourceStatus source_statuses;
464
465 Compressor compressor;
466
467 DspConfiguration dsp_configuration;
468
469 IntermediateMixSamples intermediate_mix_samples;
470
471 SourceConfiguration source_configurations;
472
473 AdpcmCoefficients adpcm_coefficients;
474
475 /// Unknown 10-14 (Surround sound related)
476 INSERT_PADDING_DSPWORDS(0x16ED);
477
478 u16_le frame_counter;
479};
480ASSERT_DSP_STRUCT(SharedMemory, 0x8000);
481
482#undef INSERT_PADDING_DSPWORDS
483#undef ASSERT_DSP_STRUCT
484
485/// Initialize DSP hardware
486void Init();
487
488/// Shutdown DSP hardware
489void Shutdown();
490
491/**
492 * Perform processing and updates state of current shared memory buffer.
493 * This function is called every audio tick before triggering the audio interrupt.
494 * @return Whether an audio interrupt should be triggered this frame.
495 */
496bool Tick();
497
498/// Returns a mutable reference to the current region. Current region is selected based on the frame counter.
499SharedMemory& CurrentRegion();
500
501} // namespace HLE
502} // namespace DSP
diff --git a/src/audio_core/hle/pipe.cpp b/src/audio_core/hle/pipe.cpp
new file mode 100644
index 000000000..6542c760c
--- /dev/null
+++ b/src/audio_core/hle/pipe.cpp
@@ -0,0 +1,55 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <vector>
7
8#include "audio_core/hle/pipe.h"
9
10#include "common/common_types.h"
11#include "common/logging/log.h"
12
13namespace DSP {
14namespace HLE {
15
16static size_t pipe2position = 0;
17
18void ResetPipes() {
19 pipe2position = 0;
20}
21
22std::vector<u8> PipeRead(u32 pipe_number, u32 length) {
23 if (pipe_number != 2) {
24 LOG_WARNING(Audio_DSP, "pipe_number = %u (!= 2), unimplemented", pipe_number);
25 return {}; // We currently don't handle anything other than the audio pipe.
26 }
27
28 // Canned DSP responses that games expect. These were taken from HW by 3dmoo team.
29 // TODO: Our implementation will actually use a slightly different response than this one.
30 // TODO: Use offsetof on DSP structures instead for a proper response.
31 static const std::array<u8, 32> canned_response {{
32 0x0F, 0x00, 0xFF, 0xBF, 0x8E, 0x9E, 0x80, 0x86, 0x8E, 0xA7, 0x30, 0x94, 0x00, 0x84, 0x40, 0x85,
33 0x8E, 0x94, 0x10, 0x87, 0x10, 0x84, 0x0E, 0xA9, 0x0E, 0xAA, 0xCE, 0xAA, 0x4E, 0xAC, 0x58, 0xAC
34 }};
35
36 // TODO: Move this into dsp::DSP service since it happens on the service side.
37 // Hardware observation: No data is returned if requested length reads beyond the end of the data in-pipe.
38 if (pipe2position + length > canned_response.size()) {
39 return {};
40 }
41
42 std::vector<u8> ret;
43 for (size_t i = 0; i < length; i++, pipe2position++) {
44 ret.emplace_back(canned_response[pipe2position]);
45 }
46
47 return ret;
48}
49
50void PipeWrite(u32 pipe_number, const std::vector<u8>& buffer) {
51 // TODO: proper pipe behaviour
52}
53
54} // namespace HLE
55} // namespace DSP
diff --git a/src/audio_core/hle/pipe.h b/src/audio_core/hle/pipe.h
new file mode 100644
index 000000000..ff6536950
--- /dev/null
+++ b/src/audio_core/hle/pipe.h
@@ -0,0 +1,38 @@
1// Copyright 2016 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 <vector>
8
9#include "common/common_types.h"
10
11namespace DSP {
12namespace HLE {
13
14/// Reset the pipes by setting pipe positions back to the beginning.
15void ResetPipes();
16
17/**
18 * Read a DSP pipe.
19 * Pipe IDs:
20 * pipe_number = 0: Debug
21 * pipe_number = 1: P-DMA
22 * pipe_number = 2: Audio
23 * pipe_number = 3: Binary
24 * @param pipe_number The Pipe ID
25 * @param length How much data to request.
26 * @return The data read from the pipe. The size of this vector can be less than the length requested.
27 */
28std::vector<u8> PipeRead(u32 pipe_number, u32 length);
29
30/**
31 * Write to a DSP pipe.
32 * @param pipe_number The Pipe ID
33 * @param buffer The data to write to the pipe.
34 */
35void PipeWrite(u32 pipe_number, const std::vector<u8>& buffer);
36
37} // namespace HLE
38} // namespace DSP
diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h
new file mode 100644
index 000000000..cad21a85e
--- /dev/null
+++ b/src/audio_core/sink.h
@@ -0,0 +1,34 @@
1// Copyright 2016 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 <vector>
8
9#include "common/common_types.h"
10
11namespace AudioCore {
12
13/**
14 * This class is an interface for an audio sink. An audio sink accepts samples in stereo signed PCM16 format to be output.
15 * Sinks *do not* handle resampling and expect the correct sample rate. They are dumb outputs.
16 */
17class Sink {
18public:
19 virtual ~Sink() = default;
20
21 /// The native rate of this sink. The sink expects to be fed samples that respect this. (Units: samples/sec)
22 virtual unsigned GetNativeSampleRate() const = 0;
23
24 /**
25 * Feed stereo samples to sink.
26 * @param samples Samples in interleaved stereo PCM16 format. Size of vector must be multiple of two.
27 */
28 virtual void EnqueueSamples(const std::vector<s16>& samples) = 0;
29
30 /// Samples enqueued that have not been played yet.
31 virtual std::size_t SamplesInQueue() const = 0;
32};
33
34} // namespace
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt
index e7f8a17f9..b9abb818e 100644
--- a/src/citra/CMakeLists.txt
+++ b/src/citra/CMakeLists.txt
@@ -17,7 +17,7 @@ include_directories(${GLFW_INCLUDE_DIRS})
17link_directories(${GLFW_LIBRARY_DIRS}) 17link_directories(${GLFW_LIBRARY_DIRS})
18 18
19add_executable(citra ${SRCS} ${HEADERS}) 19add_executable(citra ${SRCS} ${HEADERS})
20target_link_libraries(citra core video_core common) 20target_link_libraries(citra core video_core audio_core common)
21target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih glad) 21target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih glad)
22if (MSVC) 22if (MSVC)
23 target_link_libraries(citra getopt) 23 target_link_libraries(citra getopt)
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index bbf6ae001..b3d1205a4 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -79,7 +79,7 @@ if (APPLE)
79else() 79else()
80 add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) 80 add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS})
81endif() 81endif()
82target_link_libraries(citra-qt core video_core common qhexedit) 82target_link_libraries(citra-qt core video_core audio_core common qhexedit)
83target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) 83target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS})
84target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) 84target_link_libraries(citra-qt ${PLATFORM_LIBRARIES})
85 85
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 144f11117..da9ea6c91 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -171,6 +171,8 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
171 } 171 }
172 UpdateRecentFiles(); 172 UpdateRecentFiles();
173 173
174 confirm_before_closing = settings.value("confirmClose", true).toBool();
175
174 // Setup connections 176 // Setup connections
175 connect(game_list, SIGNAL(GameChosen(QString)), this, SLOT(OnGameListLoadFile(QString))); 177 connect(game_list, SIGNAL(GameChosen(QString)), this, SLOT(OnGameListLoadFile(QString)));
176 connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile())); 178 connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile()));
@@ -497,7 +499,22 @@ void GMainWindow::OnConfigure() {
497 //GControllerConfigDialog* dialog = new GControllerConfigDialog(controller_ports, this); 499 //GControllerConfigDialog* dialog = new GControllerConfigDialog(controller_ports, this);
498} 500}
499 501
502bool GMainWindow::ConfirmClose() {
503 if (emu_thread == nullptr || !confirm_before_closing)
504 return true;
505
506 auto answer = QMessageBox::question(this, tr("Citra"),
507 tr("Are you sure you want to close Citra?"),
508 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
509 return answer != QMessageBox::No;
510}
511
500void GMainWindow::closeEvent(QCloseEvent* event) { 512void GMainWindow::closeEvent(QCloseEvent* event) {
513 if (!ConfirmClose()) {
514 event->ignore();
515 return;
516 }
517
501 // Save window layout 518 // Save window layout
502 QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Citra team", "Citra"); 519 QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Citra team", "Citra");
503 520
@@ -512,6 +529,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
512 settings.setValue("singleWindowMode", ui.action_Single_Window_Mode->isChecked()); 529 settings.setValue("singleWindowMode", ui.action_Single_Window_Mode->isChecked());
513 settings.setValue("displayTitleBars", ui.actionDisplay_widget_title_bars->isChecked()); 530 settings.setValue("displayTitleBars", ui.actionDisplay_widget_title_bars->isChecked());
514 settings.setValue("firstStart", false); 531 settings.setValue("firstStart", false);
532 settings.setValue("confirmClose", confirm_before_closing);
515 game_list->SaveInterfaceLayout(settings); 533 game_list->SaveInterfaceLayout(settings);
516 SaveHotkeys(settings); 534 SaveHotkeys(settings);
517 535
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index f6d429cd9..8c195f816 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -82,6 +82,13 @@ private:
82 */ 82 */
83 void UpdateRecentFiles(); 83 void UpdateRecentFiles();
84 84
85 /**
86 * If the emulation is running,
87 * asks the user if he really want to close the emulator
88 *
89 * @return true if the user confirmed
90 */
91 bool ConfirmClose();
85 void closeEvent(QCloseEvent* event) override; 92 void closeEvent(QCloseEvent* event) override;
86 93
87private slots: 94private slots:
@@ -122,6 +129,7 @@ private:
122 GPUCommandListWidget* graphicsCommandsWidget; 129 GPUCommandListWidget* graphicsCommandsWidget;
123 130
124 QAction* actions_recent_files[max_recent_files_item]; 131 QAction* actions_recent_files[max_recent_files_item];
132 bool confirm_before_closing;
125}; 133};
126 134
127#endif // _CITRA_QT_MAIN_HXX_ 135#endif // _CITRA_QT_MAIN_HXX_
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 66689f398..371eb17a1 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -115,29 +115,24 @@ template<std::size_t position, std::size_t bits, typename T>
115struct BitField 115struct BitField
116{ 116{
117private: 117private:
118 // This constructor might be considered ambiguous: 118 // We hide the copy assigment operator here, because the default copy
119 // Would it initialize the storage or just the bitfield? 119 // assignment would copy the full storage value, rather than just the bits
120 // Hence, delete it. Use the assignment operator to set bitfield values! 120 // relevant to this particular bit field.
121 BitField(T val) = delete; 121 // We don't delete it because we want BitField to be trivially copyable.
122 BitField& operator=(const BitField&) = default;
122 123
123public: 124public:
125 // This constructor and assignment operator might be considered ambiguous:
126 // Would they initialize the storage or just the bitfield?
127 // Hence, delete them. Use the Assign method to set bitfield values!
128 BitField(T val) = delete;
129 BitField& operator=(T val) = delete;
130
124 // Force default constructor to be created 131 // Force default constructor to be created
125 // so that we can use this within unions 132 // so that we can use this within unions
126 BitField() = default; 133 BitField() = default;
127 134
128 // We explicitly delete the copy assigment operator here, because the 135 FORCE_INLINE operator T() const {
129 // default copy assignment would copy the full storage value, rather than
130 // just the bits relevant to this particular bit field.
131 BitField& operator=(const BitField&) = delete;
132
133 FORCE_INLINE BitField& operator=(T val)
134 {
135 Assign(val);
136 return *this;
137 }
138
139 FORCE_INLINE operator T() const
140 {
141 return Value(); 136 return Value();
142 } 137 }
143 138
@@ -145,8 +140,7 @@ public:
145 storage = (storage & ~GetMask()) | (((StorageType)value << position) & GetMask()); 140 storage = (storage & ~GetMask()) | (((StorageType)value << position) & GetMask());
146 } 141 }
147 142
148 FORCE_INLINE T Value() const 143 FORCE_INLINE T Value() const {
149 {
150 if (std::numeric_limits<T>::is_signed) 144 if (std::numeric_limits<T>::is_signed)
151 { 145 {
152 std::size_t shift = 8 * sizeof(T)-bits; 146 std::size_t shift = 8 * sizeof(T)-bits;
@@ -159,8 +153,7 @@ public:
159 } 153 }
160 154
161 // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015 155 // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015
162 FORCE_INLINE bool ToBool() const 156 FORCE_INLINE bool ToBool() const {
163 {
164 return Value() != 0; 157 return Value() != 0;
165 } 158 }
166 159
@@ -176,8 +169,7 @@ private:
176 // Unsigned version of StorageType 169 // Unsigned version of StorageType
177 typedef typename std::make_unsigned<StorageType>::type StorageTypeU; 170 typedef typename std::make_unsigned<StorageType>::type StorageTypeU;
178 171
179 FORCE_INLINE StorageType GetMask() const 172 FORCE_INLINE StorageType GetMask() const {
180 {
181 return (((StorageTypeU)~0) >> (8 * sizeof(T)-bits)) << position; 173 return (((StorageTypeU)~0) >> (8 * sizeof(T)-bits)) << position;
182 } 174 }
183 175
@@ -189,6 +181,10 @@ private:
189 static_assert(position < 8 * sizeof(T), "Invalid position"); 181 static_assert(position < 8 * sizeof(T), "Invalid position");
190 static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); 182 static_assert(bits <= 8 * sizeof(T), "Invalid number of bits");
191 static_assert(bits > 0, "Invalid number of bits"); 183 static_assert(bits > 0, "Invalid number of bits");
192 static_assert(std::is_standard_layout<T>::value, "Invalid base type"); 184 static_assert(std::is_pod<T>::value, "Invalid base type");
193}; 185};
194#pragma pack() 186#pragma pack()
187
188#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
189static_assert(std::is_trivially_copyable<BitField<0, 1, u32>>::value, "BitField must be trivially copyable");
190#endif
diff --git a/src/common/color.h b/src/common/color.h
index eb199e308..908879ea6 100644
--- a/src/common/color.h
+++ b/src/common/color.h
@@ -11,42 +11,42 @@
11namespace Color { 11namespace Color {
12 12
13/// Convert a 1-bit color component to 8 bit 13/// Convert a 1-bit color component to 8 bit
14inline u8 Convert1To8(u8 value) { 14constexpr u8 Convert1To8(u8 value) {
15 return value * 255; 15 return value * 255;
16} 16}
17 17
18/// Convert a 4-bit color component to 8 bit 18/// Convert a 4-bit color component to 8 bit
19inline u8 Convert4To8(u8 value) { 19constexpr u8 Convert4To8(u8 value) {
20 return (value << 4) | value; 20 return (value << 4) | value;
21} 21}
22 22
23/// Convert a 5-bit color component to 8 bit 23/// Convert a 5-bit color component to 8 bit
24inline u8 Convert5To8(u8 value) { 24constexpr u8 Convert5To8(u8 value) {
25 return (value << 3) | (value >> 2); 25 return (value << 3) | (value >> 2);
26} 26}
27 27
28/// Convert a 6-bit color component to 8 bit 28/// Convert a 6-bit color component to 8 bit
29inline u8 Convert6To8(u8 value) { 29constexpr u8 Convert6To8(u8 value) {
30 return (value << 2) | (value >> 4); 30 return (value << 2) | (value >> 4);
31} 31}
32 32
33/// Convert a 8-bit color component to 1 bit 33/// Convert a 8-bit color component to 1 bit
34inline u8 Convert8To1(u8 value) { 34constexpr u8 Convert8To1(u8 value) {
35 return value >> 7; 35 return value >> 7;
36} 36}
37 37
38/// Convert a 8-bit color component to 4 bit 38/// Convert a 8-bit color component to 4 bit
39inline u8 Convert8To4(u8 value) { 39constexpr u8 Convert8To4(u8 value) {
40 return value >> 4; 40 return value >> 4;
41} 41}
42 42
43/// Convert a 8-bit color component to 5 bit 43/// Convert a 8-bit color component to 5 bit
44inline u8 Convert8To5(u8 value) { 44constexpr u8 Convert8To5(u8 value) {
45 return value >> 3; 45 return value >> 3;
46} 46}
47 47
48/// Convert a 8-bit color component to 6 bit 48/// Convert a 8-bit color component to 6 bit
49inline u8 Convert8To6(u8 value) { 49constexpr u8 Convert8To6(u8 value) {
50 return value >> 2; 50 return value >> 2;
51} 51}
52 52
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index b69b05cb9..b2807354a 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -55,14 +55,14 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
55 (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); 55 (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top);
56 56
57 touch_pressed = true; 57 touch_pressed = true;
58 pad_state.touch = 1; 58 pad_state.touch.Assign(1);
59} 59}
60 60
61void EmuWindow::TouchReleased() { 61void EmuWindow::TouchReleased() {
62 touch_pressed = false; 62 touch_pressed = false;
63 touch_x = 0; 63 touch_x = 0;
64 touch_y = 0; 64 touch_y = 0;
65 pad_state.touch = 0; 65 pad_state.touch.Assign(0);
66} 66}
67 67
68void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { 68void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
diff --git a/src/common/key_map.h b/src/common/key_map.h
index 0ecec714f..68f7e2f99 100644
--- a/src/common/key_map.h
+++ b/src/common/key_map.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <tuple>
7#include "core/hle/service/hid/hid.h" 8#include "core/hle/service/hid/hid.h"
8 9
9namespace KeyMap { 10namespace KeyMap {
@@ -15,15 +16,14 @@ struct HostDeviceKey {
15 int key_code; 16 int key_code;
16 int device_id; ///< Uniquely identifies a host device 17 int device_id; ///< Uniquely identifies a host device
17 18
18 bool operator < (const HostDeviceKey &other) const { 19 bool operator<(const HostDeviceKey &other) const {
19 if (device_id == other.device_id) { 20 return std::tie(key_code, device_id) <
20 return key_code < other.key_code; 21 std::tie(other.key_code, other.device_id);
21 }
22 return device_id < other.device_id;
23 } 22 }
24 23
25 bool operator == (const HostDeviceKey &other) const { 24 bool operator==(const HostDeviceKey &other) const {
26 return device_id == other.device_id && key_code == other.key_code; 25 return std::tie(key_code, device_id) ==
26 std::tie(other.key_code, other.device_id);
27 } 27 }
28}; 28};
29 29
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index d186ba8f8..54291429a 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -49,6 +49,7 @@ namespace Log {
49 SUB(Service, DSP) \ 49 SUB(Service, DSP) \
50 SUB(Service, HID) \ 50 SUB(Service, HID) \
51 SUB(Service, SOC) \ 51 SUB(Service, SOC) \
52 SUB(Service, IR) \
52 SUB(Service, Y2R) \ 53 SUB(Service, Y2R) \
53 CLS(HW) \ 54 CLS(HW) \
54 SUB(HW, Memory) \ 55 SUB(HW, Memory) \
@@ -58,6 +59,8 @@ namespace Log {
58 CLS(Render) \ 59 CLS(Render) \
59 SUB(Render, Software) \ 60 SUB(Render, Software) \
60 SUB(Render, OpenGL) \ 61 SUB(Render, OpenGL) \
62 CLS(Audio) \
63 SUB(Audio, DSP) \
61 CLS(Loader) 64 CLS(Loader)
62 65
63// GetClassName is a macro defined by Windows.h, grrr... 66// GetClassName is a macro defined by Windows.h, grrr...
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index c1f4d08e4..795d42ebd 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -27,25 +27,9 @@ struct Entry {
27 std::string message; 27 std::string message;
28 28
29 Entry() = default; 29 Entry() = default;
30 Entry(Entry&& o) = default;
30 31
31 // TODO(yuriks) Use defaulted move constructors once MSVC supports them 32 Entry& operator=(Entry&& o) = default;
32#define MOVE(member) member(std::move(o.member))
33 Entry(Entry&& o)
34 : MOVE(timestamp), MOVE(log_class), MOVE(log_level),
35 MOVE(location), MOVE(message)
36 {}
37#undef MOVE
38
39 Entry& operator=(const Entry&& o) {
40#define MOVE(member) member = std::move(o.member)
41 MOVE(timestamp);
42 MOVE(log_class);
43 MOVE(log_level);
44 MOVE(location);
45 MOVE(message);
46#undef MOVE
47 return *this;
48 }
49}; 33};
50 34
51/** 35/**
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 2d9323a7b..4b01805ae 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -64,6 +64,7 @@ enum class Class : ClassType {
64 Service_DSP, ///< The DSP (DSP control) service 64 Service_DSP, ///< The DSP (DSP control) service
65 Service_HID, ///< The HID (Human interface device) service 65 Service_HID, ///< The HID (Human interface device) service
66 Service_SOC, ///< The SOC (Socket) service 66 Service_SOC, ///< The SOC (Socket) service
67 Service_IR, ///< The IR service
67 Service_Y2R, ///< The Y2R (YUV to RGB conversion) service 68 Service_Y2R, ///< The Y2R (YUV to RGB conversion) service
68 HW, ///< Low-level hardware emulation 69 HW, ///< Low-level hardware emulation
69 HW_Memory, ///< Memory-map and address translation 70 HW_Memory, ///< Memory-map and address translation
@@ -73,6 +74,8 @@ enum class Class : ClassType {
73 Render, ///< Emulator video output and hardware acceleration 74 Render, ///< Emulator video output and hardware acceleration
74 Render_Software, ///< Software renderer backend 75 Render_Software, ///< Software renderer backend
75 Render_OpenGL, ///< OpenGL backend 76 Render_OpenGL, ///< OpenGL backend
77 Audio, ///< Emulator audio output
78 Audio_DSP, ///< The HLE implementation of the DSP
76 Loader, ///< ROM loader 79 Loader, ///< ROM loader
77 80
78 Count ///< Total number of logging classes 81 Count ///< Total number of logging classes
diff --git a/src/common/x64/emitter.cpp b/src/common/x64/emitter.cpp
index 939df210e..1dcf2416c 100644
--- a/src/common/x64/emitter.cpp
+++ b/src/common/x64/emitter.cpp
@@ -225,14 +225,14 @@ void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp
225 // do we need any VEX fields that only appear in the three-byte form? 225 // do we need any VEX fields that only appear in the three-byte form?
226 if (X == 1 && B == 1 && W == 0 && mmmmm == 1) 226 if (X == 1 && B == 1 && W == 0 && mmmmm == 1)
227 { 227 {
228 u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 1) | pp; 228 u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 2) | pp;
229 emit->Write8(0xC5); 229 emit->Write8(0xC5);
230 emit->Write8(RvvvvLpp); 230 emit->Write8(RvvvvLpp);
231 } 231 }
232 else 232 else
233 { 233 {
234 u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm; 234 u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm;
235 u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 1) | pp; 235 u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 2) | pp;
236 emit->Write8(0xC4); 236 emit->Write8(0xC4);
237 emit->Write8(RXBmmmmm); 237 emit->Write8(RXBmmmmm);
238 emit->Write8(WvvvvLpp); 238 emit->Write8(WvvvvLpp);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 861b711c7..edf5fcc44 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -250,6 +250,7 @@ set(HEADERS
250 tracer/citrace.h 250 tracer/citrace.h
251 memory.h 251 memory.h
252 memory_setup.h 252 memory_setup.h
253 mmio.h
253 settings.h 254 settings.h
254 system.h 255 system.h
255 ) 256 )
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp
index 76408e9fa..5ad1f1c29 100644
--- a/src/core/arm/disassembler/arm_disasm.cpp
+++ b/src/core/arm/disassembler/arm_disasm.cpp
@@ -738,23 +738,23 @@ std::string ARM_Disasm::DisassembleMemHalf(u32 insn)
738 if (is_immed) { 738 if (is_immed) {
739 if (is_pre) { 739 if (is_pre) {
740 if (offset == 0) { 740 if (offset == 0) {
741 return Common::StringFromFormat("%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn); 741 return Common::StringFromFormat("%s%s%s\tr%d, [r%d]", opname, cond_to_str(cond), width, rd, rn);
742 } else { 742 } else {
743 return Common::StringFromFormat("%s%sh\tr%d, [r%d, #%s%u]%s", 743 return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s",
744 opname, cond_to_str(cond), rd, rn, minus, offset, bang); 744 opname, cond_to_str(cond), width, rd, rn, minus, offset, bang);
745 } 745 }
746 } else { 746 } else {
747 return Common::StringFromFormat("%s%sh\tr%d, [r%d], #%s%u", 747 return Common::StringFromFormat("%s%s%s\tr%d, [r%d], #%s%u",
748 opname, cond_to_str(cond), rd, rn, minus, offset); 748 opname, cond_to_str(cond), width, rd, rn, minus, offset);
749 } 749 }
750 } 750 }
751 751
752 if (is_pre) { 752 if (is_pre) {
753 return Common::StringFromFormat("%s%sh\tr%d, [r%d, %sr%d]%s", 753 return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s",
754 opname, cond_to_str(cond), rd, rn, minus, rm, bang); 754 opname, cond_to_str(cond), width, rd, rn, minus, rm, bang);
755 } else { 755 } else {
756 return Common::StringFromFormat("%s%sh\tr%d, [r%d], %sr%d", 756 return Common::StringFromFormat("%s%s%s\tr%d, [r%d], %sr%d",
757 opname, cond_to_str(cond), rd, rn, minus, rm); 757 opname, cond_to_str(cond), width, rd, rn, minus, rm);
758 } 758 }
759} 759}
760 760
diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/archive_backend.cpp
index 3f81447df..97adf0e12 100644
--- a/src/core/file_sys/archive_backend.cpp
+++ b/src/core/file_sys/archive_backend.cpp
@@ -43,7 +43,7 @@ Path::Path(LowPathType type, u32 size, u32 pointer) : type(type) {
43 } 43 }
44} 44}
45 45
46const std::string Path::DebugStr() const { 46std::string Path::DebugStr() const {
47 switch (GetType()) { 47 switch (GetType()) {
48 case Invalid: 48 case Invalid:
49 default: 49 default:
@@ -66,7 +66,7 @@ const std::string Path::DebugStr() const {
66 } 66 }
67} 67}
68 68
69const std::string Path::AsString() const { 69std::string Path::AsString() const {
70 switch (GetType()) { 70 switch (GetType()) {
71 case Char: 71 case Char:
72 return string; 72 return string;
@@ -83,7 +83,7 @@ const std::string Path::AsString() const {
83 } 83 }
84} 84}
85 85
86const std::u16string Path::AsU16Str() const { 86std::u16string Path::AsU16Str() const {
87 switch (GetType()) { 87 switch (GetType()) {
88 case Char: 88 case Char:
89 return Common::UTF8ToUTF16(string); 89 return Common::UTF8ToUTF16(string);
@@ -99,7 +99,7 @@ const std::u16string Path::AsU16Str() const {
99 } 99 }
100} 100}
101 101
102const std::vector<u8> Path::AsBinary() const { 102std::vector<u8> Path::AsBinary() const {
103 switch (GetType()) { 103 switch (GetType()) {
104 case Binary: 104 case Binary:
105 return binary; 105 return binary;
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index e7a59a1ed..601e95d8c 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -49,11 +49,11 @@ public:
49 * Gets the string representation of the path for debugging 49 * Gets the string representation of the path for debugging
50 * @return String representation of the path for debugging 50 * @return String representation of the path for debugging
51 */ 51 */
52 const std::string DebugStr() const; 52 std::string DebugStr() const;
53 53
54 const std::string AsString() const; 54 std::string AsString() const;
55 const std::u16string AsU16Str() const; 55 std::u16string AsU16Str() const;
56 const std::vector<u8> AsBinary() const; 56 std::vector<u8> AsBinary() const;
57 57
58private: 58private:
59 LowPathType type; 59 LowPathType type;
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
index 0cfb43fc7..862643448 100644
--- a/src/core/hle/kernel/memory.cpp
+++ b/src/core/hle/kernel/memory.cpp
@@ -7,6 +7,8 @@
7#include <utility> 7#include <utility>
8#include <vector> 8#include <vector>
9 9
10#include "audio_core/audio_core.h"
11
10#include "common/common_types.h" 12#include "common/common_types.h"
11#include "common/logging/log.h" 13#include "common/logging/log.h"
12 14
@@ -107,7 +109,6 @@ struct MemoryArea {
107static MemoryArea memory_areas[] = { 109static MemoryArea memory_areas[] = {
108 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory 110 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
109 {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM) 111 {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
110 {DSP_RAM_VADDR, DSP_RAM_SIZE, "DSP RAM"}, // DSP memory
111 {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory 112 {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory
112}; 113};
113 114
@@ -133,6 +134,8 @@ void InitLegacyAddressSpace(Kernel::VMManager& address_space) {
133 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR, 134 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
134 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom(); 135 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
135 address_space.Reprotect(shared_page_vma, VMAPermission::Read); 136 address_space.Reprotect(shared_page_vma, VMAPermission::Read);
137
138 AudioCore::AddAddressSpace(address_space);
136} 139}
137 140
138} // namespace 141} // namespace
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index d148efde2..16eb972fb 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -35,7 +35,7 @@ SharedPtr<Process> Process::Create(SharedPtr<CodeSet> code_set) {
35 35
36 process->codeset = std::move(code_set); 36 process->codeset = std::move(code_set);
37 process->flags.raw = 0; 37 process->flags.raw = 0;
38 process->flags.memory_region = MemoryRegion::APPLICATION; 38 process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
39 Memory::InitLegacyAddressSpace(process->vm_manager); 39 Memory::InitLegacyAddressSpace(process->vm_manager);
40 40
41 return process; 41 return process;
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 2610acf76..1e289f38a 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -8,6 +8,7 @@
8 8
9#include "core/hle/kernel/vm_manager.h" 9#include "core/hle/kernel/vm_manager.h"
10#include "core/memory_setup.h" 10#include "core/memory_setup.h"
11#include "core/mmio.h"
11 12
12namespace Kernel { 13namespace Kernel {
13 14
@@ -104,7 +105,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * m
104 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); 105 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
105} 106}
106 107
107ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state) { 108ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, Memory::MMIORegionPointer mmio_handler) {
108 // This is the appropriately sized VMA that will turn into our allocation. 109 // This is the appropriately sized VMA that will turn into our allocation.
109 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size)); 110 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
110 VirtualMemoryArea& final_vma = vma_handle->second; 111 VirtualMemoryArea& final_vma = vma_handle->second;
@@ -114,6 +115,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u3
114 final_vma.permissions = VMAPermission::ReadWrite; 115 final_vma.permissions = VMAPermission::ReadWrite;
115 final_vma.meminfo_state = state; 116 final_vma.meminfo_state = state;
116 final_vma.paddr = paddr; 117 final_vma.paddr = paddr;
118 final_vma.mmio_handler = mmio_handler;
117 UpdatePageTableForVMA(final_vma); 119 UpdatePageTableForVMA(final_vma);
118 120
119 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); 121 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
@@ -330,8 +332,7 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
330 Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory); 332 Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory);
331 break; 333 break;
332 case VMAType::MMIO: 334 case VMAType::MMIO:
333 // TODO(yuriks): Add support for MMIO handlers. 335 Memory::MapIoRegion(vma.base, vma.size, vma.mmio_handler);
334 Memory::MapIoRegion(vma.base, vma.size);
335 break; 336 break;
336 } 337 }
337} 338}
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 4e95f1f0c..91d40655b 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -11,6 +11,7 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12 12
13#include "core/hle/result.h" 13#include "core/hle/result.h"
14#include "core/mmio.h"
14 15
15namespace Kernel { 16namespace Kernel {
16 17
@@ -92,6 +93,7 @@ struct VirtualMemoryArea {
92 // Settings for type = MMIO 93 // Settings for type = MMIO
93 /// Physical address of the register area this VMA maps to. 94 /// Physical address of the register area this VMA maps to.
94 PAddr paddr = 0; 95 PAddr paddr = 0;
96 Memory::MMIORegionPointer mmio_handler = nullptr;
95 97
96 /// Tests if this area can be merged to the right with `next`. 98 /// Tests if this area can be merged to the right with `next`.
97 bool CanBeMergedWith(const VirtualMemoryArea& next) const; 99 bool CanBeMergedWith(const VirtualMemoryArea& next) const;
@@ -168,8 +170,9 @@ public:
168 * @param paddr The physical address where the registers are present. 170 * @param paddr The physical address where the registers are present.
169 * @param size Size of the mapping. 171 * @param size Size of the mapping.
170 * @param state MemoryState tag to attach to the VMA. 172 * @param state MemoryState tag to attach to the VMA.
173 * @param mmio_handler The handler that will implement read and write for this MMIO region.
171 */ 174 */
172 ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state); 175 ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, Memory::MMIORegionPointer mmio_handler);
173 176
174 /// Unmaps a range of addresses, splitting VMAs as necessary. 177 /// Unmaps a range of addresses, splitting VMAs as necessary.
175 ResultCode UnmapRange(VAddr target, u32 size); 178 ResultCode UnmapRange(VAddr target, u32 size);
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index ea3abb5f6..0fce5988b 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -193,10 +193,10 @@ union ResultCode {
193 explicit ResultCode(u32 raw) : raw(raw) {} 193 explicit ResultCode(u32 raw) : raw(raw) {}
194 ResultCode(ErrorDescription description_, ErrorModule module_, 194 ResultCode(ErrorDescription description_, ErrorModule module_,
195 ErrorSummary summary_, ErrorLevel level_) : raw(0) { 195 ErrorSummary summary_, ErrorLevel level_) : raw(0) {
196 description = description_; 196 description.Assign(description_);
197 module = module_; 197 module.Assign(module_);
198 summary = summary_; 198 summary.Assign(summary_);
199 level = level_; 199 level.Assign(level_);
200 } 200 }
201 201
202 ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; } 202 ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; }
diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp
index f8aab6bc7..c48259e13 100644
--- a/src/core/hle/service/ac_u.cpp
+++ b/src/core/hle/service/ac_u.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/ac_u.h" 6#include "core/hle/service/ac_u.h"
8 7
9//////////////////////////////////////////////////////////////////////////////////////////////////// 8////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/act_u.cpp b/src/core/hle/service/act_u.cpp
index bbe8e1625..b23d17fba 100644
--- a/src/core/hle/service/act_u.cpp
+++ b/src/core/hle/service/act_u.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/act_u.h" 5#include "core/hle/service/act_u.h"
7 6
8//////////////////////////////////////////////////////////////////////////////////////////////////// 7////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 7ae4859a7..06be9940e 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -10,10 +10,6 @@
10#include "core/hle/service/am/am_net.h" 10#include "core/hle/service/am/am_net.h"
11#include "core/hle/service/am/am_sys.h" 11#include "core/hle/service/am/am_sys.h"
12 12
13#include "core/hle/hle.h"
14#include "core/hle/kernel/event.h"
15#include "core/hle/kernel/shared_memory.h"
16
17namespace Service { 13namespace Service {
18namespace AM { 14namespace AM {
19 15
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 0b78f5393..15e63bc7b 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -4,10 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service { 7namespace Service {
8
9class Interface;
10
11namespace AM { 11namespace AM {
12 12
13/** 13/**
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp
index f40a87cb4..16c76a1eb 100644
--- a/src/core/hle/service/am/am_app.cpp
+++ b/src/core/hle/service/am/am_app.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/am/am.h" 5#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/am_app.h" 6#include "core/hle/service/am/am_app.h"
8 7
diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp
index 7515a4e6e..065e04118 100644
--- a/src/core/hle/service/am/am_net.cpp
+++ b/src/core/hle/service/am/am_net.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/am/am.h" 5#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/am_net.h" 6#include "core/hle/service/am/am_net.h"
8 7
diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp
index 715b7b55d..e38812297 100644
--- a/src/core/hle/service/am/am_sys.cpp
+++ b/src/core/hle/service/am/am_sys.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/am/am.h" 5#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/am_sys.h" 6#include "core/hle/service/am/am_sys.h"
8 7
diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp
index b1e1ea5e4..c0392b754 100644
--- a/src/core/hle/service/am/am_u.cpp
+++ b/src/core/hle/service/am/am_u.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/am/am.h" 5#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/am_u.h" 6#include "core/hle/service/am/am_u.h"
8 7
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index ba66569b4..69255e2ef 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -13,12 +13,10 @@
13#include "core/hle/service/apt/apt_s.h" 13#include "core/hle/service/apt/apt_s.h"
14#include "core/hle/service/apt/apt_u.h" 14#include "core/hle/service/apt/apt_u.h"
15 15
16#include "core/hle/hle.h"
17#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/event.h"
18#include "core/hle/kernel/mutex.h" 17#include "core/hle/kernel/mutex.h"
19#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
20#include "core/hle/kernel/shared_memory.h" 19#include "core/hle/kernel/shared_memory.h"
21#include "core/hle/kernel/thread.h"
22 20
23namespace Service { 21namespace Service {
24namespace APT { 22namespace APT {
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index 22800c56f..0c6a77305 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/apt/apt.h" 5#include "core/hle/service/apt/apt.h"
7#include "core/hle/service/apt/apt_a.h" 6#include "core/hle/service/apt/apt_a.h"
8 7
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp
index e5fd9165c..7f6e81a63 100644
--- a/src/core/hle/service/apt/apt_s.cpp
+++ b/src/core/hle/service/apt/apt_s.cpp
@@ -2,8 +2,6 @@
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
6#include "core/hle/hle.h"
7#include "core/hle/service/apt/apt.h" 5#include "core/hle/service/apt/apt.h"
8#include "core/hle/service/apt/apt_s.h" 6#include "core/hle/service/apt/apt_s.h"
9 7
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index aba627f54..209a0055b 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -2,9 +2,6 @@
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
6#include "common/file_util.h"
7
8#include "core/hle/service/apt/apt.h" 5#include "core/hle/service/apt/apt.h"
9#include "core/hle/service/apt/apt_u.h" 6#include "core/hle/service/apt/apt_u.h"
10 7
diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp
index d38140f19..419ec976e 100644
--- a/src/core/hle/service/boss/boss.cpp
+++ b/src/core/hle/service/boss/boss.cpp
@@ -7,10 +7,6 @@
7#include "core/hle/service/boss/boss_p.h" 7#include "core/hle/service/boss/boss_p.h"
8#include "core/hle/service/boss/boss_u.h" 8#include "core/hle/service/boss/boss_u.h"
9 9
10#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/shared_memory.h"
12#include "core/hle/hle.h"
13
14namespace Service { 10namespace Service {
15namespace BOSS { 11namespace BOSS {
16 12
diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h
index a6942ada6..d3b5d7101 100644
--- a/src/core/hle/service/boss/boss.h
+++ b/src/core/hle/service/boss/boss.h
@@ -4,9 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service { 7namespace Service {
11namespace BOSS { 8namespace BOSS {
12 9
diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp
index 089f5f186..c498abe4e 100644
--- a/src/core/hle/service/boss/boss_p.cpp
+++ b/src/core/hle/service/boss/boss_p.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/boss/boss.h"
7#include "core/hle/service/boss/boss_p.h" 5#include "core/hle/service/boss/boss_p.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/boss/boss_u.cpp b/src/core/hle/service/boss/boss_u.cpp
index 9f17711bb..d59babe71 100644
--- a/src/core/hle/service/boss/boss_u.cpp
+++ b/src/core/hle/service/boss/boss_u.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/boss/boss.h"
7#include "core/hle/service/boss/boss_u.h" 5#include "core/hle/service/boss/boss_u.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index 4f34b699b..360bcfca4 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -11,10 +11,6 @@
11#include "core/hle/service/cam/cam_s.h" 11#include "core/hle/service/cam/cam_s.h"
12#include "core/hle/service/cam/cam_u.h" 12#include "core/hle/service/cam/cam_u.h"
13 13
14#include "core/hle/kernel/event.h"
15#include "core/hle/kernel/shared_memory.h"
16#include "core/hle/hle.h"
17
18namespace Service { 14namespace Service {
19namespace CAM { 15namespace CAM {
20 16
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
index e9abdcb1f..23d0c9c59 100644
--- a/src/core/hle/service/cam/cam.h
+++ b/src/core/hle/service/cam/cam.h
@@ -4,8 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/kernel.h" 7#include "common/common_types.h"
8#include "core/hle/service/service.h"
9 8
10namespace Service { 9namespace Service {
11namespace CAM { 10namespace CAM {
diff --git a/src/core/hle/service/cam/cam_c.cpp b/src/core/hle/service/cam/cam_c.cpp
index d35adcb9f..8fa7abc85 100644
--- a/src/core/hle/service/cam/cam_c.cpp
+++ b/src/core/hle/service/cam/cam_c.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cam/cam.h"
7#include "core/hle/service/cam/cam_c.h" 5#include "core/hle/service/cam/cam_c.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/cam/cam_q.cpp b/src/core/hle/service/cam/cam_q.cpp
index c2760a102..d3ba91e9d 100644
--- a/src/core/hle/service/cam/cam_q.cpp
+++ b/src/core/hle/service/cam/cam_q.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cam/cam.h"
7#include "core/hle/service/cam/cam_q.h" 5#include "core/hle/service/cam/cam_q.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/cam/cam_s.cpp b/src/core/hle/service/cam/cam_s.cpp
index aefbf7df4..2a13984d8 100644
--- a/src/core/hle/service/cam/cam_s.cpp
+++ b/src/core/hle/service/cam/cam_s.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cam/cam.h"
7#include "core/hle/service/cam/cam_s.h" 5#include "core/hle/service/cam/cam_s.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp
index 1c292ea23..9d59c55fb 100644
--- a/src/core/hle/service/cam/cam_u.cpp
+++ b/src/core/hle/service/cam/cam_u.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cam/cam.h"
7#include "core/hle/service/cam/cam_u.h" 5#include "core/hle/service/cam/cam_u.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index db0e52b79..6d79ce9b4 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -9,10 +9,6 @@
9#include "core/hle/service/cecd/cecd_s.h" 9#include "core/hle/service/cecd/cecd_s.h"
10#include "core/hle/service/cecd/cecd_u.h" 10#include "core/hle/service/cecd/cecd_u.h"
11 11
12#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/shared_memory.h"
14#include "core/hle/hle.h"
15
16namespace Service { 12namespace Service {
17namespace CECD { 13namespace CECD {
18 14
diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h
index 32fd2045d..9e158521b 100644
--- a/src/core/hle/service/cecd/cecd.h
+++ b/src/core/hle/service/cecd/cecd.h
@@ -4,9 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service { 7namespace Service {
11namespace CECD { 8namespace CECD {
12 9
diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp
index 72d7e8d44..bfd821c07 100644
--- a/src/core/hle/service/cecd/cecd_s.cpp
+++ b/src/core/hle/service/cecd/cecd_s.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cecd/cecd.h"
7#include "core/hle/service/cecd/cecd_s.h" 5#include "core/hle/service/cecd/cecd_s.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp
index 0a23bafbc..9b720a738 100644
--- a/src/core/hle/service/cecd/cecd_u.cpp
+++ b/src/core/hle/service/cecd/cecd_u.cpp
@@ -2,18 +2,17 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cecd/cecd.h"
7#include "core/hle/service/cecd/cecd_u.h" 5#include "core/hle/service/cecd/cecd_u.h"
8 6
9namespace Service { 7namespace Service {
10namespace CECD { 8namespace CECD {
11 9
12// Empty arrays are illegal -- commented out until an entry is added. 10static const Interface::FunctionInfo FunctionTable[] = {
13//const Interface::FunctionInfo FunctionTable[] = { }; 11 { 0x00120104, nullptr, "ReadSavedData" },
12};
14 13
15CECD_U_Interface::CECD_U_Interface() { 14CECD_U_Interface::CECD_U_Interface() {
16 //Register(FunctionTable); 15 Register(FunctionTable);
17} 16}
18 17
19} // namespace CECD 18} // namespace CECD
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 56986a49e..4c82a58e4 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -4,13 +4,15 @@
4 4
5#include <algorithm> 5#include <algorithm>
6 6
7#include "common/file_util.h"
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "common/string_util.h" 9#include "common/string_util.h"
9#include "common/file_util.h" 10#include "common/swap.h"
10 11
11#include "core/file_sys/archive_systemsavedata.h" 12#include "core/file_sys/archive_systemsavedata.h"
12#include "core/file_sys/file_backend.h" 13#include "core/file_sys/file_backend.h"
13#include "core/settings.h" 14#include "core/settings.h"
15#include "core/hle/result.h"
14#include "core/hle/service/cfg/cfg.h" 16#include "core/hle/service/cfg/cfg.h"
15#include "core/hle/service/cfg/cfg_i.h" 17#include "core/hle/service/cfg/cfg_i.h"
16#include "core/hle/service/cfg/cfg_s.h" 18#include "core/hle/service/cfg/cfg_s.h"
@@ -292,8 +294,8 @@ ResultCode DeleteConfigNANDSaveFile() {
292 294
293ResultCode UpdateConfigNANDSavegame() { 295ResultCode UpdateConfigNANDSavegame() {
294 FileSys::Mode mode = {}; 296 FileSys::Mode mode = {};
295 mode.write_flag = 1; 297 mode.write_flag.Assign(1);
296 mode.create_flag = 1; 298 mode.create_flag.Assign(1);
297 299
298 FileSys::Path path("config"); 300 FileSys::Path path("config");
299 301
@@ -333,6 +335,18 @@ ResultCode FormatConfig() {
333 res = CreateConfigInfoBlk(0x000A0000, sizeof(CONSOLE_USERNAME_BLOCK), 0xE, &CONSOLE_USERNAME_BLOCK); 335 res = CreateConfigInfoBlk(0x000A0000, sizeof(CONSOLE_USERNAME_BLOCK), 0xE, &CONSOLE_USERNAME_BLOCK);
334 if (!res.IsSuccess()) return res; 336 if (!res.IsSuccess()) return res;
335 337
338 // 0x000A0000 - Profile username
339 struct {
340 u16_le username[10];
341 u8 unused[4];
342 u32_le wordfilter_version; // Unused by Citra
343 } profile_username = {};
344
345 std::u16string username_string = Common::UTF8ToUTF16("Citra");
346 std::copy(username_string.cbegin(), username_string.cend(), profile_username.username);
347 res = CreateConfigInfoBlk(0x000A0000, sizeof(profile_username), 0xE, &profile_username);
348 if (!res.IsSuccess()) return res;
349
336 // 0x000A0001 - Profile birthday 350 // 0x000A0001 - Profile birthday
337 const u8 profile_birthday[2] = {3, 25}; // March 25th, 2014 351 const u8 profile_birthday[2] = {3, 25}; // March 25th, 2014
338 res = CreateConfigInfoBlk(0x000A0001, sizeof(profile_birthday), 0xE, profile_birthday); 352 res = CreateConfigInfoBlk(0x000A0001, sizeof(profile_birthday), 0xE, profile_birthday);
@@ -343,9 +357,10 @@ ResultCode FormatConfig() {
343 res = CreateConfigInfoBlk(0x000B0000, sizeof(COUNTRY_INFO), 0xE, &COUNTRY_INFO); 357 res = CreateConfigInfoBlk(0x000B0000, sizeof(COUNTRY_INFO), 0xE, &COUNTRY_INFO);
344 if (!res.IsSuccess()) return res; 358 if (!res.IsSuccess()) return res;
345 359
346 char16_t country_name_buffer[16][0x40] = {}; 360 u16_le country_name_buffer[16][0x40] = {};
361 std::u16string region_name = Common::UTF8ToUTF16("Gensokyo");
347 for (size_t i = 0; i < 16; ++i) { 362 for (size_t i = 0; i < 16; ++i) {
348 Common::UTF8ToUTF16("Gensokyo").copy(country_name_buffer[i], 0x40); 363 std::copy(region_name.cbegin(), region_name.cend(), country_name_buffer[i]);
349 } 364 }
350 // 0x000B0001 - Localized names for the profile Country 365 // 0x000B0001 - Localized names for the profile Country
351 res = CreateConfigInfoBlk(0x000B0001, sizeof(country_name_buffer), 0xE, country_name_buffer); 366 res = CreateConfigInfoBlk(0x000B0001, sizeof(country_name_buffer), 0xE, country_name_buffer);
@@ -404,7 +419,7 @@ void Init() {
404 419
405 FileSys::Path config_path("config"); 420 FileSys::Path config_path("config");
406 FileSys::Mode open_mode = {}; 421 FileSys::Mode open_mode = {};
407 open_mode.read_flag = 1; 422 open_mode.read_flag.Assign(1);
408 423
409 auto config_result = Service::FS::OpenFileFromArchive(*archive_result, config_path, open_mode); 424 auto config_result = Service::FS::OpenFileFromArchive(*archive_result, config_path, open_mode);
410 425
diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h
index fc2a16a04..606ab99cf 100644
--- a/src/core/hle/service/cfg/cfg.h
+++ b/src/core/hle/service/cfg/cfg.h
@@ -5,10 +5,15 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "core/hle/result.h" 8
9#include "core/hle/service/service.h" 9#include "common/common_types.h"
10
11union ResultCode;
10 12
11namespace Service { 13namespace Service {
14
15class Interface;
16
12namespace CFG { 17namespace CFG {
13 18
14enum SystemModel { 19enum SystemModel {
diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp
index 5aeadc084..0559a07b2 100644
--- a/src/core/hle/service/cfg/cfg_i.cpp
+++ b/src/core/hle/service/cfg/cfg_i.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cfg/cfg.h" 5#include "core/hle/service/cfg/cfg.h"
7#include "core/hle/service/cfg/cfg_i.h" 6#include "core/hle/service/cfg/cfg_i.h"
8 7
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp
index a329514a6..b03d290e5 100644
--- a/src/core/hle/service/cfg/cfg_s.cpp
+++ b/src/core/hle/service/cfg/cfg_s.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cfg/cfg.h" 5#include "core/hle/service/cfg/cfg.h"
7#include "core/hle/service/cfg/cfg_s.h" 6#include "core/hle/service/cfg/cfg_s.h"
8 7
diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp
index 18939750b..89ae96c9e 100644
--- a/src/core/hle/service/cfg/cfg_u.cpp
+++ b/src/core/hle/service/cfg/cfg_u.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cfg/cfg.h" 5#include "core/hle/service/cfg/cfg.h"
7#include "core/hle/service/cfg/cfg_u.h" 6#include "core/hle/service/cfg/cfg_u.h"
8 7
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index d6b8d1318..15d3274ec 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -2,9 +2,10 @@
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/hle/pipe.h"
6
5#include "common/logging/log.h" 7#include "common/logging/log.h"
6 8
7#include "core/hle/hle.h"
8#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/event.h"
9#include "core/hle/service/dsp_dsp.h" 10#include "core/hle/service/dsp_dsp.h"
10 11
@@ -15,17 +16,30 @@ namespace DSP_DSP {
15 16
16static u32 read_pipe_count; 17static u32 read_pipe_count;
17static Kernel::SharedPtr<Kernel::Event> semaphore_event; 18static Kernel::SharedPtr<Kernel::Event> semaphore_event;
18static Kernel::SharedPtr<Kernel::Event> interrupt_event;
19 19
20void SignalInterrupt() { 20struct PairHash {
21 // TODO(bunnei): This is just a stub, it does not do anything other than signal to the emulated 21 template <typename T, typename U>
22 // application that a DSP interrupt occurred, without specifying which one. Since we do not 22 std::size_t operator()(const std::pair<T, U> &x) const {
23 // emulate the DSP yet (and how it works is largely unknown), this is a work around to get games 23 // TODO(yuriks): Replace with better hash combining function.
24 // that check the DSP interrupt signal event to run. We should figure out the different types of 24 return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
25 // DSP interrupts, and trigger them at the appropriate times. 25 }
26};
27
28/// Map of (audio interrupt number, channel number) to Kernel::Events. See: RegisterInterruptEvents
29static std::unordered_map<std::pair<u32, u32>, Kernel::SharedPtr<Kernel::Event>, PairHash> interrupt_events;
30
31// DSP Interrupts:
32// Interrupt #2 occurs every frame tick. Userland programs normally have a thread that's waiting
33// for an interrupt event. Immediately after this interrupt event, userland normally updates the
34// state in the next region and increments the relevant frame counter by two.
35void SignalAllInterrupts() {
36 // HACK: The other interrupts have currently unknown purpose, we trigger them each tick in any case.
37 for (auto& interrupt_event : interrupt_events)
38 interrupt_event.second->Signal();
39}
26 40
27 if (interrupt_event != 0) 41void SignalInterrupt(u32 interrupt, u32 channel) {
28 interrupt_event->Signal(); 42 interrupt_events[std::make_pair(interrupt, channel)]->Signal();
29} 43}
30 44
31/** 45/**
@@ -44,7 +58,7 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
44 cmd_buff[1] = 0; // No error 58 cmd_buff[1] = 0; // No error
45 cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000); 59 cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000);
46 60
47 LOG_WARNING(Service_DSP, "(STUBBED) called with address 0x%08X", addr); 61 LOG_TRACE(Service_DSP, "addr=0x%08X", addr);
48} 62}
49 63
50/** 64/**
@@ -122,8 +136,8 @@ static void FlushDataCache(Service::Interface* self) {
122/** 136/**
123 * DSP_DSP::RegisterInterruptEvents service function 137 * DSP_DSP::RegisterInterruptEvents service function
124 * Inputs: 138 * Inputs:
125 * 1 : Parameter 0 (purpose unknown) 139 * 1 : Interrupt Number
126 * 2 : Parameter 1 (purpose unknown) 140 * 2 : Channel Number
127 * 4 : Interrupt event handle 141 * 4 : Interrupt event handle
128 * Outputs: 142 * Outputs:
129 * 1 : Result of function, 0 on success, otherwise error code 143 * 1 : Result of function, 0 on success, otherwise error code
@@ -131,22 +145,24 @@ static void FlushDataCache(Service::Interface* self) {
131static void RegisterInterruptEvents(Service::Interface* self) { 145static void RegisterInterruptEvents(Service::Interface* self) {
132 u32* cmd_buff = Kernel::GetCommandBuffer(); 146 u32* cmd_buff = Kernel::GetCommandBuffer();
133 147
134 u32 param0 = cmd_buff[1]; 148 u32 interrupt = cmd_buff[1];
135 u32 param1 = cmd_buff[2]; 149 u32 channel = cmd_buff[2];
136 u32 event_handle = cmd_buff[4]; 150 u32 event_handle = cmd_buff[4];
137 151
138 auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]); 152 if (event_handle) {
139 if (evt != nullptr) { 153 auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
140 interrupt_event = evt; 154 if (evt) {
141 cmd_buff[1] = 0; // No error 155 interrupt_events[std::make_pair(interrupt, channel)] = evt;
156 cmd_buff[1] = RESULT_SUCCESS.raw;
157 LOG_WARNING(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
158 } else {
159 cmd_buff[1] = -1;
160 LOG_ERROR(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
161 }
142 } else { 162 } else {
143 LOG_ERROR(Service_DSP, "called with invalid handle=%08X", cmd_buff[4]); 163 interrupt_events.erase(std::make_pair(interrupt, channel));
144 164 LOG_WARNING(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
145 // TODO(yuriks): An error should be returned from SendSyncRequest, not in the cmdbuf
146 cmd_buff[1] = -1;
147 } 165 }
148
149 LOG_WARNING(Service_DSP, "(STUBBED) called param0=%u, param1=%u, event_handle=0x%08X", param0, param1, event_handle);
150} 166}
151 167
152/** 168/**
@@ -159,8 +175,6 @@ static void RegisterInterruptEvents(Service::Interface* self) {
159static void SetSemaphore(Service::Interface* self) { 175static void SetSemaphore(Service::Interface* self) {
160 u32* cmd_buff = Kernel::GetCommandBuffer(); 176 u32* cmd_buff = Kernel::GetCommandBuffer();
161 177
162 SignalInterrupt();
163
164 cmd_buff[1] = 0; // No error 178 cmd_buff[1] = 0; // No error
165 179
166 LOG_WARNING(Service_DSP, "(STUBBED) called"); 180 LOG_WARNING(Service_DSP, "(STUBBED) called");
@@ -169,9 +183,9 @@ static void SetSemaphore(Service::Interface* self) {
169/** 183/**
170 * DSP_DSP::WriteProcessPipe service function 184 * DSP_DSP::WriteProcessPipe service function
171 * Inputs: 185 * Inputs:
172 * 1 : Number 186 * 1 : Channel
173 * 2 : Size 187 * 2 : Size
174 * 3 : (size <<14) | 0x402 188 * 3 : (size << 14) | 0x402
175 * 4 : Buffer 189 * 4 : Buffer
176 * Outputs: 190 * Outputs:
177 * 0 : Return header 191 * 0 : Return header
@@ -180,21 +194,42 @@ static void SetSemaphore(Service::Interface* self) {
180static void WriteProcessPipe(Service::Interface* self) { 194static void WriteProcessPipe(Service::Interface* self) {
181 u32* cmd_buff = Kernel::GetCommandBuffer(); 195 u32* cmd_buff = Kernel::GetCommandBuffer();
182 196
183 u32 number = cmd_buff[1]; 197 u32 channel = cmd_buff[1];
184 u32 size = cmd_buff[2]; 198 u32 size = cmd_buff[2];
185 u32 new_size = cmd_buff[3];
186 u32 buffer = cmd_buff[4]; 199 u32 buffer = cmd_buff[4];
187 200
201 if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) {
202 LOG_ERROR(Service_DSP, "IPC static buffer descriptor failed validation (0x%X). channel=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], channel, size, buffer);
203 cmd_buff[1] = -1; // TODO
204 return;
205 }
206
207 if (!Memory::GetPointer(buffer)) {
208 LOG_ERROR(Service_DSP, "Invalid Buffer: channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer);
209 cmd_buff[1] = -1; // TODO
210 return;
211 }
212
213 std::vector<u8> message(size);
214
215 for (size_t i = 0; i < size; i++) {
216 message[i] = Memory::Read8(buffer + i);
217 }
218
219 DSP::HLE::PipeWrite(channel, message);
220
188 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 221 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
189 222
190 LOG_WARNING(Service_DSP, "(STUBBED) called number=%u, size=0x%X, new_size=0x%X, buffer=0x%08X", 223 LOG_TRACE(Service_DSP, "channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer);
191 number, size, new_size, buffer);
192} 224}
193 225
194/** 226/**
195 * DSP_DSP::ReadPipeIfPossible service function 227 * DSP_DSP::ReadPipeIfPossible service function
228 * A pipe is a means of communication between the ARM11 and DSP that occurs on
229 * hardware by writing to/reading from the DSP registers at 0x10203000.
230 * Pipes are used for initialisation. See also DSP::HLE::PipeRead.
196 * Inputs: 231 * Inputs:
197 * 1 : Unknown 232 * 1 : Pipe Number
198 * 2 : Unknown 233 * 2 : Unknown
199 * 3 : Size in bytes of read (observed only lower half word used) 234 * 3 : Size in bytes of read (observed only lower half word used)
200 * 0x41 : Virtual address to read from DSP pipe to in memory 235 * 0x41 : Virtual address to read from DSP pipe to in memory
@@ -205,35 +240,25 @@ static void WriteProcessPipe(Service::Interface* self) {
205static void ReadPipeIfPossible(Service::Interface* self) { 240static void ReadPipeIfPossible(Service::Interface* self) {
206 u32* cmd_buff = Kernel::GetCommandBuffer(); 241 u32* cmd_buff = Kernel::GetCommandBuffer();
207 242
208 u32 unk1 = cmd_buff[1]; 243 u32 pipe = cmd_buff[1];
209 u32 unk2 = cmd_buff[2]; 244 u32 unk2 = cmd_buff[2];
210 u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size 245 u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size
211 VAddr addr = cmd_buff[0x41]; 246 VAddr addr = cmd_buff[0x41];
212 247
213 // Canned DSP responses that games expect. These were taken from HW by 3dmoo team. 248 if (!Memory::GetPointer(addr)) {
214 // TODO: Remove this hack :) 249 LOG_ERROR(Service_DSP, "Invalid addr: pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr);
215 static const std::array<u16, 16> canned_read_pipe = {{ 250 cmd_buff[1] = -1; // TODO
216 0x000F, 0xBFFF, 0x9E8E, 0x8680, 0xA78E, 0x9430, 0x8400, 0x8540, 251 return;
217 0x948E, 0x8710, 0x8410, 0xA90E, 0xAA0E, 0xAACE, 0xAC4E, 0xAC58 252 }
218 }};
219 253
220 u32 initial_size = read_pipe_count; 254 std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
221 255
222 for (unsigned offset = 0; offset < size; offset += sizeof(u16)) { 256 Memory::WriteBlock(addr, response.data(), response.size());
223 if (read_pipe_count < canned_read_pipe.size()) {
224 Memory::Write16(addr + offset, canned_read_pipe[read_pipe_count]);
225 read_pipe_count++;
226 } else {
227 LOG_ERROR(Service_DSP, "canned read pipe log exceeded!");
228 break;
229 }
230 }
231 257
232 cmd_buff[1] = 0; // No error 258 cmd_buff[1] = 0; // No error
233 cmd_buff[2] = (read_pipe_count - initial_size) * sizeof(u16); 259 cmd_buff[2] = (u32)response.size();
234 260
235 LOG_WARNING(Service_DSP, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", 261 LOG_TRACE(Service_DSP, "pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr);
236 unk1, unk2, size, addr);
237} 262}
238 263
239/** 264/**
@@ -312,7 +337,6 @@ const Interface::FunctionInfo FunctionTable[] = {
312 337
313Interface::Interface() { 338Interface::Interface() {
314 semaphore_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "DSP_DSP::semaphore_event"); 339 semaphore_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "DSP_DSP::semaphore_event");
315 interrupt_event = nullptr;
316 read_pipe_count = 0; 340 read_pipe_count = 0;
317 341
318 Register(FunctionTable); 342 Register(FunctionTable);
@@ -320,7 +344,7 @@ Interface::Interface() {
320 344
321Interface::~Interface() { 345Interface::~Interface() {
322 semaphore_event = nullptr; 346 semaphore_event = nullptr;
323 interrupt_event = nullptr; 347 interrupt_events.clear();
324} 348}
325 349
326} // namespace 350} // namespace
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index b6f611db5..32b89e9bb 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -23,7 +23,15 @@ public:
23 } 23 }
24}; 24};
25 25
26/// Signals that a DSP interrupt has occurred to userland code 26/// Signal all audio related interrupts.
27void SignalInterrupt(); 27void SignalAllInterrupts();
28
29/**
30 * Signal a specific audio related interrupt based on interrupt id and channel id.
31 * @param interrupt_id The interrupt id
32 * @param channel_id The channel id
33 * The significance of various values of interrupt_id and channel_id is not yet known.
34 */
35void SignalInterrupt(u32 interrupt_id, u32 channel_id);
28 36
29} // namespace 37} // namespace
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index e8c06c1cf..5f9cf6e94 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -2,9 +2,10 @@
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 "common/bit_field.h"
6#include "common/common_types.h"
5#include "common/logging/log.h" 7#include "common/logging/log.h"
6 8
7#include "core/hle/hle.h"
8#include "core/hle/service/err_f.h" 9#include "core/hle/service/err_f.h"
9 10
10//////////////////////////////////////////////////////////////////////////////////////////////////// 11////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp
index 2911ab402..c13ffd9d2 100644
--- a/src/core/hle/service/frd/frd.cpp
+++ b/src/core/hle/service/frd/frd.cpp
@@ -7,10 +7,6 @@
7#include "core/hle/service/frd/frd_a.h" 7#include "core/hle/service/frd/frd_a.h"
8#include "core/hle/service/frd/frd_u.h" 8#include "core/hle/service/frd/frd_u.h"
9 9
10#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/shared_memory.h"
12#include "core/hle/hle.h"
13
14namespace Service { 10namespace Service {
15namespace FRD { 11namespace FRD {
16 12
diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h
index 41f7a2f6b..f9f88b444 100644
--- a/src/core/hle/service/frd/frd.h
+++ b/src/core/hle/service/frd/frd.h
@@ -4,9 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service { 7namespace Service {
11namespace FRD { 8namespace FRD {
12 9
diff --git a/src/core/hle/service/frd/frd_a.cpp b/src/core/hle/service/frd/frd_a.cpp
index 1c438a337..818d610f3 100644
--- a/src/core/hle/service/frd/frd_a.cpp
+++ b/src/core/hle/service/frd/frd_a.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/frd/frd.h"
7#include "core/hle/service/frd/frd_a.h" 5#include "core/hle/service/frd/frd_a.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp
index 9e70ec901..2c6885377 100644
--- a/src/core/hle/service/frd/frd_u.cpp
+++ b/src/core/hle/service/frd/frd_u.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/frd/frd.h"
7#include "core/hle/service/frd/frd_u.h" 5#include "core/hle/service/frd/frd_u.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 98b11c798..5838b6d71 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -347,7 +347,7 @@ void SignalInterrupt(InterruptId interrupt_id) {
347 FrameBufferUpdate* info = GetFrameBufferInfo(thread_id, screen_id); 347 FrameBufferUpdate* info = GetFrameBufferInfo(thread_id, screen_id);
348 if (info->is_dirty) { 348 if (info->is_dirty) {
349 SetBufferSwap(screen_id, info->framebuffer_info[info->index]); 349 SetBufferSwap(screen_id, info->framebuffer_info[info->index]);
350 info->is_dirty = false; 350 info->is_dirty.Assign(false);
351 } 351 }
352 } 352 }
353 } 353 }
@@ -499,7 +499,7 @@ static void SetLcdForceBlack(Service::Interface* self) {
499 499
500 // Since data is already zeroed, there is no need to explicitly set 500 // Since data is already zeroed, there is no need to explicitly set
501 // the color to black (all zero). 501 // the color to black (all zero).
502 data.is_enabled = enable_black; 502 data.is_enabled.Assign(enable_black);
503 503
504 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD 504 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD
505 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD 505 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD
@@ -521,7 +521,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
521 ExecuteCommand(command_buffer->commands[i], thread_id); 521 ExecuteCommand(command_buffer->commands[i], thread_id);
522 522
523 // Indicates that command has completed 523 // Indicates that command has completed
524 command_buffer->number_commands = command_buffer->number_commands - 1; 524 command_buffer->number_commands.Assign(command_buffer->number_commands - 1);
525 } 525 }
526 } 526 }
527 527
diff --git a/src/core/hle/service/gsp_lcd.cpp b/src/core/hle/service/gsp_lcd.cpp
index 59ee9b73c..7ad7f081f 100644
--- a/src/core/hle/service/gsp_lcd.cpp
+++ b/src/core/hle/service/gsp_lcd.cpp
@@ -2,8 +2,6 @@
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 "common/bit_field.h"
6
7#include "core/hle/service/gsp_lcd.h" 5#include "core/hle/service/gsp_lcd.h"
8 6
9//////////////////////////////////////////////////////////////////////////////////////////////////// 7////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 2e1e5c3e9..11d7e69a1 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -13,7 +13,6 @@
13#include "core/core_timing.h" 13#include "core/core_timing.h"
14#include "core/hle/kernel/event.h" 14#include "core/hle/kernel/event.h"
15#include "core/hle/kernel/shared_memory.h" 15#include "core/hle/kernel/shared_memory.h"
16#include "core/hle/hle.h"
17 16
18#include "video_core/video_core.h" 17#include "video_core/video_core.h"
19 18
@@ -106,7 +105,7 @@ void Update() {
106 bool pressed = false; 105 bool pressed = false;
107 106
108 std::tie(touch_entry->x, touch_entry->y, pressed) = VideoCore::g_emu_window->GetTouchState(); 107 std::tie(touch_entry->x, touch_entry->y, pressed) = VideoCore::g_emu_window->GetTouchState();
109 touch_entry->valid = pressed ? 1 : 0; 108 touch_entry->valid.Assign(pressed ? 1 : 0);
110 109
111 // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which 110 // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which
112 // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being 111 // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being
diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp
index 532931ae0..c50f597eb 100644
--- a/src/core/hle/service/hid/hid_spvr.cpp
+++ b/src/core/hle/service/hid/hid_spvr.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/hid/hid.h" 5#include "core/hle/service/hid/hid.h"
7#include "core/hle/service/hid/hid_spvr.h" 6#include "core/hle/service/hid/hid_spvr.h"
8 7
diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp
index e103881b1..bbdde2abb 100644
--- a/src/core/hle/service/hid/hid_user.cpp
+++ b/src/core/hle/service/hid/hid_user.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/hid/hid.h" 5#include "core/hle/service/hid/hid.h"
7#include "core/hle/service/hid/hid_user.h" 6#include "core/hle/service/hid/hid_user.h"
8 7
diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp
index 43d8a3b85..79009053e 100644
--- a/src/core/hle/service/http_c.cpp
+++ b/src/core/hle/service/http_c.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/http_c.h" 5#include "core/hle/service/http_c.h"
7 6
8//////////////////////////////////////////////////////////////////////////////////////////////////// 7////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp
index adfbb258d..c2121cb2e 100644
--- a/src/core/hle/service/ir/ir.cpp
+++ b/src/core/hle/service/ir/ir.cpp
@@ -2,21 +2,22 @@
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 "core/hle/kernel/event.h"
6#include "core/hle/kernel/shared_memory.h"
7
5#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
6#include "core/hle/service/ir/ir.h" 9#include "core/hle/service/ir/ir.h"
7#include "core/hle/service/ir/ir_rst.h" 10#include "core/hle/service/ir/ir_rst.h"
8#include "core/hle/service/ir/ir_u.h" 11#include "core/hle/service/ir/ir_u.h"
9#include "core/hle/service/ir/ir_user.h" 12#include "core/hle/service/ir/ir_user.h"
10 13
11#include "core/hle/hle.h"
12#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/shared_memory.h"
14
15namespace Service { 14namespace Service {
16namespace IR { 15namespace IR {
17 16
18static Kernel::SharedPtr<Kernel::Event> handle_event; 17static Kernel::SharedPtr<Kernel::Event> handle_event;
18static Kernel::SharedPtr<Kernel::Event> conn_status_event;
19static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; 19static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
20static Kernel::SharedPtr<Kernel::SharedMemory> transfer_shared_memory;
20 21
21void GetHandles(Service::Interface* self) { 22void GetHandles(Service::Interface* self) {
22 u32* cmd_buff = Kernel::GetCommandBuffer(); 23 u32* cmd_buff = Kernel::GetCommandBuffer();
@@ -27,6 +28,64 @@ void GetHandles(Service::Interface* self) {
27 cmd_buff[4] = Kernel::g_handle_table.Create(Service::IR::handle_event).MoveFrom(); 28 cmd_buff[4] = Kernel::g_handle_table.Create(Service::IR::handle_event).MoveFrom();
28} 29}
29 30
31void InitializeIrNopShared(Interface* self) {
32 u32* cmd_buff = Kernel::GetCommandBuffer();
33
34 u32 transfer_buff_size = cmd_buff[1];
35 u32 recv_buff_size = cmd_buff[2];
36 u32 unk1 = cmd_buff[3];
37 u32 send_buff_size = cmd_buff[4];
38 u32 unk2 = cmd_buff[5];
39 u8 baud_rate = cmd_buff[6] & 0xFF;
40 Handle handle = cmd_buff[8];
41
42 if(Kernel::g_handle_table.IsValid(handle)) {
43 transfer_shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(handle);
44 transfer_shared_memory->name = "IR:TransferSharedMemory";
45 }
46
47 cmd_buff[1] = RESULT_SUCCESS.raw;
48
49 LOG_WARNING(Service_IR, "(STUBBED) called, transfer_buff_size=%d, recv_buff_size=%d, "
50 "unk1=%d, send_buff_size=%d, unk2=%d, baud_rate=%u, handle=0x%08X",
51 transfer_buff_size, recv_buff_size, unk1, send_buff_size, unk2, baud_rate, handle);
52}
53
54void RequireConnection(Interface* self) {
55 u32* cmd_buff = Kernel::GetCommandBuffer();
56
57 conn_status_event->Signal();
58
59 cmd_buff[1] = RESULT_SUCCESS.raw;
60
61 LOG_WARNING(Service_IR, "(STUBBED) called");
62}
63
64void Disconnect(Interface* self) {
65 u32* cmd_buff = Kernel::GetCommandBuffer();
66
67 cmd_buff[1] = RESULT_SUCCESS.raw;
68
69 LOG_WARNING(Service_IR, "(STUBBED) called");
70}
71
72void GetConnectionStatusEvent(Interface* self) {
73 u32* cmd_buff = Kernel::GetCommandBuffer();
74
75 cmd_buff[1] = RESULT_SUCCESS.raw;
76 cmd_buff[3] = Kernel::g_handle_table.Create(Service::IR::conn_status_event).MoveFrom();
77
78 LOG_WARNING(Service_IR, "(STUBBED) called");
79}
80
81void FinalizeIrNop(Interface* self) {
82 u32* cmd_buff = Kernel::GetCommandBuffer();
83
84 cmd_buff[1] = RESULT_SUCCESS.raw;
85
86 LOG_WARNING(Service_IR, "(STUBBED) called");
87}
88
30void Init() { 89void Init() {
31 using namespace Kernel; 90 using namespace Kernel;
32 91
@@ -36,15 +95,19 @@ void Init() {
36 95
37 using Kernel::MemoryPermission; 96 using Kernel::MemoryPermission;
38 shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite, 97 shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite,
39 Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory"); 98 Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory");
99 transfer_shared_memory = nullptr;
40 100
41 // Create event handle(s) 101 // Create event handle(s)
42 handle_event = Event::Create(RESETTYPE_ONESHOT, "IR:HandleEvent"); 102 handle_event = Event::Create(RESETTYPE_ONESHOT, "IR:HandleEvent");
103 conn_status_event = Event::Create(RESETTYPE_ONESHOT, "IR:ConnectionStatusEvent");
43} 104}
44 105
45void Shutdown() { 106void Shutdown() {
107 transfer_shared_memory = nullptr;
46 shared_memory = nullptr; 108 shared_memory = nullptr;
47 handle_event = nullptr; 109 handle_event = nullptr;
110 conn_status_event = nullptr;
48} 111}
49 112
50} // namespace IR 113} // namespace IR
diff --git a/src/core/hle/service/ir/ir.h b/src/core/hle/service/ir/ir.h
index c16d963e7..72d44ce60 100644
--- a/src/core/hle/service/ir/ir.h
+++ b/src/core/hle/service/ir/ir.h
@@ -4,10 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service { 7namespace Service {
8
9class Interface;
10
11namespace IR { 11namespace IR {
12 12
13/** 13/**
@@ -20,6 +20,53 @@ namespace IR {
20 */ 20 */
21void GetHandles(Interface* self); 21void GetHandles(Interface* self);
22 22
23/**
24 * IR::InitializeIrNopShared service function
25 * Inputs:
26 * 1 : Size of transfer buffer
27 * 2 : Recv buffer size
28 * 3 : unknown
29 * 4 : Send buffer size
30 * 5 : unknown
31 * 6 : BaudRate (u8)
32 * 7 : 0
33 * 8 : Handle of transfer shared memory
34 * Outputs:
35 * 1 : Result of function, 0 on success, otherwise error code
36 */
37void InitializeIrNopShared(Interface* self);
38
39/**
40 * IR::FinalizeIrNop service function
41 * Outputs:
42 * 1 : Result of function, 0 on success, otherwise error code
43 */
44void FinalizeIrNop(Interface* self);
45
46/**
47 * IR::GetConnectionStatusEvent service function
48 * Outputs:
49 * 1 : Result of function, 0 on success, otherwise error code
50 * 2 : Connection Status Event handle
51 */
52void GetConnectionStatusEvent(Interface* self);
53
54/**
55 * IR::Disconnect service function
56 * Outputs:
57 * 1 : Result of function, 0 on success, otherwise error code
58 */
59void Disconnect(Interface* self);
60
61/**
62 * IR::RequireConnection service function
63 * Inputs:
64 * 1 : unknown (u8), looks like always 1
65 * Outputs:
66 * 1 : Result of function, 0 on success, otherwise error code
67 */
68void RequireConnection(Interface* self);
69
23/// Initialize IR service 70/// Initialize IR service
24void Init(); 71void Init();
25 72
diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp
index 96ae63420..c0300f109 100644
--- a/src/core/hle/service/ir/ir_rst.cpp
+++ b/src/core/hle/service/ir/ir_rst.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/ir/ir.h" 5#include "core/hle/service/ir/ir.h"
7#include "core/hle/service/ir/ir_rst.h" 6#include "core/hle/service/ir/ir_rst.h"
8 7
diff --git a/src/core/hle/service/ir/ir_u.cpp b/src/core/hle/service/ir/ir_u.cpp
index 1b1e3078b..96f76cb83 100644
--- a/src/core/hle/service/ir/ir_u.cpp
+++ b/src/core/hle/service/ir/ir_u.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/ir/ir.h"
7#include "core/hle/service/ir/ir_u.h" 5#include "core/hle/service/ir/ir_u.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp
index 8e3ff140f..06a601029 100644
--- a/src/core/hle/service/ir/ir_user.cpp
+++ b/src/core/hle/service/ir/ir_user.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/ir/ir.h" 5#include "core/hle/service/ir/ir.h"
7#include "core/hle/service/ir/ir_user.h" 6#include "core/hle/service/ir/ir_user.h"
8 7
@@ -10,20 +9,32 @@ namespace Service {
10namespace IR { 9namespace IR {
11 10
12const Interface::FunctionInfo FunctionTable[] = { 11const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010182, nullptr, "InitializeIrNop"}, 12 {0x00010182, nullptr, "InitializeIrNop"},
14 {0x00020000, nullptr, "FinalizeIrNop"}, 13 {0x00020000, FinalizeIrNop, "FinalizeIrNop"},
15 {0x00030000, nullptr, "ClearReceiveBuffer"}, 14 {0x00030000, nullptr, "ClearReceiveBuffer"},
16 {0x00040000, nullptr, "ClearSendBuffer"}, 15 {0x00040000, nullptr, "ClearSendBuffer"},
17 {0x00060040, nullptr, "RequireConnection"}, 16 {0x000500C0, nullptr, "WaitConnection"},
18 {0x00090000, nullptr, "Disconnect"}, 17 {0x00060040, RequireConnection, "RequireConnection"},
19 {0x000A0000, nullptr, "GetReceiveEvent"}, 18 {0x000702C0, nullptr, "AutoConnection"},
20 {0x000B0000, nullptr, "GetSendEvent"}, 19 {0x00080000, nullptr, "AnyConnection"},
21 {0x000C0000, nullptr, "GetConnectionStatusEvent"}, 20 {0x00090000, Disconnect, "Disconnect"},
22 {0x000D0042, nullptr, "SendIrNop"}, 21 {0x000A0000, nullptr, "GetReceiveEvent"},
23 {0x000E0042, nullptr, "SendIrNopLarge"}, 22 {0x000B0000, nullptr, "GetSendEvent"},
24 {0x00180182, nullptr, "InitializeIrNopShared"}, 23 {0x000C0000, GetConnectionStatusEvent, "GetConnectionStatusEvent"},
25 {0x00190040, nullptr, "ReleaseReceivedData"}, 24 {0x000D0042, nullptr, "SendIrNop"},
26 {0x001A0040, nullptr, "SetOwnMachineId"}, 25 {0x000E0042, nullptr, "SendIrNopLarge"},
26 {0x000F0040, nullptr, "ReceiveIrnop"},
27 {0x00100042, nullptr, "ReceiveIrnopLarge"},
28 {0x00110040, nullptr, "GetLatestReceiveErrorResult"},
29 {0x00120040, nullptr, "GetLatestSendErrorResult"},
30 {0x00130000, nullptr, "GetConnectionStatus"},
31 {0x00140000, nullptr, "GetTryingToConnectStatus"},
32 {0x00150000, nullptr, "GetReceiveSizeFreeAndUsed"},
33 {0x00160000, nullptr, "GetSendSizeFreeAndUsed"},
34 {0x00170000, nullptr, "GetConnectionRole"},
35 {0x00180182, InitializeIrNopShared, "InitializeIrNopShared"},
36 {0x00190040, nullptr, "ReleaseReceivedData"},
37 {0x001A0040, nullptr, "SetOwnMachineId"},
27}; 38};
28 39
29IR_User_Interface::IR_User_Interface() { 40IR_User_Interface::IR_User_Interface() {
diff --git a/src/core/hle/service/ldr_ro.cpp b/src/core/hle/service/ldr_ro.cpp
index f84ce4d72..ecec2ce32 100644
--- a/src/core/hle/service/ldr_ro.cpp
+++ b/src/core/hle/service/ldr_ro.cpp
@@ -2,9 +2,9 @@
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 "common/common_types.h"
5#include "common/logging/log.h" 6#include "common/logging/log.h"
6 7
7#include "core/hle/hle.h"
8#include "core/hle/service/ldr_ro.h" 8#include "core/hle/service/ldr_ro.h"
9 9
10//////////////////////////////////////////////////////////////////////////////////////////////////// 10////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index 1f27e9c1f..f792bc9cd 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/mic_u.h" 5#include "core/hle/service/mic_u.h"
7 6
8//////////////////////////////////////////////////////////////////////////////////////////////////// 7////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/ndm_u.cpp b/src/core/hle/service/ndm_u.cpp
index ad247fd1f..8fdf1ef90 100644
--- a/src/core/hle/service/ndm_u.cpp
+++ b/src/core/hle/service/ndm_u.cpp
@@ -2,8 +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 "core/hle/hle.h" 5#include "core/hle/service/ndm_u.h"
6#include "ndm_u.h"
7 6
8//////////////////////////////////////////////////////////////////////////////////////////////////// 7////////////////////////////////////////////////////////////////////////////////////////////////////
9// Namespace NDM_U 8// Namespace NDM_U
diff --git a/src/core/hle/service/news/news.cpp b/src/core/hle/service/news/news.cpp
index 63cbd3850..b3f500694 100644
--- a/src/core/hle/service/news/news.cpp
+++ b/src/core/hle/service/news/news.cpp
@@ -9,10 +9,6 @@
9#include "core/hle/service/news/news_s.h" 9#include "core/hle/service/news/news_s.h"
10#include "core/hle/service/news/news_u.h" 10#include "core/hle/service/news/news_u.h"
11 11
12#include "core/hle/hle.h"
13#include "core/hle/kernel/event.h"
14#include "core/hle/kernel/shared_memory.h"
15
16namespace Service { 12namespace Service {
17namespace NEWS { 13namespace NEWS {
18 14
diff --git a/src/core/hle/service/news/news.h b/src/core/hle/service/news/news.h
index b31ade255..46a3ffcb5 100644
--- a/src/core/hle/service/news/news.h
+++ b/src/core/hle/service/news/news.h
@@ -4,9 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service { 7namespace Service {
11namespace NEWS { 8namespace NEWS {
12 9
diff --git a/src/core/hle/service/news/news_s.cpp b/src/core/hle/service/news/news_s.cpp
index 5b8db3288..39b5a50f8 100644
--- a/src/core/hle/service/news/news_s.cpp
+++ b/src/core/hle/service/news/news_s.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/news/news.h" 5#include "core/hle/service/news/news.h"
7#include "core/hle/service/news/news_s.h" 6#include "core/hle/service/news/news_s.h"
8 7
diff --git a/src/core/hle/service/news/news_u.cpp b/src/core/hle/service/news/news_u.cpp
index 81f45a244..6b75cc24e 100644
--- a/src/core/hle/service/news/news_u.cpp
+++ b/src/core/hle/service/news/news_u.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/news/news.h"
7#include "core/hle/service/news/news_u.h" 5#include "core/hle/service/news/news_u.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index 73b0ee52a..ed42464ce 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.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 "common/common_types.h"
5#include "common/logging/log.h" 6#include "common/logging/log.h"
6 7
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
@@ -10,10 +11,6 @@
10#include "core/hle/service/nim/nim_s.h" 11#include "core/hle/service/nim/nim_s.h"
11#include "core/hle/service/nim/nim_u.h" 12#include "core/hle/service/nim/nim_u.h"
12 13
13#include "core/hle/kernel/event.h"
14#include "core/hle/kernel/shared_memory.h"
15#include "core/hle/hle.h"
16
17namespace Service { 14namespace Service {
18namespace NIM { 15namespace NIM {
19 16
diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h
index f7635c747..c3106f18b 100644
--- a/src/core/hle/service/nim/nim.h
+++ b/src/core/hle/service/nim/nim.h
@@ -4,10 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service { 7namespace Service {
8
9class Interface;
10
11namespace NIM { 11namespace NIM {
12 12
13/** 13/**
diff --git a/src/core/hle/service/nim/nim_aoc.cpp b/src/core/hle/service/nim/nim_aoc.cpp
index e6b1b6145..4a4818d57 100644
--- a/src/core/hle/service/nim/nim_aoc.cpp
+++ b/src/core/hle/service/nim/nim_aoc.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/nim/nim.h"
7#include "core/hle/service/nim/nim_aoc.h" 5#include "core/hle/service/nim/nim_aoc.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp
index 1172770ac..dcaa0255a 100644
--- a/src/core/hle/service/nim/nim_s.cpp
+++ b/src/core/hle/service/nim/nim_s.cpp
@@ -2,8 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/nim/nim.h"
7#include "core/hle/service/nim/nim_s.h" 5#include "core/hle/service/nim/nim_s.h"
8 6
9namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp
index 066570a85..eae45ebc0 100644
--- a/src/core/hle/service/nim/nim_u.cpp
+++ b/src/core/hle/service/nim/nim_u.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/nim/nim.h" 5#include "core/hle/service/nim/nim.h"
7#include "core/hle/service/nim/nim_u.h" 6#include "core/hle/service/nim/nim_u.h"
8 7
diff --git a/src/core/hle/service/ns_s.cpp b/src/core/hle/service/ns_s.cpp
index 99e8e0880..072918d62 100644
--- a/src/core/hle/service/ns_s.cpp
+++ b/src/core/hle/service/ns_s.cpp
@@ -2,8 +2,6 @@
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
6#include "core/hle/hle.h"
7#include "core/hle/service/ns_s.h" 5#include "core/hle/service/ns_s.h"
8 6
9//////////////////////////////////////////////////////////////////////////////////////////////////// 7////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -14,14 +12,19 @@ namespace NS_S {
14const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
15 {0x000100C0, nullptr, "LaunchFIRM"}, 13 {0x000100C0, nullptr, "LaunchFIRM"},
16 {0x000200C0, nullptr, "LaunchTitle"}, 14 {0x000200C0, nullptr, "LaunchTitle"},
15 {0x00030000, nullptr, "TerminateApplication"},
16 {0x00040040, nullptr, "TerminateProcess"},
17 {0x000500C0, nullptr, "LaunchApplicationFIRM"}, 17 {0x000500C0, nullptr, "LaunchApplicationFIRM"},
18 {0x00060042, nullptr, "SetFIRMParams4A0"}, 18 {0x00060042, nullptr, "SetFIRMParams4A0"},
19 {0x00070042, nullptr, "CardUpdateInitialize"}, 19 {0x00070042, nullptr, "CardUpdateInitialize"},
20 {0x000D0140, nullptr, "SetFIRMParams4B0"}, 20 {0x00080000, nullptr, "CardUpdateShutdown"},
21 {0x000D0140, nullptr, "SetTWLBannerHMAC"},
21 {0x000E0000, nullptr, "ShutdownAsync"}, 22 {0x000E0000, nullptr, "ShutdownAsync"},
22 {0x00100180, nullptr, "RebootSystem"}, 23 {0x00100180, nullptr, "RebootSystem"},
24 {0x00110100, nullptr, "TerminateTitle"},
25 {0x001200C0, nullptr, "SetApplicationCpuTimeLimit"},
23 {0x00150140, nullptr, "LaunchApplication"}, 26 {0x00150140, nullptr, "LaunchApplication"},
24 {0x00160000, nullptr, "HardRebootSystem"}, 27 {0x00160000, nullptr, "RebootSystemClean"},
25}; 28};
26 29
27//////////////////////////////////////////////////////////////////////////////////////////////////// 30////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp
index adca64a3a..dc80984b2 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -2,9 +2,9 @@
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 "common/common_types.h"
5#include "common/logging/log.h" 6#include "common/logging/log.h"
6 7
7#include "core/hle/hle.h"
8#include "core/hle/kernel/event.h" 8#include "core/hle/kernel/event.h"
9#include "core/hle/service/nwm_uds.h" 9#include "core/hle/service/nwm_uds.h"
10 10
diff --git a/src/core/hle/service/pm_app.cpp b/src/core/hle/service/pm_app.cpp
index 48646ed72..05d01bc48 100644
--- a/src/core/hle/service/pm_app.cpp
+++ b/src/core/hle/service/pm_app.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/pm_app.h" 5#include "core/hle/service/pm_app.h"
7 6
8//////////////////////////////////////////////////////////////////////////////////////////////////// 7////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
index 22c1093ff..6bdee4d9e 100644
--- a/src/core/hle/service/ptm/ptm.cpp
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -110,8 +110,8 @@ void Init() {
110 110
111 FileSys::Path gamecoin_path("gamecoin.dat"); 111 FileSys::Path gamecoin_path("gamecoin.dat");
112 FileSys::Mode open_mode = {}; 112 FileSys::Mode open_mode = {};
113 open_mode.write_flag = 1; 113 open_mode.write_flag.Assign(1);
114 open_mode.create_flag = 1; 114 open_mode.create_flag.Assign(1);
115 // Open the file and write the default gamecoin information 115 // Open the file and write the default gamecoin information
116 auto gamecoin_result = Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); 116 auto gamecoin_result = Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode);
117 if (gamecoin_result.Succeeded()) { 117 if (gamecoin_result.Succeeded()) {
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index f2e76441f..4cf7383d1 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -4,11 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array> 7#include "common/common_types.h"
8#include "core/hle/service/service.h"
9#include "core/hle/result.h"
10 8
11namespace Service { 9namespace Service {
10
11class Interface;
12
12namespace PTM { 13namespace PTM {
13 14
14/// Charge levels used by PTM functions 15/// Charge levels used by PTM functions
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 7bb990193..ca5dd0403 100644
--- a/src/core/hle/service/ptm/ptm_play.cpp
+++ b/src/core/hle/service/ptm/ptm_play.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/ptm/ptm_play.h" 5#include "core/hle/service/ptm/ptm_play.h"
7 6
8namespace Service { 7namespace Service {
diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp
index 3ecfab05c..fe76dd108 100644
--- a/src/core/hle/service/ptm/ptm_sysm.cpp
+++ b/src/core/hle/service/ptm/ptm_sysm.cpp
@@ -2,7 +2,6 @@
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 "core/hle/hle.h"
6#include "core/hle/service/ptm/ptm.h" 5#include "core/hle/service/ptm/ptm.h"
7#include "core/hle/service/ptm/ptm_sysm.h" 6#include "core/hle/service/ptm/ptm_sysm.h"
8 7
diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp
index 09dc38c3e..17e764866 100644
--- a/src/core/hle/service/ptm/ptm_u.cpp
+++ b/src/core/hle/service/ptm/ptm_u.cpp
@@ -2,9 +2,6 @@
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 "common/logging/log.h"
6
7#include "core/hle/hle.h"
8#include "core/hle/service/ptm/ptm.h" 5#include "core/hle/service/ptm/ptm.h"
9#include "core/hle/service/ptm/ptm_u.h" 6#include "core/hle/service/ptm/ptm_u.h"
10 7
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 822b093f4..e603bf794 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -178,17 +178,17 @@ struct CTRPollFD {
178 static Events TranslateTo3DS(u32 input_event) { 178 static Events TranslateTo3DS(u32 input_event) {
179 Events ev = {}; 179 Events ev = {};
180 if (input_event & POLLIN) 180 if (input_event & POLLIN)
181 ev.pollin = 1; 181 ev.pollin.Assign(1);
182 if (input_event & POLLPRI) 182 if (input_event & POLLPRI)
183 ev.pollpri = 1; 183 ev.pollpri.Assign(1);
184 if (input_event & POLLHUP) 184 if (input_event & POLLHUP)
185 ev.pollhup = 1; 185 ev.pollhup.Assign(1);
186 if (input_event & POLLERR) 186 if (input_event & POLLERR)
187 ev.pollerr = 1; 187 ev.pollerr.Assign(1);
188 if (input_event & POLLOUT) 188 if (input_event & POLLOUT)
189 ev.pollout = 1; 189 ev.pollout.Assign(1);
190 if (input_event & POLLNVAL) 190 if (input_event & POLLNVAL)
191 ev.pollnval = 1; 191 ev.pollnval.Assign(1);
192 return ev; 192 return ev;
193 } 193 }
194 194
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 3b8c7c0e4..41fc3437b 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -2,9 +2,9 @@
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 "common/common_types.h"
5#include "common/logging/log.h" 6#include "common/logging/log.h"
6 7
7#include "core/hle/hle.h"
8#include "core/hle/service/srv.h" 8#include "core/hle/service/srv.h"
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/event.h"
10 10
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp
index 9ecb72c77..fc7a4e6d3 100644
--- a/src/core/hle/service/ssl_c.cpp
+++ b/src/core/hle/service/ssl_c.cpp
@@ -4,7 +4,7 @@
4 4
5#include <random> 5#include <random>
6 6
7#include "core/hle/hle.h" 7#include "common/common_types.h"
8#include "core/hle/service/ssl_c.h" 8#include "core/hle/service/ssl_c.h"
9 9
10//////////////////////////////////////////////////////////////////////////////////////////////////// 10////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 69d0bf4a3..bbead9344 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -4,15 +4,15 @@
4 4
5#include <cstring> 5#include <cstring>
6 6
7#include "common/common_types.h"
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8 9
9#include "core/hle/hle.h"
10#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/kernel.h"
11#include "core/hle/service/y2r_u.h" 12#include "core/hle/service/y2r_u.h"
12#include "core/hw/y2r.h" 13#include "core/hw/y2r.h"
13 14
14#include "video_core/renderer_base.h" 15#include "video_core/renderer_base.h"
15#include "video_core/utils.h"
16#include "video_core/video_core.h" 16#include "video_core/video_core.h"
17 17
18//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 4bd3a632d..5312baa83 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -17,7 +17,6 @@
17#include "core/core_timing.h" 17#include "core/core_timing.h"
18 18
19#include "core/hle/service/gsp_gpu.h" 19#include "core/hle/service/gsp_gpu.h"
20#include "core/hle/service/dsp_dsp.h"
21#include "core/hle/service/hid/hid.h" 20#include "core/hle/service/hid/hid.h"
22 21
23#include "core/hw/hw.h" 22#include "core/hw/hw.h"
@@ -146,8 +145,8 @@ inline void Write(u32 addr, const T data) {
146 145
147 // Reset "trigger" flag and set the "finish" flag 146 // Reset "trigger" flag and set the "finish" flag
148 // NOTE: This was confirmed to happen on hardware even if "address_start" is zero. 147 // NOTE: This was confirmed to happen on hardware even if "address_start" is zero.
149 config.trigger = 0; 148 config.trigger.Assign(0);
150 config.finished = 1; 149 config.finished.Assign(1);
151 } 150 }
152 break; 151 break;
153 } 152 }
@@ -414,11 +413,6 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
414 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0); 413 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0);
415 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1); 414 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
416 415
417 // TODO(bunnei): Fake a DSP interrupt on each frame. This does not belong here, but
418 // until we can emulate DSP interrupts, this is probably the only reasonable place to do
419 // this. Certain games expect this to be periodically signaled.
420 DSP_DSP::SignalInterrupt();
421
422 // Check for user input updates 416 // Check for user input updates
423 Service::HID::Update(); 417 Service::HID::Update();
424 418
@@ -444,16 +438,16 @@ void Init() {
444 framebuffer_sub.address_left1 = 0x1848F000; 438 framebuffer_sub.address_left1 = 0x1848F000;
445 framebuffer_sub.address_left2 = 0x184C7800; 439 framebuffer_sub.address_left2 = 0x184C7800;
446 440
447 framebuffer_top.width = 240; 441 framebuffer_top.width.Assign(240);
448 framebuffer_top.height = 400; 442 framebuffer_top.height.Assign(400);
449 framebuffer_top.stride = 3 * 240; 443 framebuffer_top.stride = 3 * 240;
450 framebuffer_top.color_format = Regs::PixelFormat::RGB8; 444 framebuffer_top.color_format.Assign(Regs::PixelFormat::RGB8);
451 framebuffer_top.active_fb = 0; 445 framebuffer_top.active_fb = 0;
452 446
453 framebuffer_sub.width = 240; 447 framebuffer_sub.width.Assign(240);
454 framebuffer_sub.height = 320; 448 framebuffer_sub.height.Assign(320);
455 framebuffer_sub.stride = 3 * 240; 449 framebuffer_sub.stride = 3 * 240;
456 framebuffer_sub.color_format = Regs::PixelFormat::RGB8; 450 framebuffer_sub.color_format.Assign(Regs::PixelFormat::RGB8);
457 framebuffer_sub.active_fb = 0; 451 framebuffer_sub.active_fb = 0;
458 452
459 last_skip_frame = false; 453 last_skip_frame = false;
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 5d7264f12..69df94324 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -250,7 +250,7 @@ const char *ElfReader::GetSectionName(int section) const {
250 return nullptr; 250 return nullptr;
251 251
252 int name_offset = sections[section].sh_name; 252 int name_offset = sections[section].sh_name;
253 const char* ptr = (char*)GetSectionDataPtr(header->e_shstrndx); 253 const char* ptr = reinterpret_cast<const char*>(GetSectionDataPtr(header->e_shstrndx));
254 254
255 if (ptr) 255 if (ptr)
256 return ptr + name_offset; 256 return ptr + name_offset;
@@ -347,10 +347,10 @@ bool ElfReader::LoadSymbols() {
347 SectionID sec = GetSectionByName(".symtab"); 347 SectionID sec = GetSectionByName(".symtab");
348 if (sec != -1) { 348 if (sec != -1) {
349 int stringSection = sections[sec].sh_link; 349 int stringSection = sections[sec].sh_link;
350 const char *stringBase = (const char *)GetSectionDataPtr(stringSection); 350 const char *stringBase = reinterpret_cast<const char*>(GetSectionDataPtr(stringSection));
351 351
352 //We have a symbol table! 352 //We have a symbol table!
353 Elf32_Sym* symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); 353 const Elf32_Sym* symtab = reinterpret_cast<const Elf32_Sym*>(GetSectionDataPtr(sec));
354 unsigned int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); 354 unsigned int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
355 for (unsigned sym = 0; sym < numSymbols; sym++) { 355 for (unsigned sym = 0; sym < numSymbols; sym++) {
356 int size = symtab[sym].st_size; 356 int size = symtab[sym].st_size;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index fc79c3ee9..4753c63a7 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -13,6 +13,7 @@
13#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
14#include "core/memory.h" 14#include "core/memory.h"
15#include "core/memory_setup.h" 15#include "core/memory_setup.h"
16#include "core/mmio.h"
16 17
17namespace Memory { 18namespace Memory {
18 19
@@ -25,6 +26,12 @@ enum class PageType {
25 Special, 26 Special,
26}; 27};
27 28
29struct SpecialRegion {
30 VAddr base;
31 u32 size;
32 MMIORegionPointer handler;
33};
34
28/** 35/**
29 * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely 36 * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely
30 * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and 37 * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and
@@ -41,8 +48,13 @@ struct PageTable {
41 std::array<u8*, NUM_ENTRIES> pointers; 48 std::array<u8*, NUM_ENTRIES> pointers;
42 49
43 /** 50 /**
51 * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of type `Special`.
52 */
53 std::vector<SpecialRegion> special_regions;
54
55 /**
44 * Array of fine grained page attributes. If it is set to any value other than `Memory`, then 56 * Array of fine grained page attributes. If it is set to any value other than `Memory`, then
45 * the corresponding entry in `pointer` MUST be set to null. 57 * the corresponding entry in `pointers` MUST be set to null.
46 */ 58 */
47 std::array<PageType, NUM_ENTRIES> attributes; 59 std::array<PageType, NUM_ENTRIES> attributes;
48}; 60};
@@ -80,10 +92,12 @@ void MapMemoryRegion(VAddr base, u32 size, u8* target) {
80 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory); 92 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory);
81} 93}
82 94
83void MapIoRegion(VAddr base, u32 size) { 95void MapIoRegion(VAddr base, u32 size, MMIORegionPointer mmio_handler) {
84 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size); 96 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size);
85 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base); 97 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base);
86 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); 98 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special);
99
100 current_page_table->special_regions.emplace_back(SpecialRegion{base, size, mmio_handler});
87} 101}
88 102
89void UnmapRegion(VAddr base, u32 size) { 103void UnmapRegion(VAddr base, u32 size) {
@@ -92,6 +106,22 @@ void UnmapRegion(VAddr base, u32 size) {
92 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped); 106 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
93} 107}
94 108
109/**
110 * This function should only be called for virtual addreses with attribute `PageType::Special`.
111 */
112static MMIORegionPointer GetMMIOHandler(VAddr vaddr) {
113 for (const auto& region : current_page_table->special_regions) {
114 if (vaddr >= region.base && vaddr < (region.base + region.size)) {
115 return region.handler;
116 }
117 }
118 ASSERT_MSG(false, "Mapped IO page without a handler @ %08X", vaddr);
119 return nullptr; // Should never happen
120}
121
122template<typename T>
123T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr);
124
95template <typename T> 125template <typename T>
96T Read(const VAddr vaddr) { 126T Read(const VAddr vaddr) {
97 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 127 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
@@ -108,14 +138,17 @@ T Read(const VAddr vaddr) {
108 return 0; 138 return 0;
109 case PageType::Memory: 139 case PageType::Memory:
110 ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); 140 ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr);
141 break;
111 case PageType::Special: 142 case PageType::Special:
112 LOG_ERROR(HW_Memory, "I/O reads aren't implemented yet @ %08X", vaddr); 143 return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr);
113 return 0;
114 default: 144 default:
115 UNREACHABLE(); 145 UNREACHABLE();
116 } 146 }
117} 147}
118 148
149template<typename T>
150void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data);
151
119template <typename T> 152template <typename T>
120void Write(const VAddr vaddr, const T data) { 153void Write(const VAddr vaddr, const T data) {
121 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 154 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
@@ -131,9 +164,10 @@ void Write(const VAddr vaddr, const T data) {
131 return; 164 return;
132 case PageType::Memory: 165 case PageType::Memory:
133 ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); 166 ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr);
167 break;
134 case PageType::Special: 168 case PageType::Special:
135 LOG_ERROR(HW_Memory, "I/O writes aren't implemented yet @ %08X", vaddr); 169 WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data);
136 return; 170 break;
137 default: 171 default:
138 UNREACHABLE(); 172 UNREACHABLE();
139 } 173 }
@@ -191,6 +225,46 @@ void WriteBlock(const VAddr addr, const u8* data, const size_t size) {
191 } 225 }
192} 226}
193 227
228template<>
229u8 ReadMMIO<u8>(MMIORegionPointer mmio_handler, VAddr addr) {
230 return mmio_handler->Read8(addr);
231}
232
233template<>
234u16 ReadMMIO<u16>(MMIORegionPointer mmio_handler, VAddr addr) {
235 return mmio_handler->Read16(addr);
236}
237
238template<>
239u32 ReadMMIO<u32>(MMIORegionPointer mmio_handler, VAddr addr) {
240 return mmio_handler->Read32(addr);
241}
242
243template<>
244u64 ReadMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr) {
245 return mmio_handler->Read64(addr);
246}
247
248template<>
249void WriteMMIO<u8>(MMIORegionPointer mmio_handler, VAddr addr, const u8 data) {
250 mmio_handler->Write8(addr, data);
251}
252
253template<>
254void WriteMMIO<u16>(MMIORegionPointer mmio_handler, VAddr addr, const u16 data) {
255 mmio_handler->Write16(addr, data);
256}
257
258template<>
259void WriteMMIO<u32>(MMIORegionPointer mmio_handler, VAddr addr, const u32 data) {
260 mmio_handler->Write32(addr, data);
261}
262
263template<>
264void WriteMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr, const u64 data) {
265 mmio_handler->Write64(addr, data);
266}
267
194PAddr VirtualToPhysicalAddress(const VAddr addr) { 268PAddr VirtualToPhysicalAddress(const VAddr addr) {
195 if (addr == 0) { 269 if (addr == 0) {
196 return 0; 270 return 0;
diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h
index 84ff30120..05f70a1fe 100644
--- a/src/core/memory_setup.h
+++ b/src/core/memory_setup.h
@@ -23,10 +23,11 @@ void MapMemoryRegion(VAddr base, u32 size, u8* target);
23 23
24/** 24/**
25 * Maps a region of the emulated process address space as a IO region. 25 * Maps a region of the emulated process address space as a IO region.
26 * @note Currently this can only be used to mark a region as being IO, since actual memory-mapped 26 * @param base The address to start mapping at. Must be page-aligned.
27 * IO isn't yet supported. 27 * @param size The amount of bytes to map. Must be page-aligned.
28 * @param mmio_handler The handler that backs the mapping.
28 */ 29 */
29void MapIoRegion(VAddr base, u32 size); 30void MapIoRegion(VAddr base, u32 size, MMIORegionPointer mmio_handler);
30 31
31void UnmapRegion(VAddr base, u32 size); 32void UnmapRegion(VAddr base, u32 size);
32 33
diff --git a/src/core/mmio.h b/src/core/mmio.h
new file mode 100644
index 000000000..06b555e98
--- /dev/null
+++ b/src/core/mmio.h
@@ -0,0 +1,34 @@
1// Copyright 2016 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 <memory>
8
9#include "common/common_types.h"
10
11namespace Memory {
12
13/**
14 * Represents a device with memory mapped IO.
15 * A device may be mapped to multiple regions of memory.
16 */
17class MMIORegion {
18public:
19 virtual ~MMIORegion() = default;
20
21 virtual u8 Read8(VAddr addr) = 0;
22 virtual u16 Read16(VAddr addr) = 0;
23 virtual u32 Read32(VAddr addr) = 0;
24 virtual u64 Read64(VAddr addr) = 0;
25
26 virtual void Write8(VAddr addr, u8 data) = 0;
27 virtual void Write16(VAddr addr, u16 data) = 0;
28 virtual void Write32(VAddr addr, u32 data) = 0;
29 virtual void Write64(VAddr addr, u64 data) = 0;
30};
31
32using MMIORegionPointer = std::shared_ptr<MMIORegion>;
33
34};
diff --git a/src/core/system.cpp b/src/core/system.cpp
index 7e9c56538..b62ebf69e 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -2,9 +2,12 @@
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/audio_core.h"
6
5#include "core/core.h" 7#include "core/core.h"
6#include "core/core_timing.h" 8#include "core/core_timing.h"
7#include "core/system.h" 9#include "core/system.h"
10#include "core/gdbstub/gdbstub.h"
8#include "core/hw/hw.h" 11#include "core/hw/hw.h"
9#include "core/hle/hle.h" 12#include "core/hle/hle.h"
10#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
@@ -12,8 +15,6 @@
12 15
13#include "video_core/video_core.h" 16#include "video_core/video_core.h"
14 17
15#include "core/gdbstub/gdbstub.h"
16
17namespace System { 18namespace System {
18 19
19void Init(EmuWindow* emu_window) { 20void Init(EmuWindow* emu_window) {
@@ -24,11 +25,13 @@ void Init(EmuWindow* emu_window) {
24 Kernel::Init(); 25 Kernel::Init();
25 HLE::Init(); 26 HLE::Init();
26 VideoCore::Init(emu_window); 27 VideoCore::Init(emu_window);
28 AudioCore::Init();
27 GDBStub::Init(); 29 GDBStub::Init();
28} 30}
29 31
30void Shutdown() { 32void Shutdown() {
31 GDBStub::Shutdown(); 33 GDBStub::Shutdown();
34 AudioCore::Shutdown();
32 VideoCore::Shutdown(); 35 VideoCore::Shutdown();
33 HLE::Shutdown(); 36 HLE::Shutdown();
34 Kernel::Shutdown(); 37 Kernel::Shutdown();
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index c3d7294d5..4b5d298f3 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -33,6 +33,7 @@ set(HEADERS
33 command_processor.h 33 command_processor.h
34 gpu_debugger.h 34 gpu_debugger.h
35 pica.h 35 pica.h
36 pica_types.h
36 primitive_assembly.h 37 primitive_assembly.h
37 rasterizer.h 38 rasterizer.h
38 rasterizer_interface.h 39 rasterizer_interface.h
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
index 5d609da06..a385589d2 100644
--- a/src/video_core/clipper.cpp
+++ b/src/video_core/clipper.cpp
@@ -59,15 +59,17 @@ static void InitScreenCoordinates(OutputVertex& vtx)
59 } viewport; 59 } viewport;
60 60
61 const auto& regs = g_state.regs; 61 const auto& regs = g_state.regs;
62 viewport.halfsize_x = float24::FromRawFloat24(regs.viewport_size_x); 62 viewport.halfsize_x = float24::FromRaw(regs.viewport_size_x);
63 viewport.halfsize_y = float24::FromRawFloat24(regs.viewport_size_y); 63 viewport.halfsize_y = float24::FromRaw(regs.viewport_size_y);
64 viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.viewport_corner.x)); 64 viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.viewport_corner.x));
65 viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.viewport_corner.y)); 65 viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.viewport_corner.y));
66 viewport.zscale = float24::FromRawFloat24(regs.viewport_depth_range); 66 viewport.zscale = float24::FromRaw(regs.viewport_depth_range);
67 viewport.offset_z = float24::FromRawFloat24(regs.viewport_depth_far_plane); 67 viewport.offset_z = float24::FromRaw(regs.viewport_depth_far_plane);
68 68
69 float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w; 69 float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w;
70 vtx.color *= inv_w; 70 vtx.color *= inv_w;
71 vtx.view *= inv_w;
72 vtx.quat *= inv_w;
71 vtx.tc0 *= inv_w; 73 vtx.tc0 *= inv_w;
72 vtx.tc1 *= inv_w; 74 vtx.tc1 *= inv_w;
73 vtx.tc2 *= inv_w; 75 vtx.tc2 *= inv_w;
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 35b976c60..73fdfbe9c 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -98,10 +98,10 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
98 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index]; 98 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
99 99
100 // NOTE: The destination component order indeed is "backwards" 100 // NOTE: The destination component order indeed is "backwards"
101 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8); 101 attribute.w = float24::FromRaw(default_attr_write_buffer[0] >> 8);
102 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF)); 102 attribute.z = float24::FromRaw(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
103 attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF)); 103 attribute.y = float24::FromRaw(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF));
104 attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF); 104 attribute.x = float24::FromRaw(default_attr_write_buffer[2] & 0xFFFFFF);
105 105
106 LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index, 106 LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index,
107 attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(), 107 attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(),
@@ -157,15 +157,25 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
157 157
158 // TODO: What happens if a loader overwrites a previous one's data? 158 // TODO: What happens if a loader overwrites a previous one's data?
159 for (unsigned component = 0; component < loader_config.component_count; ++component) { 159 for (unsigned component = 0; component < loader_config.component_count; ++component) {
160 if (component >= 12) 160 if (component >= 12) {
161 LOG_ERROR(HW_GPU, "Overflow in the vertex attribute loader %u trying to load component %u", loader, component); 161 LOG_ERROR(HW_GPU, "Overflow in the vertex attribute loader %u trying to load component %u", loader, component);
162 continue;
163 }
164
162 u32 attribute_index = loader_config.GetComponent(component); 165 u32 attribute_index = loader_config.GetComponent(component);
163 vertex_attribute_sources[attribute_index] = load_address; 166 if (attribute_index < 12) {
164 vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); 167 vertex_attribute_sources[attribute_index] = load_address;
165 vertex_attribute_formats[attribute_index] = attribute_config.GetFormat(attribute_index); 168 vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
166 vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index); 169 vertex_attribute_formats[attribute_index] = attribute_config.GetFormat(attribute_index);
167 vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index); 170 vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index);
168 load_address += attribute_config.GetStride(attribute_index); 171 vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index);
172 load_address += attribute_config.GetStride(attribute_index);
173 } else if (attribute_index < 16) {
174 // Attribute ids 12, 13, 14 and 15 signify 4, 8, 12 and 16-byte paddings, respectively
175 load_address += (attribute_index - 11) * 4;
176 } else {
177 UNREACHABLE(); // This is truly unreachable due to the number of bits for each component
178 }
169 } 179 }
170 } 180 }
171 181
@@ -418,10 +428,10 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
418 uniform[3 - i] = float24::FromFloat32(*(float*)(&uniform_write_buffer[i])); 428 uniform[3 - i] = float24::FromFloat32(*(float*)(&uniform_write_buffer[i]));
419 } else { 429 } else {
420 // TODO: Untested 430 // TODO: Untested
421 uniform.w = float24::FromRawFloat24(uniform_write_buffer[0] >> 8); 431 uniform.w = float24::FromRaw(uniform_write_buffer[0] >> 8);
422 uniform.z = float24::FromRawFloat24(((uniform_write_buffer[0] & 0xFF)<<16) | ((uniform_write_buffer[1] >> 16) & 0xFFFF)); 432 uniform.z = float24::FromRaw(((uniform_write_buffer[0] & 0xFF) << 16) | ((uniform_write_buffer[1] >> 16) & 0xFFFF));
423 uniform.y = float24::FromRawFloat24(((uniform_write_buffer[1] & 0xFFFF)<<8) | ((uniform_write_buffer[2] >> 24) & 0xFF)); 433 uniform.y = float24::FromRaw(((uniform_write_buffer[1] & 0xFFFF) << 8) | ((uniform_write_buffer[2] >> 24) & 0xFF));
424 uniform.x = float24::FromRawFloat24(uniform_write_buffer[2] & 0xFFFFFF); 434 uniform.x = float24::FromRaw(uniform_write_buffer[2] & 0xFFFFFF);
425 } 435 }
426 436
427 LOG_TRACE(HW_GPU, "Set uniform %x to (%f %f %f %f)", (int)uniform_setup.index, 437 LOG_TRACE(HW_GPU, "Set uniform %x to (%f %f %f %f)", (int)uniform_setup.index,
@@ -429,7 +439,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
429 uniform.w.ToFloat32()); 439 uniform.w.ToFloat32());
430 440
431 // TODO: Verify that this actually modifies the register! 441 // TODO: Verify that this actually modifies the register!
432 uniform_setup.index = uniform_setup.index + 1; 442 uniform_setup.index.Assign(uniform_setup.index + 1);
433 } 443 }
434 break; 444 break;
435 } 445 }
@@ -464,6 +474,24 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
464 break; 474 break;
465 } 475 }
466 476
477 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[0], 0x1c8):
478 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[1], 0x1c9):
479 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[2], 0x1ca):
480 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[3], 0x1cb):
481 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[4], 0x1cc):
482 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[5], 0x1cd):
483 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce):
484 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf):
485 {
486 auto& lut_config = regs.lighting.lut_config;
487
488 ASSERT_MSG(lut_config.index < 256, "lut_config.index exceeded maximum value of 255!");
489
490 g_state.lighting.luts[lut_config.type][lut_config.index].raw = value;
491 lut_config.index.Assign(lut_config.index + 1);
492 break;
493 }
494
467 default: 495 default:
468 break; 496 break;
469 } 497 }
@@ -486,9 +514,8 @@ void ProcessCommandList(const u32* list, u32 size) {
486 514
487 u32 value = *g_state.cmd_list.current_ptr++; 515 u32 value = *g_state.cmd_list.current_ptr++;
488 const CommandHeader header = { *g_state.cmd_list.current_ptr++ }; 516 const CommandHeader header = { *g_state.cmd_list.current_ptr++ };
489 u32 cmd = header.cmd_id;
490 517
491 WritePicaReg(cmd, value, header.parameter_mask); 518 WritePicaReg(header.cmd_id, value, header.parameter_mask);
492 519
493 for (unsigned i = 0; i < header.extra_data_length; ++i) { 520 for (unsigned i = 0; i < header.extra_data_length; ++i) {
494 u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0); 521 u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0);
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 4f66dbd65..6e6fd7335 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -201,11 +201,11 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, c
201 201
202 if (it == output_info_table.end()) { 202 if (it == output_info_table.end()) {
203 output_info_table.emplace_back(); 203 output_info_table.emplace_back();
204 output_info_table.back().type = type; 204 output_info_table.back().type.Assign(type);
205 output_info_table.back().component_mask = component_mask; 205 output_info_table.back().component_mask.Assign(component_mask);
206 output_info_table.back().id = i; 206 output_info_table.back().id.Assign(i);
207 } else { 207 } else {
208 it->component_mask = it->component_mask | component_mask; 208 it->component_mask.Assign(it->component_mask | component_mask);
209 } 209 }
210 } catch (const std::out_of_range& ) { 210 } catch (const std::out_of_range& ) {
211 DEBUG_ASSERT_MSG(false, "Unknown output attribute mapping"); 211 DEBUG_ASSERT_MSG(false, "Unknown output attribute mapping");
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
index 8c528989e..d7b31384a 100644
--- a/src/video_core/pica.cpp
+++ b/src/video_core/pica.cpp
@@ -12,66 +12,474 @@ namespace Pica {
12 12
13State g_state; 13State g_state;
14 14
15static const std::pair<u16, const char*> register_names[] = {
16 { 0x010, "GPUREG_FINALIZE" },
17
18 { 0x040, "GPUREG_FACECULLING_CONFIG" },
19 { 0x041, "GPUREG_VIEWPORT_WIDTH" },
20 { 0x042, "GPUREG_VIEWPORT_INVW" },
21 { 0x043, "GPUREG_VIEWPORT_HEIGHT" },
22 { 0x044, "GPUREG_VIEWPORT_INVH" },
23
24 { 0x047, "GPUREG_FRAGOP_CLIP" },
25 { 0x048, "GPUREG_FRAGOP_CLIP_DATA0" },
26 { 0x049, "GPUREG_FRAGOP_CLIP_DATA1" },
27 { 0x04A, "GPUREG_FRAGOP_CLIP_DATA2" },
28 { 0x04B, "GPUREG_FRAGOP_CLIP_DATA3" },
29
30 { 0x04D, "GPUREG_DEPTHMAP_SCALE" },
31 { 0x04E, "GPUREG_DEPTHMAP_OFFSET" },
32 { 0x04F, "GPUREG_SH_OUTMAP_TOTAL" },
33 { 0x050, "GPUREG_SH_OUTMAP_O0" },
34 { 0x051, "GPUREG_SH_OUTMAP_O1" },
35 { 0x052, "GPUREG_SH_OUTMAP_O2" },
36 { 0x053, "GPUREG_SH_OUTMAP_O3" },
37 { 0x054, "GPUREG_SH_OUTMAP_O4" },
38 { 0x055, "GPUREG_SH_OUTMAP_O5" },
39 { 0x056, "GPUREG_SH_OUTMAP_O6" },
40
41 { 0x061, "GPUREG_EARLYDEPTH_FUNC" },
42 { 0x062, "GPUREG_EARLYDEPTH_TEST1" },
43 { 0x063, "GPUREG_EARLYDEPTH_CLEAR" },
44 { 0x064, "GPUREG_SH_OUTATTR_MODE" },
45 { 0x065, "GPUREG_SCISSORTEST_MODE" },
46 { 0x066, "GPUREG_SCISSORTEST_POS" },
47 { 0x067, "GPUREG_SCISSORTEST_DIM" },
48 { 0x068, "GPUREG_VIEWPORT_XY" },
49
50 { 0x06A, "GPUREG_EARLYDEPTH_DATA" },
51
52 { 0x06D, "GPUREG_DEPTHMAP_ENABLE" },
53 { 0x06E, "GPUREG_RENDERBUF_DIM" },
54 { 0x06F, "GPUREG_SH_OUTATTR_CLOCK" },
55
56 { 0x080, "GPUREG_TEXUNIT_CONFIG" },
57 { 0x081, "GPUREG_TEXUNIT0_BORDER_COLOR" },
58 { 0x082, "GPUREG_TEXUNIT0_DIM" },
59 { 0x083, "GPUREG_TEXUNIT0_PARAM" },
60 { 0x084, "GPUREG_TEXUNIT0_LOD" },
61 { 0x085, "GPUREG_TEXUNIT0_ADDR1" },
62 { 0x086, "GPUREG_TEXUNIT0_ADDR2" },
63 { 0x087, "GPUREG_TEXUNIT0_ADDR3" },
64 { 0x088, "GPUREG_TEXUNIT0_ADDR4" },
65 { 0x089, "GPUREG_TEXUNIT0_ADDR5" },
66 { 0x08A, "GPUREG_TEXUNIT0_ADDR6" },
67 { 0x08B, "GPUREG_TEXUNIT0_SHADOW" },
68
69 { 0x08E, "GPUREG_TEXUNIT0_TYPE" },
70 { 0x08F, "GPUREG_LIGHTING_ENABLE0" },
71
72 { 0x091, "GPUREG_TEXUNIT1_BORDER_COLOR" },
73 { 0x092, "GPUREG_TEXUNIT1_DIM" },
74 { 0x093, "GPUREG_TEXUNIT1_PARAM" },
75 { 0x094, "GPUREG_TEXUNIT1_LOD" },
76 { 0x095, "GPUREG_TEXUNIT1_ADDR" },
77 { 0x096, "GPUREG_TEXUNIT1_TYPE" },
78
79 { 0x099, "GPUREG_TEXUNIT2_BORDER_COLOR" },
80 { 0x09A, "GPUREG_TEXUNIT2_DIM" },
81 { 0x09B, "GPUREG_TEXUNIT2_PARAM" },
82 { 0x09C, "GPUREG_TEXUNIT2_LOD" },
83 { 0x09D, "GPUREG_TEXUNIT2_ADDR" },
84 { 0x09E, "GPUREG_TEXUNIT2_TYPE" },
85
86 { 0x0A8, "GPUREG_TEXUNIT3_PROCTEX0" },
87 { 0x0A9, "GPUREG_TEXUNIT3_PROCTEX1" },
88 { 0x0AA, "GPUREG_TEXUNIT3_PROCTEX2" },
89 { 0x0AB, "GPUREG_TEXUNIT3_PROCTEX3" },
90 { 0x0AC, "GPUREG_TEXUNIT3_PROCTEX4" },
91 { 0x0AD, "GPUREG_TEXUNIT3_PROCTEX5" },
92
93 { 0x0AF, "GPUREG_PROCTEX_LUT" },
94 { 0x0B0, "GPUREG_PROCTEX_LUT_DATA0" },
95 { 0x0B1, "GPUREG_PROCTEX_LUT_DATA1" },
96 { 0x0B2, "GPUREG_PROCTEX_LUT_DATA2" },
97 { 0x0B3, "GPUREG_PROCTEX_LUT_DATA3" },
98 { 0x0B4, "GPUREG_PROCTEX_LUT_DATA4" },
99 { 0x0B5, "GPUREG_PROCTEX_LUT_DATA5" },
100 { 0x0B6, "GPUREG_PROCTEX_LUT_DATA6" },
101 { 0x0B7, "GPUREG_PROCTEX_LUT_DATA7" },
102
103 { 0x0C0, "GPUREG_TEXENV0_SOURCE" },
104 { 0x0C1, "GPUREG_TEXENV0_OPERAND" },
105 { 0x0C2, "GPUREG_TEXENV0_COMBINER" },
106 { 0x0C3, "GPUREG_TEXENV0_COLOR" },
107 { 0x0C4, "GPUREG_TEXENV0_SCALE" },
108
109 { 0x0C8, "GPUREG_TEXENV1_SOURCE" },
110 { 0x0C9, "GPUREG_TEXENV1_OPERAND" },
111 { 0x0CA, "GPUREG_TEXENV1_COMBINER" },
112 { 0x0CB, "GPUREG_TEXENV1_COLOR" },
113 { 0x0CC, "GPUREG_TEXENV1_SCALE" },
114
115 { 0x0D0, "GPUREG_TEXENV2_SOURCE" },
116 { 0x0D1, "GPUREG_TEXENV2_OPERAND" },
117 { 0x0D2, "GPUREG_TEXENV2_COMBINER" },
118 { 0x0D3, "GPUREG_TEXENV2_COLOR" },
119 { 0x0D4, "GPUREG_TEXENV2_SCALE" },
120
121 { 0x0D8, "GPUREG_TEXENV3_SOURCE" },
122 { 0x0D9, "GPUREG_TEXENV3_OPERAND" },
123 { 0x0DA, "GPUREG_TEXENV3_COMBINER" },
124 { 0x0DB, "GPUREG_TEXENV3_COLOR" },
125 { 0x0DC, "GPUREG_TEXENV3_SCALE" },
126
127 { 0x0E0, "GPUREG_TEXENV_UPDATE_BUFFER" },
128 { 0x0E1, "GPUREG_FOG_COLOR" },
129
130 { 0x0E4, "GPUREG_GAS_ATTENUATION" },
131 { 0x0E5, "GPUREG_GAS_ACCMAX" },
132 { 0x0E6, "GPUREG_FOG_LUT_INDEX" },
133
134 { 0x0E8, "GPUREG_FOG_LUT_DATA0" },
135 { 0x0E9, "GPUREG_FOG_LUT_DATA1" },
136 { 0x0EA, "GPUREG_FOG_LUT_DATA2" },
137 { 0x0EB, "GPUREG_FOG_LUT_DATA3" },
138 { 0x0EC, "GPUREG_FOG_LUT_DATA4" },
139 { 0x0ED, "GPUREG_FOG_LUT_DATA5" },
140 { 0x0EE, "GPUREG_FOG_LUT_DATA6" },
141 { 0x0EF, "GPUREG_FOG_LUT_DATA7" },
142 { 0x0F0, "GPUREG_TEXENV4_SOURCE" },
143 { 0x0F1, "GPUREG_TEXENV4_OPERAND" },
144 { 0x0F2, "GPUREG_TEXENV4_COMBINER" },
145 { 0x0F3, "GPUREG_TEXENV4_COLOR" },
146 { 0x0F4, "GPUREG_TEXENV4_SCALE" },
147
148 { 0x0F8, "GPUREG_TEXENV5_SOURCE" },
149 { 0x0F9, "GPUREG_TEXENV5_OPERAND" },
150 { 0x0FA, "GPUREG_TEXENV5_COMBINER" },
151 { 0x0FB, "GPUREG_TEXENV5_COLOR" },
152 { 0x0FC, "GPUREG_TEXENV5_SCALE" },
153 { 0x0FD, "GPUREG_TEXENV_BUFFER_COLOR" },
154
155 { 0x100, "GPUREG_COLOR_OPERATION" },
156 { 0x101, "GPUREG_BLEND_FUNC" },
157 { 0x102, "GPUREG_LOGIC_OP" },
158 { 0x103, "GPUREG_BLEND_COLOR" },
159 { 0x104, "GPUREG_FRAGOP_ALPHA_TEST" },
160 { 0x105, "GPUREG_STENCIL_TEST" },
161 { 0x106, "GPUREG_STENCIL_OP" },
162 { 0x107, "GPUREG_DEPTH_COLOR_MASK" },
163
164 { 0x110, "GPUREG_FRAMEBUFFER_INVALIDATE" },
165 { 0x111, "GPUREG_FRAMEBUFFER_FLUSH" },
166 { 0x112, "GPUREG_COLORBUFFER_READ" },
167 { 0x113, "GPUREG_COLORBUFFER_WRITE" },
168 { 0x114, "GPUREG_DEPTHBUFFER_READ" },
169 { 0x115, "GPUREG_DEPTHBUFFER_WRITE" },
170 { 0x116, "GPUREG_DEPTHBUFFER_FORMAT" },
171 { 0x117, "GPUREG_COLORBUFFER_FORMAT" },
172 { 0x118, "GPUREG_EARLYDEPTH_TEST2" },
173
174 { 0x11B, "GPUREG_FRAMEBUFFER_BLOCK32" },
175 { 0x11C, "GPUREG_DEPTHBUFFER_LOC" },
176 { 0x11D, "GPUREG_COLORBUFFER_LOC" },
177 { 0x11E, "GPUREG_FRAMEBUFFER_DIM" },
178
179 { 0x120, "GPUREG_GAS_LIGHT_XY" },
180 { 0x121, "GPUREG_GAS_LIGHT_Z" },
181 { 0x122, "GPUREG_GAS_LIGHT_Z_COLOR" },
182 { 0x123, "GPUREG_GAS_LUT_INDEX" },
183 { 0x124, "GPUREG_GAS_LUT_DATA" },
184
185 { 0x126, "GPUREG_GAS_DELTAZ_DEPTH" },
186
187 { 0x130, "GPUREG_FRAGOP_SHADOW" },
188
189 { 0x140, "GPUREG_LIGHT0_SPECULAR0" },
190 { 0x141, "GPUREG_LIGHT0_SPECULAR1" },
191 { 0x142, "GPUREG_LIGHT0_DIFFUSE" },
192 { 0x143, "GPUREG_LIGHT0_AMBIENT" },
193 { 0x144, "GPUREG_LIGHT0_XY" },
194 { 0x145, "GPUREG_LIGHT0_Z" },
195 { 0x146, "GPUREG_LIGHT0_SPOTDIR_XY" },
196 { 0x147, "GPUREG_LIGHT0_SPOTDIR_Z" },
197
198 { 0x149, "GPUREG_LIGHT0_CONFIG" },
199 { 0x14A, "GPUREG_LIGHT0_ATTENUATION_BIAS" },
200 { 0x14B, "GPUREG_LIGHT0_ATTENUATION_SCALE" },
201
202 { 0x150, "GPUREG_LIGHT1_SPECULAR0" },
203 { 0x151, "GPUREG_LIGHT1_SPECULAR1" },
204 { 0x152, "GPUREG_LIGHT1_DIFFUSE" },
205 { 0x153, "GPUREG_LIGHT1_AMBIENT" },
206 { 0x154, "GPUREG_LIGHT1_XY" },
207 { 0x155, "GPUREG_LIGHT1_Z" },
208 { 0x156, "GPUREG_LIGHT1_SPOTDIR_XY" },
209 { 0x157, "GPUREG_LIGHT1_SPOTDIR_Z" },
210
211 { 0x159, "GPUREG_LIGHT1_CONFIG" },
212 { 0x15A, "GPUREG_LIGHT1_ATTENUATION_BIAS" },
213 { 0x15B, "GPUREG_LIGHT1_ATTENUATION_SCALE" },
214
215 { 0x160, "GPUREG_LIGHT2_SPECULAR0" },
216 { 0x161, "GPUREG_LIGHT2_SPECULAR1" },
217 { 0x162, "GPUREG_LIGHT2_DIFFUSE" },
218 { 0x163, "GPUREG_LIGHT2_AMBIENT" },
219 { 0x164, "GPUREG_LIGHT2_XY" },
220 { 0x165, "GPUREG_LIGHT2_Z" },
221 { 0x166, "GPUREG_LIGHT2_SPOTDIR_XY" },
222 { 0x167, "GPUREG_LIGHT2_SPOTDIR_Z" },
223
224 { 0x169, "GPUREG_LIGHT2_CONFIG" },
225 { 0x16A, "GPUREG_LIGHT2_ATTENUATION_BIAS" },
226 { 0x16B, "GPUREG_LIGHT2_ATTENUATION_SCALE" },
227
228 { 0x170, "GPUREG_LIGHT3_SPECULAR0" },
229 { 0x171, "GPUREG_LIGHT3_SPECULAR1" },
230 { 0x172, "GPUREG_LIGHT3_DIFFUSE" },
231 { 0x173, "GPUREG_LIGHT3_AMBIENT" },
232 { 0x174, "GPUREG_LIGHT3_XY" },
233 { 0x175, "GPUREG_LIGHT3_Z" },
234 { 0x176, "GPUREG_LIGHT3_SPOTDIR_XY" },
235 { 0x177, "GPUREG_LIGHT3_SPOTDIR_Z" },
236
237 { 0x179, "GPUREG_LIGHT3_CONFIG" },
238 { 0x17A, "GPUREG_LIGHT3_ATTENUATION_BIAS" },
239 { 0x17B, "GPUREG_LIGHT3_ATTENUATION_SCALE" },
240
241 { 0x180, "GPUREG_LIGHT4_SPECULAR0" },
242 { 0x181, "GPUREG_LIGHT4_SPECULAR1" },
243 { 0x182, "GPUREG_LIGHT4_DIFFUSE" },
244 { 0x183, "GPUREG_LIGHT4_AMBIENT" },
245 { 0x184, "GPUREG_LIGHT4_XY" },
246 { 0x185, "GPUREG_LIGHT4_Z" },
247 { 0x186, "GPUREG_LIGHT4_SPOTDIR_XY" },
248 { 0x187, "GPUREG_LIGHT4_SPOTDIR_Z" },
249
250 { 0x189, "GPUREG_LIGHT4_CONFIG" },
251 { 0x18A, "GPUREG_LIGHT4_ATTENUATION_BIAS" },
252 { 0x18B, "GPUREG_LIGHT4_ATTENUATION_SCALE" },
253
254 { 0x190, "GPUREG_LIGHT5_SPECULAR0" },
255 { 0x191, "GPUREG_LIGHT5_SPECULAR1" },
256 { 0x192, "GPUREG_LIGHT5_DIFFUSE" },
257 { 0x193, "GPUREG_LIGHT5_AMBIENT" },
258 { 0x194, "GPUREG_LIGHT5_XY" },
259 { 0x195, "GPUREG_LIGHT5_Z" },
260 { 0x196, "GPUREG_LIGHT5_SPOTDIR_XY" },
261 { 0x197, "GPUREG_LIGHT5_SPOTDIR_Z" },
262
263 { 0x199, "GPUREG_LIGHT5_CONFIG" },
264 { 0x19A, "GPUREG_LIGHT5_ATTENUATION_BIAS" },
265 { 0x19B, "GPUREG_LIGHT5_ATTENUATION_SCALE" },
266
267 { 0x1A0, "GPUREG_LIGHT6_SPECULAR0" },
268 { 0x1A1, "GPUREG_LIGHT6_SPECULAR1" },
269 { 0x1A2, "GPUREG_LIGHT6_DIFFUSE" },
270 { 0x1A3, "GPUREG_LIGHT6_AMBIENT" },
271 { 0x1A4, "GPUREG_LIGHT6_XY" },
272 { 0x1A5, "GPUREG_LIGHT6_Z" },
273 { 0x1A6, "GPUREG_LIGHT6_SPOTDIR_XY" },
274 { 0x1A7, "GPUREG_LIGHT6_SPOTDIR_Z" },
275
276 { 0x1A9, "GPUREG_LIGHT6_CONFIG" },
277 { 0x1AA, "GPUREG_LIGHT6_ATTENUATION_BIAS" },
278 { 0x1AB, "GPUREG_LIGHT6_ATTENUATION_SCALE" },
279
280 { 0x1B0, "GPUREG_LIGHT7_SPECULAR0" },
281 { 0x1B1, "GPUREG_LIGHT7_SPECULAR1" },
282 { 0x1B2, "GPUREG_LIGHT7_DIFFUSE" },
283 { 0x1B3, "GPUREG_LIGHT7_AMBIENT" },
284 { 0x1B4, "GPUREG_LIGHT7_XY" },
285 { 0x1B5, "GPUREG_LIGHT7_Z" },
286 { 0x1B6, "GPUREG_LIGHT7_SPOTDIR_XY" },
287 { 0x1B7, "GPUREG_LIGHT7_SPOTDIR_Z" },
288
289 { 0x1B9, "GPUREG_LIGHT7_CONFIG" },
290 { 0x1BA, "GPUREG_LIGHT7_ATTENUATION_BIAS" },
291 { 0x1BB, "GPUREG_LIGHT7_ATTENUATION_SCALE" },
292
293 { 0x1C0, "GPUREG_LIGHTING_AMBIENT" },
294
295 { 0x1C2, "GPUREG_LIGHTING_NUM_LIGHTS" },
296 { 0x1C3, "GPUREG_LIGHTING_CONFIG0" },
297 { 0x1C4, "GPUREG_LIGHTING_CONFIG1" },
298 { 0x1C5, "GPUREG_LIGHTING_LUT_INDEX" },
299 { 0x1C6, "GPUREG_LIGHTING_ENABLE1" },
300
301 { 0x1C8, "GPUREG_LIGHTING_LUT_DATA0" },
302 { 0x1C9, "GPUREG_LIGHTING_LUT_DATA1" },
303 { 0x1CA, "GPUREG_LIGHTING_LUT_DATA2" },
304 { 0x1CB, "GPUREG_LIGHTING_LUT_DATA3" },
305 { 0x1CC, "GPUREG_LIGHTING_LUT_DATA4" },
306 { 0x1CD, "GPUREG_LIGHTING_LUT_DATA5" },
307 { 0x1CE, "GPUREG_LIGHTING_LUT_DATA6" },
308 { 0x1CF, "GPUREG_LIGHTING_LUT_DATA7" },
309 { 0x1D0, "GPUREG_LIGHTING_LUTINPUT_ABS" },
310 { 0x1D1, "GPUREG_LIGHTING_LUTINPUT_SELECT" },
311 { 0x1D2, "GPUREG_LIGHTING_LUTINPUT_SCALE" },
312
313 { 0x1D9, "GPUREG_LIGHTING_LIGHT_PERMUTATION" },
314
315 { 0x200, "GPUREG_ATTRIBBUFFERS_LOC" },
316 { 0x201, "GPUREG_ATTRIBBUFFERS_FORMAT_LOW" },
317 { 0x202, "GPUREG_ATTRIBBUFFERS_FORMAT_HIGH" },
318 { 0x203, "GPUREG_ATTRIBBUFFER0_OFFSET" },
319 { 0x204, "GPUREG_ATTRIBBUFFER0_CONFIG1" },
320 { 0x205, "GPUREG_ATTRIBBUFFER0_CONFIG2" },
321 { 0x206, "GPUREG_ATTRIBBUFFER1_OFFSET" },
322 { 0x207, "GPUREG_ATTRIBBUFFER1_CONFIG1" },
323 { 0x208, "GPUREG_ATTRIBBUFFER1_CONFIG2" },
324 { 0x209, "GPUREG_ATTRIBBUFFER2_OFFSET" },
325 { 0x20A, "GPUREG_ATTRIBBUFFER2_CONFIG1" },
326 { 0x20B, "GPUREG_ATTRIBBUFFER2_CONFIG2" },
327 { 0x20C, "GPUREG_ATTRIBBUFFER3_OFFSET" },
328 { 0x20D, "GPUREG_ATTRIBBUFFER3_CONFIG1" },
329 { 0x20E, "GPUREG_ATTRIBBUFFER3_CONFIG2" },
330 { 0x20F, "GPUREG_ATTRIBBUFFER4_OFFSET" },
331 { 0x210, "GPUREG_ATTRIBBUFFER4_CONFIG1" },
332 { 0x211, "GPUREG_ATTRIBBUFFER4_CONFIG2" },
333 { 0x212, "GPUREG_ATTRIBBUFFER5_OFFSET" },
334 { 0x213, "GPUREG_ATTRIBBUFFER5_CONFIG1" },
335 { 0x214, "GPUREG_ATTRIBBUFFER5_CONFIG2" },
336 { 0x215, "GPUREG_ATTRIBBUFFER6_OFFSET" },
337 { 0x216, "GPUREG_ATTRIBBUFFER6_CONFIG1" },
338 { 0x217, "GPUREG_ATTRIBBUFFER6_CONFIG2" },
339 { 0x218, "GPUREG_ATTRIBBUFFER7_OFFSET" },
340 { 0x219, "GPUREG_ATTRIBBUFFER7_CONFIG1" },
341 { 0x21A, "GPUREG_ATTRIBBUFFER7_CONFIG2" },
342 { 0x21B, "GPUREG_ATTRIBBUFFER8_OFFSET" },
343 { 0x21C, "GPUREG_ATTRIBBUFFER8_CONFIG1" },
344 { 0x21D, "GPUREG_ATTRIBBUFFER8_CONFIG2" },
345 { 0x21E, "GPUREG_ATTRIBBUFFER9_OFFSET" },
346 { 0x21F, "GPUREG_ATTRIBBUFFER9_CONFIG1" },
347 { 0x220, "GPUREG_ATTRIBBUFFER9_CONFIG2" },
348 { 0x221, "GPUREG_ATTRIBBUFFER10_OFFSET" },
349 { 0x222, "GPUREG_ATTRIBBUFFER10_CONFIG1" },
350 { 0x223, "GPUREG_ATTRIBBUFFER10_CONFIG2" },
351 { 0x224, "GPUREG_ATTRIBBUFFER11_OFFSET" },
352 { 0x225, "GPUREG_ATTRIBBUFFER11_CONFIG1" },
353 { 0x226, "GPUREG_ATTRIBBUFFER11_CONFIG2" },
354 { 0x227, "GPUREG_INDEXBUFFER_CONFIG" },
355 { 0x228, "GPUREG_NUMVERTICES" },
356 { 0x229, "GPUREG_GEOSTAGE_CONFIG" },
357 { 0x22A, "GPUREG_VERTEX_OFFSET" },
358
359 { 0x22D, "GPUREG_POST_VERTEX_CACHE_NUM" },
360 { 0x22E, "GPUREG_DRAWARRAYS" },
361 { 0x22F, "GPUREG_DRAWELEMENTS" },
362
363 { 0x231, "GPUREG_VTX_FUNC" },
364 { 0x232, "GPUREG_FIXEDATTRIB_INDEX" },
365 { 0x233, "GPUREG_FIXEDATTRIB_DATA0" },
366 { 0x234, "GPUREG_FIXEDATTRIB_DATA1" },
367 { 0x235, "GPUREG_FIXEDATTRIB_DATA2" },
368
369 { 0x238, "GPUREG_CMDBUF_SIZE0" },
370 { 0x239, "GPUREG_CMDBUF_SIZE1" },
371 { 0x23A, "GPUREG_CMDBUF_ADDR0" },
372 { 0x23B, "GPUREG_CMDBUF_ADDR1" },
373 { 0x23C, "GPUREG_CMDBUF_JUMP0" },
374 { 0x23D, "GPUREG_CMDBUF_JUMP1" },
375
376 { 0x242, "GPUREG_VSH_NUM_ATTR" },
377
378 { 0x244, "GPUREG_VSH_COM_MODE" },
379 { 0x245, "GPUREG_START_DRAW_FUNC0" },
380
381 { 0x24A, "GPUREG_VSH_OUTMAP_TOTAL1" },
382
383 { 0x251, "GPUREG_VSH_OUTMAP_TOTAL2" },
384 { 0x252, "GPUREG_GSH_MISC0" },
385 { 0x253, "GPUREG_GEOSTAGE_CONFIG2" },
386 { 0x254, "GPUREG_GSH_MISC1" },
387
388 { 0x25E, "GPUREG_PRIMITIVE_CONFIG" },
389 { 0x25F, "GPUREG_RESTART_PRIMITIVE" },
390
391 { 0x280, "GPUREG_GSH_BOOLUNIFORM" },
392 { 0x281, "GPUREG_GSH_INTUNIFORM_I0" },
393 { 0x282, "GPUREG_GSH_INTUNIFORM_I1" },
394 { 0x283, "GPUREG_GSH_INTUNIFORM_I2" },
395 { 0x284, "GPUREG_GSH_INTUNIFORM_I3" },
396
397 { 0x289, "GPUREG_GSH_INPUTBUFFER_CONFIG" },
398 { 0x28A, "GPUREG_GSH_ENTRYPOINT" },
399 { 0x28B, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW" },
400 { 0x28C, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_HIGH" },
401 { 0x28D, "GPUREG_GSH_OUTMAP_MASK" },
402
403 { 0x28F, "GPUREG_GSH_CODETRANSFER_END" },
404 { 0x290, "GPUREG_GSH_FLOATUNIFORM_INDEX" },
405 { 0x291, "GPUREG_GSH_FLOATUNIFORM_DATA0" },
406 { 0x292, "GPUREG_GSH_FLOATUNIFORM_DATA1" },
407 { 0x293, "GPUREG_GSH_FLOATUNIFORM_DATA2" },
408 { 0x294, "GPUREG_GSH_FLOATUNIFORM_DATA3" },
409 { 0x295, "GPUREG_GSH_FLOATUNIFORM_DATA4" },
410 { 0x296, "GPUREG_GSH_FLOATUNIFORM_DATA5" },
411 { 0x297, "GPUREG_GSH_FLOATUNIFORM_DATA6" },
412 { 0x298, "GPUREG_GSH_FLOATUNIFORM_DATA7" },
413
414 { 0x29B, "GPUREG_GSH_CODETRANSFER_INDEX" },
415 { 0x29C, "GPUREG_GSH_CODETRANSFER_DATA0" },
416 { 0x29D, "GPUREG_GSH_CODETRANSFER_DATA1" },
417 { 0x29E, "GPUREG_GSH_CODETRANSFER_DATA2" },
418 { 0x29F, "GPUREG_GSH_CODETRANSFER_DATA3" },
419 { 0x2A0, "GPUREG_GSH_CODETRANSFER_DATA4" },
420 { 0x2A1, "GPUREG_GSH_CODETRANSFER_DATA5" },
421 { 0x2A2, "GPUREG_GSH_CODETRANSFER_DATA6" },
422 { 0x2A3, "GPUREG_GSH_CODETRANSFER_DATA7" },
423
424 { 0x2A5, "GPUREG_GSH_OPDESCS_INDEX" },
425 { 0x2A6, "GPUREG_GSH_OPDESCS_DATA0" },
426 { 0x2A7, "GPUREG_GSH_OPDESCS_DATA1" },
427 { 0x2A8, "GPUREG_GSH_OPDESCS_DATA2" },
428 { 0x2A9, "GPUREG_GSH_OPDESCS_DATA3" },
429 { 0x2AA, "GPUREG_GSH_OPDESCS_DATA4" },
430 { 0x2AB, "GPUREG_GSH_OPDESCS_DATA5" },
431 { 0x2AC, "GPUREG_GSH_OPDESCS_DATA6" },
432 { 0x2AD, "GPUREG_GSH_OPDESCS_DATA7" },
433
434 { 0x2B0, "GPUREG_VSH_BOOLUNIFORM" },
435 { 0x2B1, "GPUREG_VSH_INTUNIFORM_I0" },
436 { 0x2B2, "GPUREG_VSH_INTUNIFORM_I1" },
437 { 0x2B3, "GPUREG_VSH_INTUNIFORM_I2" },
438 { 0x2B4, "GPUREG_VSH_INTUNIFORM_I3" },
439
440 { 0x2B9, "GPUREG_VSH_INPUTBUFFER_CONFIG" },
441 { 0x2BA, "GPUREG_VSH_ENTRYPOINT" },
442 { 0x2BB, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW" },
443 { 0x2BC, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH" },
444 { 0x2BD, "GPUREG_VSH_OUTMAP_MASK" },
445
446 { 0x2BF, "GPUREG_VSH_CODETRANSFER_END" },
447 { 0x2C0, "GPUREG_VSH_FLOATUNIFORM_INDEX" },
448 { 0x2C1, "GPUREG_VSH_FLOATUNIFORM_DATA0" },
449 { 0x2C2, "GPUREG_VSH_FLOATUNIFORM_DATA1" },
450 { 0x2C3, "GPUREG_VSH_FLOATUNIFORM_DATA2" },
451 { 0x2C4, "GPUREG_VSH_FLOATUNIFORM_DATA3" },
452 { 0x2C5, "GPUREG_VSH_FLOATUNIFORM_DATA4" },
453 { 0x2C6, "GPUREG_VSH_FLOATUNIFORM_DATA5" },
454 { 0x2C7, "GPUREG_VSH_FLOATUNIFORM_DATA6" },
455 { 0x2C8, "GPUREG_VSH_FLOATUNIFORM_DATA7" },
456
457 { 0x2CB, "GPUREG_VSH_CODETRANSFER_INDEX" },
458 { 0x2CC, "GPUREG_VSH_CODETRANSFER_DATA0" },
459 { 0x2CD, "GPUREG_VSH_CODETRANSFER_DATA1" },
460 { 0x2CE, "GPUREG_VSH_CODETRANSFER_DATA2" },
461 { 0x2CF, "GPUREG_VSH_CODETRANSFER_DATA3" },
462 { 0x2D0, "GPUREG_VSH_CODETRANSFER_DATA4" },
463 { 0x2D1, "GPUREG_VSH_CODETRANSFER_DATA5" },
464 { 0x2D2, "GPUREG_VSH_CODETRANSFER_DATA6" },
465 { 0x2D3, "GPUREG_VSH_CODETRANSFER_DATA7" },
466
467 { 0x2D5, "GPUREG_VSH_OPDESCS_INDEX" },
468 { 0x2D6, "GPUREG_VSH_OPDESCS_DATA0" },
469 { 0x2D7, "GPUREG_VSH_OPDESCS_DATA1" },
470 { 0x2D8, "GPUREG_VSH_OPDESCS_DATA2" },
471 { 0x2D9, "GPUREG_VSH_OPDESCS_DATA3" },
472 { 0x2DA, "GPUREG_VSH_OPDESCS_DATA4" },
473 { 0x2DB, "GPUREG_VSH_OPDESCS_DATA5" },
474 { 0x2DC, "GPUREG_VSH_OPDESCS_DATA6" },
475 { 0x2DD, "GPUREG_VSH_OPDESCS_DATA7" },
476};
477
15std::string Regs::GetCommandName(int index) { 478std::string Regs::GetCommandName(int index) {
16 static std::unordered_map<u32, std::string> map; 479 static std::unordered_map<u32, const char*> map;
17 480
18 if (map.empty()) { 481 if (map.empty()) {
19 #define ADD_FIELD(name) \ 482 map.insert(begin(register_names), end(register_names));
20 map.insert({static_cast<u32>(PICA_REG_INDEX(name)), #name}); \
21 /* TODO: change to Regs::name when VS2015 and other compilers support it */ \
22 for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \
23 map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \
24
25 ADD_FIELD(trigger_irq);
26 ADD_FIELD(cull_mode);
27 ADD_FIELD(viewport_size_x);
28 ADD_FIELD(viewport_size_y);
29 ADD_FIELD(viewport_depth_range);
30 ADD_FIELD(viewport_depth_far_plane);
31 ADD_FIELD(viewport_corner);
32 ADD_FIELD(texture0_enable);
33 ADD_FIELD(texture0);
34 ADD_FIELD(texture0_format);
35 ADD_FIELD(texture1);
36 ADD_FIELD(texture1_format);
37 ADD_FIELD(texture2);
38 ADD_FIELD(texture2_format);
39 ADD_FIELD(tev_stage0);
40 ADD_FIELD(tev_stage1);
41 ADD_FIELD(tev_stage2);
42 ADD_FIELD(tev_stage3);
43 ADD_FIELD(tev_combiner_buffer_input);
44 ADD_FIELD(tev_stage4);
45 ADD_FIELD(tev_stage5);
46 ADD_FIELD(tev_combiner_buffer_color);
47 ADD_FIELD(output_merger);
48 ADD_FIELD(framebuffer);
49 ADD_FIELD(vertex_attributes);
50 ADD_FIELD(index_array);
51 ADD_FIELD(num_vertices);
52 ADD_FIELD(vertex_offset);
53 ADD_FIELD(trigger_draw);
54 ADD_FIELD(trigger_draw_indexed);
55 ADD_FIELD(vs_default_attributes_setup);
56 ADD_FIELD(command_buffer);
57 ADD_FIELD(triangle_topology);
58 ADD_FIELD(restart_primitive);
59 ADD_FIELD(gs.bool_uniforms);
60 ADD_FIELD(gs.int_uniforms);
61 ADD_FIELD(gs.main_offset);
62 ADD_FIELD(gs.input_register_map);
63 ADD_FIELD(gs.uniform_setup);
64 ADD_FIELD(gs.program);
65 ADD_FIELD(gs.swizzle_patterns);
66 ADD_FIELD(vs.bool_uniforms);
67 ADD_FIELD(vs.int_uniforms);
68 ADD_FIELD(vs.main_offset);
69 ADD_FIELD(vs.input_register_map);
70 ADD_FIELD(vs.uniform_setup);
71 ADD_FIELD(vs.program);
72 ADD_FIELD(vs.swizzle_patterns);
73
74#undef ADD_FIELD
75 } 483 }
76 484
77 // Return empty string if no match is found 485 // Return empty string if no match is found
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 2f1b2dec4..9077b1725 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -16,6 +16,8 @@
16#include "common/vector_math.h" 16#include "common/vector_math.h"
17#include "common/logging/log.h" 17#include "common/logging/log.h"
18 18
19#include "pica_types.h"
20
19namespace Pica { 21namespace Pica {
20 22
21// Returns index corresponding to the Regs member labeled by field_name 23// Returns index corresponding to the Regs member labeled by field_name
@@ -239,7 +241,8 @@ struct Regs {
239 TextureConfig texture0; 241 TextureConfig texture0;
240 INSERT_PADDING_WORDS(0x8); 242 INSERT_PADDING_WORDS(0x8);
241 BitField<0, 4, TextureFormat> texture0_format; 243 BitField<0, 4, TextureFormat> texture0_format;
242 INSERT_PADDING_WORDS(0x2); 244 BitField<0, 1, u32> fragment_lighting_enable;
245 INSERT_PADDING_WORDS(0x1);
243 TextureConfig texture1; 246 TextureConfig texture1;
244 BitField<0, 4, TextureFormat> texture1_format; 247 BitField<0, 4, TextureFormat> texture1_format;
245 INSERT_PADDING_WORDS(0x2); 248 INSERT_PADDING_WORDS(0x2);
@@ -641,7 +644,268 @@ struct Regs {
641 } 644 }
642 } 645 }
643 646
644 INSERT_PADDING_WORDS(0xe0); 647 INSERT_PADDING_WORDS(0x20);
648
649 enum class LightingSampler {
650 Distribution0 = 0,
651 Distribution1 = 1,
652 Fresnel = 3,
653 ReflectBlue = 4,
654 ReflectGreen = 5,
655 ReflectRed = 6,
656 SpotlightAttenuation = 8,
657 DistanceAttenuation = 16,
658 };
659
660 /**
661 * Pica fragment lighting supports using different LUTs for each lighting component:
662 * Reflectance R, G, and B channels, distribution function for specular components 0 and 1,
663 * fresnel factor, and spotlight attenuation. Furthermore, which LUTs are used for each channel
664 * (or whether a channel is enabled at all) is specified by various pre-defined lighting
665 * configurations. With configurations that require more LUTs, more cycles are required on HW to
666 * perform lighting computations.
667 */
668 enum class LightingConfig {
669 Config0 = 0, ///< Reflect Red, Distribution 0, Spotlight
670 Config1 = 1, ///< Reflect Red, Fresnel, Spotlight
671 Config2 = 2, ///< Reflect Red, Distribution 0/1
672 Config3 = 3, ///< Distribution 0/1, Fresnel
673 Config4 = 4, ///< Reflect Red/Green/Blue, Distribution 0/1, Spotlight
674 Config5 = 5, ///< Reflect Red/Green/Blue, Distribution 0, Fresnel, Spotlight
675 Config6 = 6, ///< Reflect Red, Distribution 0/1, Fresnel, Spotlight
676 Config7 = 8, ///< Reflect Red/Green/Blue, Distribution 0/1, Fresnel, Spotlight
677 ///< NOTE: '8' is intentional, '7' does not appear to be a valid configuration
678 };
679
680 /// Selects which lighting components are affected by fresnel
681 enum class LightingFresnelSelector {
682 None = 0, ///< Fresnel is disabled
683 PrimaryAlpha = 1, ///< Primary (diffuse) lighting alpha is affected by fresnel
684 SecondaryAlpha = 2, ///< Secondary (specular) lighting alpha is affected by fresnel
685 Both = PrimaryAlpha | SecondaryAlpha, ///< Both primary and secondary lighting alphas are affected by fresnel
686 };
687
688 /// Factor used to scale the output of a lighting LUT
689 enum class LightingScale {
690 Scale1 = 0, ///< Scale is 1x
691 Scale2 = 1, ///< Scale is 2x
692 Scale4 = 2, ///< Scale is 4x
693 Scale8 = 3, ///< Scale is 8x
694 Scale1_4 = 6, ///< Scale is 0.25x
695 Scale1_2 = 7, ///< Scale is 0.5x
696 };
697
698 enum class LightingLutInput {
699 NH = 0, // Cosine of the angle between the normal and half-angle vectors
700 VH = 1, // Cosine of the angle between the view and half-angle vectors
701 NV = 2, // Cosine of the angle between the normal and the view vector
702 LN = 3, // Cosine of the angle between the light and the normal vectors
703 };
704
705 enum class LightingBumpMode : u32 {
706 None = 0,
707 NormalMap = 1,
708 TangentMap = 2,
709 };
710
711 union LightColor {
712 BitField< 0, 10, u32> b;
713 BitField<10, 10, u32> g;
714 BitField<20, 10, u32> r;
715
716 Math::Vec3f ToVec3f() const {
717 // These fields are 10 bits wide, however 255 corresponds to 1.0f for each color component
718 return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
719 }
720 };
721
722 /// Returns true if the specified lighting sampler is supported by the current Pica lighting configuration
723 static bool IsLightingSamplerSupported(LightingConfig config, LightingSampler sampler) {
724 switch (sampler) {
725 case LightingSampler::Distribution0:
726 return (config != LightingConfig::Config1);
727
728 case LightingSampler::Distribution1:
729 return (config != LightingConfig::Config0) && (config != LightingConfig::Config1) && (config != LightingConfig::Config5);
730
731 case LightingSampler::Fresnel:
732 return (config != LightingConfig::Config0) && (config != LightingConfig::Config2) && (config != LightingConfig::Config4);
733
734 case LightingSampler::ReflectRed:
735 return (config != LightingConfig::Config3);
736
737 case LightingSampler::ReflectGreen:
738 case LightingSampler::ReflectBlue:
739 return (config == LightingConfig::Config4) || (config == LightingConfig::Config5) || (config == LightingConfig::Config7);
740 }
741 return false;
742 }
743
744 struct {
745 struct LightSrc {
746 LightColor specular_0; // material.specular_0 * light.specular_0
747 LightColor specular_1; // material.specular_1 * light.specular_1
748 LightColor diffuse; // material.diffuse * light.diffuse
749 LightColor ambient; // material.ambient * light.ambient
750
751 struct {
752 // Encoded as 16-bit floating point
753 union {
754 BitField< 0, 16, u32> x;
755 BitField<16, 16, u32> y;
756 };
757 union {
758 BitField< 0, 16, u32> z;
759 };
760
761 INSERT_PADDING_WORDS(0x3);
762
763 union {
764 BitField<0, 1, u32> directional;
765 BitField<1, 1, u32> two_sided_diffuse; // When disabled, clamp dot-product to 0
766 };
767 };
768
769 BitField<0, 20, u32> dist_atten_bias;
770 BitField<0, 20, u32> dist_atten_scale;
771
772 INSERT_PADDING_WORDS(0x4);
773 };
774 static_assert(sizeof(LightSrc) == 0x10 * sizeof(u32), "LightSrc structure must be 0x10 words");
775
776 LightSrc light[8];
777 LightColor global_ambient; // Emission + (material.ambient * lighting.ambient)
778 INSERT_PADDING_WORDS(0x1);
779 BitField<0, 3, u32> num_lights; // Number of enabled lights - 1
780
781 union {
782 BitField< 2, 2, LightingFresnelSelector> fresnel_selector;
783 BitField< 4, 4, LightingConfig> config;
784 BitField<22, 2, u32> bump_selector; // 0: Texture 0, 1: Texture 1, 2: Texture 2
785 BitField<27, 1, u32> clamp_highlights;
786 BitField<28, 2, LightingBumpMode> bump_mode;
787 BitField<30, 1, u32> disable_bump_renorm;
788 };
789
790 union {
791 BitField<16, 1, u32> disable_lut_d0;
792 BitField<17, 1, u32> disable_lut_d1;
793 BitField<19, 1, u32> disable_lut_fr;
794 BitField<20, 1, u32> disable_lut_rr;
795 BitField<21, 1, u32> disable_lut_rg;
796 BitField<22, 1, u32> disable_lut_rb;
797
798 // Each bit specifies whether distance attenuation should be applied for the
799 // corresponding light
800
801 BitField<24, 1, u32> disable_dist_atten_light_0;
802 BitField<25, 1, u32> disable_dist_atten_light_1;
803 BitField<26, 1, u32> disable_dist_atten_light_2;
804 BitField<27, 1, u32> disable_dist_atten_light_3;
805 BitField<28, 1, u32> disable_dist_atten_light_4;
806 BitField<29, 1, u32> disable_dist_atten_light_5;
807 BitField<30, 1, u32> disable_dist_atten_light_6;
808 BitField<31, 1, u32> disable_dist_atten_light_7;
809 };
810
811 bool IsDistAttenDisabled(unsigned index) const {
812 const unsigned disable[] = { disable_dist_atten_light_0, disable_dist_atten_light_1,
813 disable_dist_atten_light_2, disable_dist_atten_light_3,
814 disable_dist_atten_light_4, disable_dist_atten_light_5,
815 disable_dist_atten_light_6, disable_dist_atten_light_7 };
816 return disable[index] != 0;
817 }
818
819 union {
820 BitField<0, 8, u32> index; ///< Index at which to set data in the LUT
821 BitField<8, 5, u32> type; ///< Type of LUT for which to set data
822 } lut_config;
823
824 BitField<0, 1, u32> disable;
825 INSERT_PADDING_WORDS(0x1);
826
827 // When data is written to any of these registers, it gets written to the lookup table of
828 // the selected type at the selected index, specified above in the `lut_config` register.
829 // With each write, `lut_config.index` is incremented. It does not matter which of these
830 // registers is written to, the behavior will be the same.
831 u32 lut_data[8];
832
833 // These are used to specify if absolute (abs) value should be used for each LUT index. When
834 // abs mode is disabled, LUT indexes are in the range of (-1.0, 1.0). Otherwise, they are in
835 // the range of (0.0, 1.0).
836 union {
837 BitField< 1, 1, u32> disable_d0;
838 BitField< 5, 1, u32> disable_d1;
839 BitField< 9, 1, u32> disable_sp;
840 BitField<13, 1, u32> disable_fr;
841 BitField<17, 1, u32> disable_rb;
842 BitField<21, 1, u32> disable_rg;
843 BitField<25, 1, u32> disable_rr;
844 } abs_lut_input;
845
846 union {
847 BitField< 0, 3, LightingLutInput> d0;
848 BitField< 4, 3, LightingLutInput> d1;
849 BitField< 8, 3, LightingLutInput> sp;
850 BitField<12, 3, LightingLutInput> fr;
851 BitField<16, 3, LightingLutInput> rb;
852 BitField<20, 3, LightingLutInput> rg;
853 BitField<24, 3, LightingLutInput> rr;
854 } lut_input;
855
856 union {
857 BitField< 0, 3, LightingScale> d0;
858 BitField< 4, 3, LightingScale> d1;
859 BitField< 8, 3, LightingScale> sp;
860 BitField<12, 3, LightingScale> fr;
861 BitField<16, 3, LightingScale> rb;
862 BitField<20, 3, LightingScale> rg;
863 BitField<24, 3, LightingScale> rr;
864
865 static float GetScale(LightingScale scale) {
866 switch (scale) {
867 case LightingScale::Scale1:
868 return 1.0f;
869 case LightingScale::Scale2:
870 return 2.0f;
871 case LightingScale::Scale4:
872 return 4.0f;
873 case LightingScale::Scale8:
874 return 8.0f;
875 case LightingScale::Scale1_4:
876 return 0.25f;
877 case LightingScale::Scale1_2:
878 return 0.5f;
879 }
880 return 0.0f;
881 }
882 } lut_scale;
883
884 INSERT_PADDING_WORDS(0x6);
885
886 union {
887 // There are 8 light enable "slots", corresponding to the total number of lights
888 // supported by Pica. For N enabled lights (specified by register 0x1c2, or 'src_num'
889 // above), the first N slots below will be set to integers within the range of 0-7,
890 // corresponding to the actual light that is enabled for each slot.
891
892 BitField< 0, 3, u32> slot_0;
893 BitField< 4, 3, u32> slot_1;
894 BitField< 8, 3, u32> slot_2;
895 BitField<12, 3, u32> slot_3;
896 BitField<16, 3, u32> slot_4;
897 BitField<20, 3, u32> slot_5;
898 BitField<24, 3, u32> slot_6;
899 BitField<28, 3, u32> slot_7;
900
901 unsigned GetNum(unsigned index) const {
902 const unsigned enable_slots[] = { slot_0, slot_1, slot_2, slot_3, slot_4, slot_5, slot_6, slot_7 };
903 return enable_slots[index];
904 }
905 } light_enable;
906 } lighting;
907
908 INSERT_PADDING_WORDS(0x26);
645 909
646 enum class VertexAttributeFormat : u64 { 910 enum class VertexAttributeFormat : u64 {
647 BYTE = 0, 911 BYTE = 0,
@@ -990,6 +1254,7 @@ ASSERT_REG_POSITION(viewport_corner, 0x68);
990ASSERT_REG_POSITION(texture0_enable, 0x80); 1254ASSERT_REG_POSITION(texture0_enable, 0x80);
991ASSERT_REG_POSITION(texture0, 0x81); 1255ASSERT_REG_POSITION(texture0, 0x81);
992ASSERT_REG_POSITION(texture0_format, 0x8e); 1256ASSERT_REG_POSITION(texture0_format, 0x8e);
1257ASSERT_REG_POSITION(fragment_lighting_enable, 0x8f);
993ASSERT_REG_POSITION(texture1, 0x91); 1258ASSERT_REG_POSITION(texture1, 0x91);
994ASSERT_REG_POSITION(texture1_format, 0x96); 1259ASSERT_REG_POSITION(texture1_format, 0x96);
995ASSERT_REG_POSITION(texture2, 0x99); 1260ASSERT_REG_POSITION(texture2, 0x99);
@@ -1004,6 +1269,7 @@ ASSERT_REG_POSITION(tev_stage5, 0xf8);
1004ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd); 1269ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd);
1005ASSERT_REG_POSITION(output_merger, 0x100); 1270ASSERT_REG_POSITION(output_merger, 0x100);
1006ASSERT_REG_POSITION(framebuffer, 0x110); 1271ASSERT_REG_POSITION(framebuffer, 0x110);
1272ASSERT_REG_POSITION(lighting, 0x140);
1007ASSERT_REG_POSITION(vertex_attributes, 0x200); 1273ASSERT_REG_POSITION(vertex_attributes, 0x200);
1008ASSERT_REG_POSITION(index_array, 0x227); 1274ASSERT_REG_POSITION(index_array, 0x227);
1009ASSERT_REG_POSITION(num_vertices, 0x228); 1275ASSERT_REG_POSITION(num_vertices, 0x228);
@@ -1026,118 +1292,6 @@ static_assert(sizeof(Regs::ShaderConfig) == 0x30 * sizeof(u32), "ShaderConfig st
1026static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be"); 1292static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be");
1027static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be"); 1293static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be");
1028 1294
1029struct float24 {
1030 static float24 FromFloat32(float val) {
1031 float24 ret;
1032 ret.value = val;
1033 return ret;
1034 }
1035
1036 // 16 bit mantissa, 7 bit exponent, 1 bit sign
1037 // TODO: No idea if this works as intended
1038 static float24 FromRawFloat24(u32 hex) {
1039 float24 ret;
1040 if ((hex & 0xFFFFFF) == 0) {
1041 ret.value = 0;
1042 } else {
1043 u32 mantissa = hex & 0xFFFF;
1044 u32 exponent = (hex >> 16) & 0x7F;
1045 u32 sign = hex >> 23;
1046 ret.value = std::pow(2.0f, (float)exponent-63.0f) * (1.0f + mantissa * std::pow(2.0f, -16.f));
1047 if (sign)
1048 ret.value = -ret.value;
1049 }
1050 return ret;
1051 }
1052
1053 static float24 Zero() {
1054 return FromFloat32(0.f);
1055 }
1056
1057 // Not recommended for anything but logging
1058 float ToFloat32() const {
1059 return value;
1060 }
1061
1062 float24 operator * (const float24& flt) const {
1063 if ((this->value == 0.f && !std::isnan(flt.value)) ||
1064 (flt.value == 0.f && !std::isnan(this->value)))
1065 // PICA gives 0 instead of NaN when multiplying by inf
1066 return Zero();
1067 return float24::FromFloat32(ToFloat32() * flt.ToFloat32());
1068 }
1069
1070 float24 operator / (const float24& flt) const {
1071 return float24::FromFloat32(ToFloat32() / flt.ToFloat32());
1072 }
1073
1074 float24 operator + (const float24& flt) const {
1075 return float24::FromFloat32(ToFloat32() + flt.ToFloat32());
1076 }
1077
1078 float24 operator - (const float24& flt) const {
1079 return float24::FromFloat32(ToFloat32() - flt.ToFloat32());
1080 }
1081
1082 float24& operator *= (const float24& flt) {
1083 if ((this->value == 0.f && !std::isnan(flt.value)) ||
1084 (flt.value == 0.f && !std::isnan(this->value)))
1085 // PICA gives 0 instead of NaN when multiplying by inf
1086 *this = Zero();
1087 else value *= flt.ToFloat32();
1088 return *this;
1089 }
1090
1091 float24& operator /= (const float24& flt) {
1092 value /= flt.ToFloat32();
1093 return *this;
1094 }
1095
1096 float24& operator += (const float24& flt) {
1097 value += flt.ToFloat32();
1098 return *this;
1099 }
1100
1101 float24& operator -= (const float24& flt) {
1102 value -= flt.ToFloat32();
1103 return *this;
1104 }
1105
1106 float24 operator - () const {
1107 return float24::FromFloat32(-ToFloat32());
1108 }
1109
1110 bool operator < (const float24& flt) const {
1111 return ToFloat32() < flt.ToFloat32();
1112 }
1113
1114 bool operator > (const float24& flt) const {
1115 return ToFloat32() > flt.ToFloat32();
1116 }
1117
1118 bool operator >= (const float24& flt) const {
1119 return ToFloat32() >= flt.ToFloat32();
1120 }
1121
1122 bool operator <= (const float24& flt) const {
1123 return ToFloat32() <= flt.ToFloat32();
1124 }
1125
1126 bool operator == (const float24& flt) const {
1127 return ToFloat32() == flt.ToFloat32();
1128 }
1129
1130 bool operator != (const float24& flt) const {
1131 return ToFloat32() != flt.ToFloat32();
1132 }
1133
1134private:
1135 // Stored as a regular float, merely for convenience
1136 // TODO: Perform proper arithmetic on this!
1137 float value;
1138};
1139static_assert(sizeof(float24) == sizeof(float), "Shader JIT assumes float24 is implemented as a 32-bit float");
1140
1141/// Struct used to describe current Pica state 1295/// Struct used to describe current Pica state
1142struct State { 1296struct State {
1143 /// Pica registers 1297 /// Pica registers
@@ -1163,6 +1317,25 @@ struct State {
1163 ShaderSetup vs; 1317 ShaderSetup vs;
1164 ShaderSetup gs; 1318 ShaderSetup gs;
1165 1319
1320 struct {
1321 union LutEntry {
1322 // Used for raw access
1323 u32 raw;
1324
1325 // LUT value, encoded as 12-bit fixed point, with 12 fraction bits
1326 BitField< 0, 12, u32> value;
1327
1328 // Used by HW for efficient interpolation, Citra does not use these
1329 BitField<12, 12, u32> difference;
1330
1331 float ToFloat() {
1332 return static_cast<float>(value) / 4095.f;
1333 }
1334 };
1335
1336 std::array<std::array<LutEntry, 256>, 24> luts;
1337 } lighting;
1338
1166 /// Current Pica command list 1339 /// Current Pica command list
1167 struct { 1340 struct {
1168 const u32* head_ptr; 1341 const u32* head_ptr;
diff --git a/src/video_core/pica_types.h b/src/video_core/pica_types.h
new file mode 100644
index 000000000..ecf45654b
--- /dev/null
+++ b/src/video_core/pica_types.h
@@ -0,0 +1,146 @@
1// Copyright 2015 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 <cstring>
8
9#include "common/common_types.h"
10
11namespace Pica {
12
13/**
14 * Template class for converting arbitrary Pica float types to IEEE 754 32-bit single-precision
15 * floating point.
16 *
17 * When decoding, format is as follows:
18 * - The first `M` bits are the mantissa
19 * - The next `E` bits are the exponent
20 * - The last bit is the sign bit
21 *
22 * @todo Verify on HW if this conversion is sufficiently accurate.
23 */
24template<unsigned M, unsigned E>
25struct Float {
26public:
27 static Float<M, E> FromFloat32(float val) {
28 Float<M, E> ret;
29 ret.value = val;
30 return ret;
31 }
32
33 static Float<M, E> FromRaw(u32 hex) {
34 Float<M, E> res;
35
36 const int width = M + E + 1;
37 const int bias = 128 - (1 << (E - 1));
38 const int exponent = (hex >> M) & ((1 << E) - 1);
39 const unsigned mantissa = hex & ((1 << M) - 1);
40
41 if (hex & ((1 << (width - 1)) - 1))
42 hex = ((hex >> (E + M)) << 31) | (mantissa << (23 - M)) | ((exponent + bias) << 23);
43 else
44 hex = ((hex >> (E + M)) << 31);
45
46 std::memcpy(&res.value, &hex, sizeof(float));
47
48 return res;
49 }
50
51 static Float<M, E> Zero() {
52 return FromFloat32(0.f);
53 }
54
55 // Not recommended for anything but logging
56 float ToFloat32() const {
57 return value;
58 }
59
60 Float<M, E> operator * (const Float<M, E>& flt) const {
61 if ((this->value == 0.f && !std::isnan(flt.value)) ||
62 (flt.value == 0.f && !std::isnan(this->value)))
63 // PICA gives 0 instead of NaN when multiplying by inf
64 return Zero();
65 return Float<M, E>::FromFloat32(ToFloat32() * flt.ToFloat32());
66 }
67
68 Float<M, E> operator / (const Float<M, E>& flt) const {
69 return Float<M, E>::FromFloat32(ToFloat32() / flt.ToFloat32());
70 }
71
72 Float<M, E> operator + (const Float<M, E>& flt) const {
73 return Float<M, E>::FromFloat32(ToFloat32() + flt.ToFloat32());
74 }
75
76 Float<M, E> operator - (const Float<M, E>& flt) const {
77 return Float<M, E>::FromFloat32(ToFloat32() - flt.ToFloat32());
78 }
79
80 Float<M, E>& operator *= (const Float<M, E>& flt) {
81 if ((this->value == 0.f && !std::isnan(flt.value)) ||
82 (flt.value == 0.f && !std::isnan(this->value)))
83 // PICA gives 0 instead of NaN when multiplying by inf
84 *this = Zero();
85 else value *= flt.ToFloat32();
86 return *this;
87 }
88
89 Float<M, E>& operator /= (const Float<M, E>& flt) {
90 value /= flt.ToFloat32();
91 return *this;
92 }
93
94 Float<M, E>& operator += (const Float<M, E>& flt) {
95 value += flt.ToFloat32();
96 return *this;
97 }
98
99 Float<M, E>& operator -= (const Float<M, E>& flt) {
100 value -= flt.ToFloat32();
101 return *this;
102 }
103
104 Float<M, E> operator - () const {
105 return Float<M, E>::FromFloat32(-ToFloat32());
106 }
107
108 bool operator < (const Float<M, E>& flt) const {
109 return ToFloat32() < flt.ToFloat32();
110 }
111
112 bool operator > (const Float<M, E>& flt) const {
113 return ToFloat32() > flt.ToFloat32();
114 }
115
116 bool operator >= (const Float<M, E>& flt) const {
117 return ToFloat32() >= flt.ToFloat32();
118 }
119
120 bool operator <= (const Float<M, E>& flt) const {
121 return ToFloat32() <= flt.ToFloat32();
122 }
123
124 bool operator == (const Float<M, E>& flt) const {
125 return ToFloat32() == flt.ToFloat32();
126 }
127
128 bool operator != (const Float<M, E>& flt) const {
129 return ToFloat32() != flt.ToFloat32();
130 }
131
132private:
133 static const unsigned MASK = (1 << (M + E + 1)) - 1;
134 static const unsigned MANTISSA_MASK = (1 << M) - 1;
135 static const unsigned EXPONENT_MASK = (1 << E) - 1;
136
137 // Stored as a regular float, merely for convenience
138 // TODO: Perform proper arithmetic on this!
139 float value;
140};
141
142using float24 = Float<16, 7>;
143using float20 = Float<12, 7>;
144using float16 = Float<10, 5>;
145
146} // namespace Pica
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 092351dce..b7d19bf94 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -36,7 +36,7 @@ static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
36 stage.GetAlphaMultiplier() == 1); 36 stage.GetAlphaMultiplier() == 1);
37} 37}
38 38
39RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr(0) { } 39RasterizerOpenGL::RasterizerOpenGL() : cached_fb_color_addr(0), cached_fb_depth_addr(0) { }
40RasterizerOpenGL::~RasterizerOpenGL() { } 40RasterizerOpenGL::~RasterizerOpenGL() { }
41 41
42void RasterizerOpenGL::InitObjects() { 42void RasterizerOpenGL::InitObjects() {
@@ -75,6 +75,12 @@ void RasterizerOpenGL::InitObjects() {
75 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1); 75 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1);
76 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2); 76 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2);
77 77
78 glVertexAttribPointer(GLShader::ATTRIBUTE_NORMQUAT, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, normquat));
79 glEnableVertexAttribArray(GLShader::ATTRIBUTE_NORMQUAT);
80
81 glVertexAttribPointer(GLShader::ATTRIBUTE_VIEW, 3, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, view));
82 glEnableVertexAttribArray(GLShader::ATTRIBUTE_VIEW);
83
78 SetShader(); 84 SetShader();
79 85
80 // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation 86 // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation
@@ -120,12 +126,26 @@ void RasterizerOpenGL::InitObjects() {
120 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_color_texture.texture.handle, 0); 126 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_color_texture.texture.handle, 0);
121 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.handle, 0); 127 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.handle, 0);
122 128
129 for (size_t i = 0; i < lighting_lut.size(); ++i) {
130 lighting_lut[i].Create();
131 state.lighting_lut[i].texture_1d = lighting_lut[i].handle;
132
133 glActiveTexture(GL_TEXTURE3 + i);
134 glBindTexture(GL_TEXTURE_1D, state.lighting_lut[i].texture_1d);
135
136 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 256, 0, GL_RGBA, GL_FLOAT, nullptr);
137 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
138 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
139 }
140 state.Apply();
141
123 ASSERT_MSG(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, 142 ASSERT_MSG(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
124 "OpenGL rasterizer framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER)); 143 "OpenGL rasterizer framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER));
125} 144}
126 145
127void RasterizerOpenGL::Reset() { 146void RasterizerOpenGL::Reset() {
128 SyncCullMode(); 147 SyncCullMode();
148 SyncDepthModifiers();
129 SyncBlendEnabled(); 149 SyncBlendEnabled();
130 SyncBlendFuncs(); 150 SyncBlendFuncs();
131 SyncBlendColor(); 151 SyncBlendColor();
@@ -138,12 +158,34 @@ void RasterizerOpenGL::Reset() {
138 res_cache.InvalidateAll(); 158 res_cache.InvalidateAll();
139} 159}
140 160
161/**
162 * This is a helper function to resolve an issue with opposite quaternions being interpolated by
163 * OpenGL. See below for a detailed description of this issue (yuriks):
164 *
165 * For any rotation, there are two quaternions Q, and -Q, that represent the same rotation. If you
166 * interpolate two quaternions that are opposite, instead of going from one rotation to another
167 * using the shortest path, you'll go around the longest path. You can test if two quaternions are
168 * opposite by checking if Dot(Q1, W2) < 0. In that case, you can flip either of them, therefore
169 * making Dot(-Q1, W2) positive.
170 *
171 * NOTE: This solution corrects this issue per-vertex before passing the quaternions to OpenGL. This
172 * should be correct for nearly all cases, however a more correct implementation (but less trivial
173 * and perhaps unnecessary) would be to handle this per-fragment, by interpolating the quaternions
174 * manually using two Lerps, and doing this correction before each Lerp.
175 */
176static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) {
177 Math::Vec4f a{ qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32() };
178 Math::Vec4f b{ qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32() };
179
180 return (Math::Dot(a, b) < 0.f);
181}
182
141void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0, 183void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0,
142 const Pica::Shader::OutputVertex& v1, 184 const Pica::Shader::OutputVertex& v1,
143 const Pica::Shader::OutputVertex& v2) { 185 const Pica::Shader::OutputVertex& v2) {
144 vertex_batch.emplace_back(v0); 186 vertex_batch.emplace_back(v0, false);
145 vertex_batch.emplace_back(v1); 187 vertex_batch.emplace_back(v1, AreQuaternionsOpposite(v0.quat, v1.quat));
146 vertex_batch.emplace_back(v2); 188 vertex_batch.emplace_back(v2, AreQuaternionsOpposite(v0.quat, v2.quat));
147} 189}
148 190
149void RasterizerOpenGL::DrawTriangles() { 191void RasterizerOpenGL::DrawTriangles() {
@@ -155,6 +197,13 @@ void RasterizerOpenGL::DrawTriangles() {
155 state.draw.shader_dirty = false; 197 state.draw.shader_dirty = false;
156 } 198 }
157 199
200 for (unsigned index = 0; index < lighting_lut.size(); index++) {
201 if (uniform_block_data.lut_dirty[index]) {
202 SyncLightingLUT(index);
203 uniform_block_data.lut_dirty[index] = false;
204 }
205 }
206
158 if (uniform_block_data.dirty) { 207 if (uniform_block_data.dirty) {
159 glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW); 208 glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW);
160 uniform_block_data.dirty = false; 209 uniform_block_data.dirty = false;
@@ -168,16 +217,14 @@ void RasterizerOpenGL::DrawTriangles() {
168 // Flush the resource cache at the current depth and color framebuffer addresses for render-to-texture 217 // Flush the resource cache at the current depth and color framebuffer addresses for render-to-texture
169 const auto& regs = Pica::g_state.regs; 218 const auto& regs = Pica::g_state.regs;
170 219
171 PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); 220 u32 cached_fb_color_size = Pica::Regs::BytesPerColorPixel(fb_color_texture.format)
172 u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) 221 * fb_color_texture.width * fb_color_texture.height;
173 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
174 222
175 PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress(); 223 u32 cached_fb_depth_size = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format)
176 u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format) 224 * fb_depth_texture.width * fb_depth_texture.height;
177 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
178 225
179 res_cache.InvalidateInRange(cur_fb_color_addr, cur_fb_color_size, true); 226 res_cache.InvalidateInRange(cached_fb_color_addr, cached_fb_color_size, true);
180 res_cache.InvalidateInRange(cur_fb_depth_addr, cur_fb_depth_size, true); 227 res_cache.InvalidateInRange(cached_fb_depth_addr, cached_fb_depth_size, true);
181} 228}
182 229
183void RasterizerOpenGL::FlushFramebuffer() { 230void RasterizerOpenGL::FlushFramebuffer() {
@@ -194,6 +241,12 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
194 SyncCullMode(); 241 SyncCullMode();
195 break; 242 break;
196 243
244 // Depth modifiers
245 case PICA_REG_INDEX(viewport_depth_range):
246 case PICA_REG_INDEX(viewport_depth_far_plane):
247 SyncDepthModifiers();
248 break;
249
197 // Blending 250 // Blending
198 case PICA_REG_INDEX(output_merger.alphablend_enable): 251 case PICA_REG_INDEX(output_merger.alphablend_enable):
199 SyncBlendEnabled(); 252 SyncBlendEnabled();
@@ -278,44 +331,199 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
278 case PICA_REG_INDEX(tev_combiner_buffer_color): 331 case PICA_REG_INDEX(tev_combiner_buffer_color):
279 SyncCombinerColor(); 332 SyncCombinerColor();
280 break; 333 break;
334
335 // Fragment lighting specular 0 color
336 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].specular_0, 0x140 + 0 * 0x10):
337 SyncLightSpecular0(0);
338 break;
339 case PICA_REG_INDEX_WORKAROUND(lighting.light[1].specular_0, 0x140 + 1 * 0x10):
340 SyncLightSpecular0(1);
341 break;
342 case PICA_REG_INDEX_WORKAROUND(lighting.light[2].specular_0, 0x140 + 2 * 0x10):
343 SyncLightSpecular0(2);
344 break;
345 case PICA_REG_INDEX_WORKAROUND(lighting.light[3].specular_0, 0x140 + 3 * 0x10):
346 SyncLightSpecular0(3);
347 break;
348 case PICA_REG_INDEX_WORKAROUND(lighting.light[4].specular_0, 0x140 + 4 * 0x10):
349 SyncLightSpecular0(4);
350 break;
351 case PICA_REG_INDEX_WORKAROUND(lighting.light[5].specular_0, 0x140 + 5 * 0x10):
352 SyncLightSpecular0(5);
353 break;
354 case PICA_REG_INDEX_WORKAROUND(lighting.light[6].specular_0, 0x140 + 6 * 0x10):
355 SyncLightSpecular0(6);
356 break;
357 case PICA_REG_INDEX_WORKAROUND(lighting.light[7].specular_0, 0x140 + 7 * 0x10):
358 SyncLightSpecular0(7);
359 break;
360
361 // Fragment lighting specular 1 color
362 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].specular_1, 0x141 + 0 * 0x10):
363 SyncLightSpecular1(0);
364 break;
365 case PICA_REG_INDEX_WORKAROUND(lighting.light[1].specular_1, 0x141 + 1 * 0x10):
366 SyncLightSpecular1(1);
367 break;
368 case PICA_REG_INDEX_WORKAROUND(lighting.light[2].specular_1, 0x141 + 2 * 0x10):
369 SyncLightSpecular1(2);
370 break;
371 case PICA_REG_INDEX_WORKAROUND(lighting.light[3].specular_1, 0x141 + 3 * 0x10):
372 SyncLightSpecular1(3);
373 break;
374 case PICA_REG_INDEX_WORKAROUND(lighting.light[4].specular_1, 0x141 + 4 * 0x10):
375 SyncLightSpecular1(4);
376 break;
377 case PICA_REG_INDEX_WORKAROUND(lighting.light[5].specular_1, 0x141 + 5 * 0x10):
378 SyncLightSpecular1(5);
379 break;
380 case PICA_REG_INDEX_WORKAROUND(lighting.light[6].specular_1, 0x141 + 6 * 0x10):
381 SyncLightSpecular1(6);
382 break;
383 case PICA_REG_INDEX_WORKAROUND(lighting.light[7].specular_1, 0x141 + 7 * 0x10):
384 SyncLightSpecular1(7);
385 break;
386
387 // Fragment lighting diffuse color
388 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].diffuse, 0x142 + 0 * 0x10):
389 SyncLightDiffuse(0);
390 break;
391 case PICA_REG_INDEX_WORKAROUND(lighting.light[1].diffuse, 0x142 + 1 * 0x10):
392 SyncLightDiffuse(1);
393 break;
394 case PICA_REG_INDEX_WORKAROUND(lighting.light[2].diffuse, 0x142 + 2 * 0x10):
395 SyncLightDiffuse(2);
396 break;
397 case PICA_REG_INDEX_WORKAROUND(lighting.light[3].diffuse, 0x142 + 3 * 0x10):
398 SyncLightDiffuse(3);
399 break;
400 case PICA_REG_INDEX_WORKAROUND(lighting.light[4].diffuse, 0x142 + 4 * 0x10):
401 SyncLightDiffuse(4);
402 break;
403 case PICA_REG_INDEX_WORKAROUND(lighting.light[5].diffuse, 0x142 + 5 * 0x10):
404 SyncLightDiffuse(5);
405 break;
406 case PICA_REG_INDEX_WORKAROUND(lighting.light[6].diffuse, 0x142 + 6 * 0x10):
407 SyncLightDiffuse(6);
408 break;
409 case PICA_REG_INDEX_WORKAROUND(lighting.light[7].diffuse, 0x142 + 7 * 0x10):
410 SyncLightDiffuse(7);
411 break;
412
413 // Fragment lighting ambient color
414 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].ambient, 0x143 + 0 * 0x10):
415 SyncLightAmbient(0);
416 break;
417 case PICA_REG_INDEX_WORKAROUND(lighting.light[1].ambient, 0x143 + 1 * 0x10):
418 SyncLightAmbient(1);
419 break;
420 case PICA_REG_INDEX_WORKAROUND(lighting.light[2].ambient, 0x143 + 2 * 0x10):
421 SyncLightAmbient(2);
422 break;
423 case PICA_REG_INDEX_WORKAROUND(lighting.light[3].ambient, 0x143 + 3 * 0x10):
424 SyncLightAmbient(3);
425 break;
426 case PICA_REG_INDEX_WORKAROUND(lighting.light[4].ambient, 0x143 + 4 * 0x10):
427 SyncLightAmbient(4);
428 break;
429 case PICA_REG_INDEX_WORKAROUND(lighting.light[5].ambient, 0x143 + 5 * 0x10):
430 SyncLightAmbient(5);
431 break;
432 case PICA_REG_INDEX_WORKAROUND(lighting.light[6].ambient, 0x143 + 6 * 0x10):
433 SyncLightAmbient(6);
434 break;
435 case PICA_REG_INDEX_WORKAROUND(lighting.light[7].ambient, 0x143 + 7 * 0x10):
436 SyncLightAmbient(7);
437 break;
438
439 // Fragment lighting position
440 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].x, 0x144 + 0 * 0x10):
441 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].z, 0x145 + 0 * 0x10):
442 SyncLightPosition(0);
443 break;
444 case PICA_REG_INDEX_WORKAROUND(lighting.light[1].x, 0x144 + 1 * 0x10):
445 case PICA_REG_INDEX_WORKAROUND(lighting.light[1].z, 0x145 + 1 * 0x10):
446 SyncLightPosition(1);
447 break;
448 case PICA_REG_INDEX_WORKAROUND(lighting.light[2].x, 0x144 + 2 * 0x10):
449 case PICA_REG_INDEX_WORKAROUND(lighting.light[2].z, 0x145 + 2 * 0x10):
450 SyncLightPosition(2);
451 break;
452 case PICA_REG_INDEX_WORKAROUND(lighting.light[3].x, 0x144 + 3 * 0x10):
453 case PICA_REG_INDEX_WORKAROUND(lighting.light[3].z, 0x145 + 3 * 0x10):
454 SyncLightPosition(3);
455 break;
456 case PICA_REG_INDEX_WORKAROUND(lighting.light[4].x, 0x144 + 4 * 0x10):
457 case PICA_REG_INDEX_WORKAROUND(lighting.light[4].z, 0x145 + 4 * 0x10):
458 SyncLightPosition(4);
459 break;
460 case PICA_REG_INDEX_WORKAROUND(lighting.light[5].x, 0x144 + 5 * 0x10):
461 case PICA_REG_INDEX_WORKAROUND(lighting.light[5].z, 0x145 + 5 * 0x10):
462 SyncLightPosition(5);
463 break;
464 case PICA_REG_INDEX_WORKAROUND(lighting.light[6].x, 0x144 + 6 * 0x10):
465 case PICA_REG_INDEX_WORKAROUND(lighting.light[6].z, 0x145 + 6 * 0x10):
466 SyncLightPosition(6);
467 break;
468 case PICA_REG_INDEX_WORKAROUND(lighting.light[7].x, 0x144 + 7 * 0x10):
469 case PICA_REG_INDEX_WORKAROUND(lighting.light[7].z, 0x145 + 7 * 0x10):
470 SyncLightPosition(7);
471 break;
472
473 // Fragment lighting global ambient color (emission + ambient * ambient)
474 case PICA_REG_INDEX_WORKAROUND(lighting.global_ambient, 0x1c0):
475 SyncGlobalAmbient();
476 break;
477
478 // Fragment lighting lookup tables
479 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[0], 0x1c8):
480 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[1], 0x1c9):
481 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[2], 0x1ca):
482 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[3], 0x1cb):
483 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[4], 0x1cc):
484 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[5], 0x1cd):
485 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce):
486 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf):
487 {
488 auto& lut_config = regs.lighting.lut_config;
489 uniform_block_data.lut_dirty[lut_config.type / 4] = true;
490 break;
491 }
492
281 } 493 }
282} 494}
283 495
284void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) { 496void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) {
285 const auto& regs = Pica::g_state.regs; 497 const auto& regs = Pica::g_state.regs;
286 498
287 PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); 499 u32 cached_fb_color_size = Pica::Regs::BytesPerColorPixel(fb_color_texture.format)
288 u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) 500 * fb_color_texture.width * fb_color_texture.height;
289 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
290 501
291 PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress(); 502 u32 cached_fb_depth_size = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format)
292 u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format) 503 * fb_depth_texture.width * fb_depth_texture.height;
293 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
294 504
295 // If source memory region overlaps 3DS framebuffers, commit them before the copy happens 505 // If source memory region overlaps 3DS framebuffers, commit them before the copy happens
296 if (MathUtil::IntervalsIntersect(addr, size, cur_fb_color_addr, cur_fb_color_size)) 506 if (MathUtil::IntervalsIntersect(addr, size, cached_fb_color_addr, cached_fb_color_size))
297 CommitColorBuffer(); 507 CommitColorBuffer();
298 508
299 if (MathUtil::IntervalsIntersect(addr, size, cur_fb_depth_addr, cur_fb_depth_size)) 509 if (MathUtil::IntervalsIntersect(addr, size, cached_fb_depth_addr, cached_fb_depth_size))
300 CommitDepthBuffer(); 510 CommitDepthBuffer();
301} 511}
302 512
303void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) { 513void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) {
304 const auto& regs = Pica::g_state.regs; 514 const auto& regs = Pica::g_state.regs;
305 515
306 PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); 516 u32 cached_fb_color_size = Pica::Regs::BytesPerColorPixel(fb_color_texture.format)
307 u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) 517 * fb_color_texture.width * fb_color_texture.height;
308 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
309 518
310 PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress(); 519 u32 cached_fb_depth_size = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format)
311 u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format) 520 * fb_depth_texture.width * fb_depth_texture.height;
312 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
313 521
314 // If modified memory region overlaps 3DS framebuffers, reload their contents into OpenGL 522 // If modified memory region overlaps 3DS framebuffers, reload their contents into OpenGL
315 if (MathUtil::IntervalsIntersect(addr, size, cur_fb_color_addr, cur_fb_color_size)) 523 if (MathUtil::IntervalsIntersect(addr, size, cached_fb_color_addr, cached_fb_color_size))
316 ReloadColorBuffer(); 524 ReloadColorBuffer();
317 525
318 if (MathUtil::IntervalsIntersect(addr, size, cur_fb_depth_addr, cur_fb_depth_size)) 526 if (MathUtil::IntervalsIntersect(addr, size, cached_fb_depth_addr, cached_fb_depth_size))
319 ReloadDepthBuffer(); 527 ReloadDepthBuffer();
320 528
321 // Notify cache of flush in case the region touches a cached resource 529 // Notify cache of flush in case the region touches a cached resource
@@ -490,27 +698,48 @@ void RasterizerOpenGL::SetShader() {
490 uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]"); 698 uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]");
491 if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); } 699 if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); }
492 700
701 // Set the texture samplers to correspond to different lookup table texture units
702 GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[0]");
703 if (uniform_lut != -1) { glUniform1i(uniform_lut, 3); }
704 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[1]");
705 if (uniform_lut != -1) { glUniform1i(uniform_lut, 4); }
706 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[2]");
707 if (uniform_lut != -1) { glUniform1i(uniform_lut, 5); }
708 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[3]");
709 if (uniform_lut != -1) { glUniform1i(uniform_lut, 6); }
710 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[4]");
711 if (uniform_lut != -1) { glUniform1i(uniform_lut, 7); }
712 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]");
713 if (uniform_lut != -1) { glUniform1i(uniform_lut, 8); }
714
493 current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); 715 current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
494 716
495 unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); 717 unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data");
496 glUniformBlockBinding(current_shader->shader.handle, block_index, 0); 718 glUniformBlockBinding(current_shader->shader.handle, block_index, 0);
497 }
498 719
499 // Update uniforms 720 // Update uniforms
500 SyncAlphaTest(); 721 SyncAlphaTest();
501 SyncCombinerColor(); 722 SyncCombinerColor();
502 auto& tev_stages = Pica::g_state.regs.GetTevStages(); 723 auto& tev_stages = Pica::g_state.regs.GetTevStages();
503 for (int index = 0; index < tev_stages.size(); ++index) 724 for (int index = 0; index < tev_stages.size(); ++index)
504 SyncTevConstColor(index, tev_stages[index]); 725 SyncTevConstColor(index, tev_stages[index]);
726
727 SyncGlobalAmbient();
728 for (int light_index = 0; light_index < 8; light_index++) {
729 SyncLightDiffuse(light_index);
730 SyncLightAmbient(light_index);
731 SyncLightPosition(light_index);
732 }
733 }
505} 734}
506 735
507void RasterizerOpenGL::SyncFramebuffer() { 736void RasterizerOpenGL::SyncFramebuffer() {
508 const auto& regs = Pica::g_state.regs; 737 const auto& regs = Pica::g_state.regs;
509 738
510 PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); 739 PAddr new_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
511 Pica::Regs::ColorFormat new_fb_color_format = regs.framebuffer.color_format; 740 Pica::Regs::ColorFormat new_fb_color_format = regs.framebuffer.color_format;
512 741
513 PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress(); 742 PAddr new_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress();
514 Pica::Regs::DepthFormat new_fb_depth_format = regs.framebuffer.depth_format; 743 Pica::Regs::DepthFormat new_fb_depth_format = regs.framebuffer.depth_format;
515 744
516 bool fb_size_changed = fb_color_texture.width != static_cast<GLsizei>(regs.framebuffer.GetWidth()) || 745 bool fb_size_changed = fb_color_texture.width != static_cast<GLsizei>(regs.framebuffer.GetWidth()) ||
@@ -522,10 +751,10 @@ void RasterizerOpenGL::SyncFramebuffer() {
522 bool depth_fb_prop_changed = fb_depth_texture.format != new_fb_depth_format || 751 bool depth_fb_prop_changed = fb_depth_texture.format != new_fb_depth_format ||
523 fb_size_changed; 752 fb_size_changed;
524 753
525 bool color_fb_modified = last_fb_color_addr != cur_fb_color_addr || 754 bool color_fb_modified = cached_fb_color_addr != new_fb_color_addr ||
526 color_fb_prop_changed; 755 color_fb_prop_changed;
527 756
528 bool depth_fb_modified = last_fb_depth_addr != cur_fb_depth_addr || 757 bool depth_fb_modified = cached_fb_depth_addr != new_fb_depth_addr ||
529 depth_fb_prop_changed; 758 depth_fb_prop_changed;
530 759
531 // Commit if framebuffer modified in any way 760 // Commit if framebuffer modified in any way
@@ -565,13 +794,13 @@ void RasterizerOpenGL::SyncFramebuffer() {
565 794
566 // Load buffer data again if fb modified in any way 795 // Load buffer data again if fb modified in any way
567 if (color_fb_modified) { 796 if (color_fb_modified) {
568 last_fb_color_addr = cur_fb_color_addr; 797 cached_fb_color_addr = new_fb_color_addr;
569 798
570 ReloadColorBuffer(); 799 ReloadColorBuffer();
571 } 800 }
572 801
573 if (depth_fb_modified) { 802 if (depth_fb_modified) {
574 last_fb_depth_addr = cur_fb_depth_addr; 803 cached_fb_depth_addr = new_fb_depth_addr;
575 804
576 ReloadDepthBuffer(); 805 ReloadDepthBuffer();
577 } 806 }
@@ -602,6 +831,15 @@ void RasterizerOpenGL::SyncCullMode() {
602 } 831 }
603} 832}
604 833
834void RasterizerOpenGL::SyncDepthModifiers() {
835 float depth_scale = -Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_range).ToFloat32();
836 float depth_offset = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_far_plane).ToFloat32() / 2.0f;
837
838 // TODO: Implement scale modifier
839 uniform_block_data.data.depth_offset = depth_offset;
840 uniform_block_data.dirty = true;
841}
842
605void RasterizerOpenGL::SyncBlendEnabled() { 843void RasterizerOpenGL::SyncBlendEnabled() {
606 state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1); 844 state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1);
607} 845}
@@ -673,12 +911,81 @@ void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevS
673 } 911 }
674} 912}
675 913
914void RasterizerOpenGL::SyncGlobalAmbient() {
915 auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.global_ambient);
916 if (color != uniform_block_data.data.lighting_global_ambient) {
917 uniform_block_data.data.lighting_global_ambient = color;
918 uniform_block_data.dirty = true;
919 }
920}
921
922void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) {
923 std::array<GLvec4, 256> new_data;
924
925 for (unsigned offset = 0; offset < new_data.size(); ++offset) {
926 new_data[offset][0] = Pica::g_state.lighting.luts[(lut_index * 4) + 0][offset].ToFloat();
927 new_data[offset][1] = Pica::g_state.lighting.luts[(lut_index * 4) + 1][offset].ToFloat();
928 new_data[offset][2] = Pica::g_state.lighting.luts[(lut_index * 4) + 2][offset].ToFloat();
929 new_data[offset][3] = Pica::g_state.lighting.luts[(lut_index * 4) + 3][offset].ToFloat();
930 }
931
932 if (new_data != lighting_lut_data[lut_index]) {
933 lighting_lut_data[lut_index] = new_data;
934 glActiveTexture(GL_TEXTURE3 + lut_index);
935 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, lighting_lut_data[lut_index].data());
936 }
937}
938
939void RasterizerOpenGL::SyncLightSpecular0(int light_index) {
940 auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].specular_0);
941 if (color != uniform_block_data.data.light_src[light_index].specular_0) {
942 uniform_block_data.data.light_src[light_index].specular_0 = color;
943 uniform_block_data.dirty = true;
944 }
945}
946
947void RasterizerOpenGL::SyncLightSpecular1(int light_index) {
948 auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].specular_1);
949 if (color != uniform_block_data.data.light_src[light_index].specular_1) {
950 uniform_block_data.data.light_src[light_index].specular_1 = color;
951 uniform_block_data.dirty = true;
952 }
953}
954
955void RasterizerOpenGL::SyncLightDiffuse(int light_index) {
956 auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].diffuse);
957 if (color != uniform_block_data.data.light_src[light_index].diffuse) {
958 uniform_block_data.data.light_src[light_index].diffuse = color;
959 uniform_block_data.dirty = true;
960 }
961}
962
963void RasterizerOpenGL::SyncLightAmbient(int light_index) {
964 auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].ambient);
965 if (color != uniform_block_data.data.light_src[light_index].ambient) {
966 uniform_block_data.data.light_src[light_index].ambient = color;
967 uniform_block_data.dirty = true;
968 }
969}
970
971void RasterizerOpenGL::SyncLightPosition(int light_index) {
972 GLvec3 position = {
973 Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(),
974 Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(),
975 Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32() };
976
977 if (position != uniform_block_data.data.light_src[light_index].position) {
978 uniform_block_data.data.light_src[light_index].position = position;
979 uniform_block_data.dirty = true;
980 }
981}
982
676void RasterizerOpenGL::SyncDrawState() { 983void RasterizerOpenGL::SyncDrawState() {
677 const auto& regs = Pica::g_state.regs; 984 const auto& regs = Pica::g_state.regs;
678 985
679 // Sync the viewport 986 // Sync the viewport
680 GLsizei viewport_width = (GLsizei)Pica::float24::FromRawFloat24(regs.viewport_size_x).ToFloat32() * 2; 987 GLsizei viewport_width = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_x).ToFloat32() * 2;
681 GLsizei viewport_height = (GLsizei)Pica::float24::FromRawFloat24(regs.viewport_size_y).ToFloat32() * 2; 988 GLsizei viewport_height = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_y).ToFloat32() * 2;
682 989
683 // OpenGL uses different y coordinates, so negate corner offset and flip origin 990 // OpenGL uses different y coordinates, so negate corner offset and flip origin
684 // TODO: Ensure viewport_corner.x should not be negated or origin flipped 991 // TODO: Ensure viewport_corner.x should not be negated or origin flipped
@@ -707,7 +1014,7 @@ void RasterizerOpenGL::SyncDrawState() {
707MICROPROFILE_DEFINE(OpenGL_FramebufferReload, "OpenGL", "FB Reload", MP_RGB(70, 70, 200)); 1014MICROPROFILE_DEFINE(OpenGL_FramebufferReload, "OpenGL", "FB Reload", MP_RGB(70, 70, 200));
708 1015
709void RasterizerOpenGL::ReloadColorBuffer() { 1016void RasterizerOpenGL::ReloadColorBuffer() {
710 u8* color_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetColorBufferPhysicalAddress()); 1017 u8* color_buffer = Memory::GetPhysicalPointer(cached_fb_color_addr);
711 1018
712 if (color_buffer == nullptr) 1019 if (color_buffer == nullptr)
713 return; 1020 return;
@@ -742,13 +1049,11 @@ void RasterizerOpenGL::ReloadColorBuffer() {
742} 1049}
743 1050
744void RasterizerOpenGL::ReloadDepthBuffer() { 1051void RasterizerOpenGL::ReloadDepthBuffer() {
745 PAddr depth_buffer_addr = Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress(); 1052 if (cached_fb_depth_addr == 0)
746
747 if (depth_buffer_addr == 0)
748 return; 1053 return;
749 1054
750 // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil 1055 // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil
751 u8* depth_buffer = Memory::GetPhysicalPointer(depth_buffer_addr); 1056 u8* depth_buffer = Memory::GetPhysicalPointer(cached_fb_depth_addr);
752 1057
753 if (depth_buffer == nullptr) 1058 if (depth_buffer == nullptr)
754 return; 1059 return;
@@ -811,8 +1116,8 @@ Common::Profiling::TimingCategory buffer_commit_category("Framebuffer Commit");
811MICROPROFILE_DEFINE(OpenGL_FramebufferCommit, "OpenGL", "FB Commit", MP_RGB(70, 70, 200)); 1116MICROPROFILE_DEFINE(OpenGL_FramebufferCommit, "OpenGL", "FB Commit", MP_RGB(70, 70, 200));
812 1117
813void RasterizerOpenGL::CommitColorBuffer() { 1118void RasterizerOpenGL::CommitColorBuffer() {
814 if (last_fb_color_addr != 0) { 1119 if (cached_fb_color_addr != 0) {
815 u8* color_buffer = Memory::GetPhysicalPointer(last_fb_color_addr); 1120 u8* color_buffer = Memory::GetPhysicalPointer(cached_fb_color_addr);
816 1121
817 if (color_buffer != nullptr) { 1122 if (color_buffer != nullptr) {
818 Common::Profiling::ScopeTimer timer(buffer_commit_category); 1123 Common::Profiling::ScopeTimer timer(buffer_commit_category);
@@ -847,9 +1152,9 @@ void RasterizerOpenGL::CommitColorBuffer() {
847} 1152}
848 1153
849void RasterizerOpenGL::CommitDepthBuffer() { 1154void RasterizerOpenGL::CommitDepthBuffer() {
850 if (last_fb_depth_addr != 0) { 1155 if (cached_fb_depth_addr != 0) {
851 // TODO: Output seems correct visually, but doesn't quite match sw renderer output. One of them is wrong. 1156 // TODO: Output seems correct visually, but doesn't quite match sw renderer output. One of them is wrong.
852 u8* depth_buffer = Memory::GetPhysicalPointer(last_fb_depth_addr); 1157 u8* depth_buffer = Memory::GetPhysicalPointer(cached_fb_depth_addr);
853 1158
854 if (depth_buffer != nullptr) { 1159 if (depth_buffer != nullptr) {
855 Common::Profiling::ScopeTimer timer(buffer_commit_category); 1160 Common::Profiling::ScopeTimer timer(buffer_commit_category);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 92b1f812e..fef5f5331 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -17,6 +17,7 @@
17#include "video_core/rasterizer_interface.h" 17#include "video_core/rasterizer_interface.h"
18#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 18#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
19#include "video_core/renderer_opengl/gl_state.h" 19#include "video_core/renderer_opengl/gl_state.h"
20#include "video_core/renderer_opengl/pica_to_gl.h"
20#include "video_core/shader/shader_interpreter.h" 21#include "video_core/shader/shader_interpreter.h"
21 22
22/** 23/**
@@ -71,6 +72,59 @@ struct PicaShaderConfig {
71 regs.tev_combiner_buffer_input.update_mask_rgb.Value() | 72 regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
72 regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; 73 regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
73 74
75 // Fragment lighting
76
77 res.lighting.enable = !regs.lighting.disable;
78 res.lighting.src_num = regs.lighting.num_lights + 1;
79
80 for (unsigned light_index = 0; light_index < res.lighting.src_num; ++light_index) {
81 unsigned num = regs.lighting.light_enable.GetNum(light_index);
82 const auto& light = regs.lighting.light[num];
83 res.lighting.light[light_index].num = num;
84 res.lighting.light[light_index].directional = light.directional != 0;
85 res.lighting.light[light_index].two_sided_diffuse = light.two_sided_diffuse != 0;
86 res.lighting.light[light_index].dist_atten_enable = !regs.lighting.IsDistAttenDisabled(num);
87 res.lighting.light[light_index].dist_atten_bias = Pica::float20::FromRaw(light.dist_atten_bias).ToFloat32();
88 res.lighting.light[light_index].dist_atten_scale = Pica::float20::FromRaw(light.dist_atten_scale).ToFloat32();
89 }
90
91 res.lighting.lut_d0.enable = regs.lighting.disable_lut_d0 == 0;
92 res.lighting.lut_d0.abs_input = regs.lighting.abs_lut_input.disable_d0 == 0;
93 res.lighting.lut_d0.type = regs.lighting.lut_input.d0.Value();
94 res.lighting.lut_d0.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.d0);
95
96 res.lighting.lut_d1.enable = regs.lighting.disable_lut_d1 == 0;
97 res.lighting.lut_d1.abs_input = regs.lighting.abs_lut_input.disable_d1 == 0;
98 res.lighting.lut_d1.type = regs.lighting.lut_input.d1.Value();
99 res.lighting.lut_d1.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.d1);
100
101 res.lighting.lut_fr.enable = regs.lighting.disable_lut_fr == 0;
102 res.lighting.lut_fr.abs_input = regs.lighting.abs_lut_input.disable_fr == 0;
103 res.lighting.lut_fr.type = regs.lighting.lut_input.fr.Value();
104 res.lighting.lut_fr.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.fr);
105
106 res.lighting.lut_rr.enable = regs.lighting.disable_lut_rr == 0;
107 res.lighting.lut_rr.abs_input = regs.lighting.abs_lut_input.disable_rr == 0;
108 res.lighting.lut_rr.type = regs.lighting.lut_input.rr.Value();
109 res.lighting.lut_rr.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.rr);
110
111 res.lighting.lut_rg.enable = regs.lighting.disable_lut_rg == 0;
112 res.lighting.lut_rg.abs_input = regs.lighting.abs_lut_input.disable_rg == 0;
113 res.lighting.lut_rg.type = regs.lighting.lut_input.rg.Value();
114 res.lighting.lut_rg.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.rg);
115
116 res.lighting.lut_rb.enable = regs.lighting.disable_lut_rb == 0;
117 res.lighting.lut_rb.abs_input = regs.lighting.abs_lut_input.disable_rb == 0;
118 res.lighting.lut_rb.type = regs.lighting.lut_input.rb.Value();
119 res.lighting.lut_rb.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.rb);
120
121 res.lighting.config = regs.lighting.config;
122 res.lighting.fresnel_selector = regs.lighting.fresnel_selector;
123 res.lighting.bump_mode = regs.lighting.bump_mode;
124 res.lighting.bump_selector = regs.lighting.bump_selector;
125 res.lighting.bump_renorm = regs.lighting.disable_bump_renorm == 0;
126 res.lighting.clamp_highlights = regs.lighting.clamp_highlights != 0;
127
74 return res; 128 return res;
75 } 129 }
76 130
@@ -86,9 +140,37 @@ struct PicaShaderConfig {
86 return std::memcmp(this, &o, sizeof(PicaShaderConfig)) == 0; 140 return std::memcmp(this, &o, sizeof(PicaShaderConfig)) == 0;
87 }; 141 };
88 142
89 Pica::Regs::CompareFunc alpha_test_func; 143 Pica::Regs::CompareFunc alpha_test_func = Pica::Regs::CompareFunc::Never;
90 std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {}; 144 std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {};
91 u8 combiner_buffer_input; 145 u8 combiner_buffer_input = 0;
146
147 struct {
148 struct {
149 unsigned num = 0;
150 bool directional = false;
151 bool two_sided_diffuse = false;
152 bool dist_atten_enable = false;
153 GLfloat dist_atten_scale = 0.0f;
154 GLfloat dist_atten_bias = 0.0f;
155 } light[8];
156
157 bool enable = false;
158 unsigned src_num = 0;
159 Pica::Regs::LightingBumpMode bump_mode = Pica::Regs::LightingBumpMode::None;
160 unsigned bump_selector = 0;
161 bool bump_renorm = false;
162 bool clamp_highlights = false;
163
164 Pica::Regs::LightingConfig config = Pica::Regs::LightingConfig::Config0;
165 Pica::Regs::LightingFresnelSelector fresnel_selector = Pica::Regs::LightingFresnelSelector::None;
166
167 struct {
168 bool enable = false;
169 bool abs_input = false;
170 Pica::Regs::LightingLutInput type = Pica::Regs::LightingLutInput::NH;
171 float scale = 1.0f;
172 } lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb;
173 } lighting;
92}; 174};
93 175
94namespace std { 176namespace std {
@@ -167,7 +249,7 @@ private:
167 249
168 /// Structure that the hardware rendered vertices are composed of 250 /// Structure that the hardware rendered vertices are composed of
169 struct HardwareVertex { 251 struct HardwareVertex {
170 HardwareVertex(const Pica::Shader::OutputVertex& v) { 252 HardwareVertex(const Pica::Shader::OutputVertex& v, bool flip_quaternion) {
171 position[0] = v.pos.x.ToFloat32(); 253 position[0] = v.pos.x.ToFloat32();
172 position[1] = v.pos.y.ToFloat32(); 254 position[1] = v.pos.y.ToFloat32();
173 position[2] = v.pos.z.ToFloat32(); 255 position[2] = v.pos.z.ToFloat32();
@@ -182,6 +264,19 @@ private:
182 tex_coord1[1] = v.tc1.y.ToFloat32(); 264 tex_coord1[1] = v.tc1.y.ToFloat32();
183 tex_coord2[0] = v.tc2.x.ToFloat32(); 265 tex_coord2[0] = v.tc2.x.ToFloat32();
184 tex_coord2[1] = v.tc2.y.ToFloat32(); 266 tex_coord2[1] = v.tc2.y.ToFloat32();
267 normquat[0] = v.quat.x.ToFloat32();
268 normquat[1] = v.quat.y.ToFloat32();
269 normquat[2] = v.quat.z.ToFloat32();
270 normquat[3] = v.quat.w.ToFloat32();
271 view[0] = v.view.x.ToFloat32();
272 view[1] = v.view.y.ToFloat32();
273 view[2] = v.view.z.ToFloat32();
274
275 if (flip_quaternion) {
276 for (float& x : normquat) {
277 x = -x;
278 }
279 }
185 } 280 }
186 281
187 GLfloat position[4]; 282 GLfloat position[4];
@@ -189,19 +284,31 @@ private:
189 GLfloat tex_coord0[2]; 284 GLfloat tex_coord0[2];
190 GLfloat tex_coord1[2]; 285 GLfloat tex_coord1[2];
191 GLfloat tex_coord2[2]; 286 GLfloat tex_coord2[2];
287 GLfloat normquat[4];
288 GLfloat view[3];
289 };
290
291 struct LightSrc {
292 alignas(16) GLvec3 specular_0;
293 alignas(16) GLvec3 specular_1;
294 alignas(16) GLvec3 diffuse;
295 alignas(16) GLvec3 ambient;
296 alignas(16) GLvec3 position;
192 }; 297 };
193 298
194 /// Uniform structure for the Uniform Buffer Object, all members must be 16-byte aligned 299 /// Uniform structure for the Uniform Buffer Object, all members must be 16-byte aligned
195 struct UniformData { 300 struct UniformData {
196 // A vec4 color for each of the six tev stages 301 // A vec4 color for each of the six tev stages
197 std::array<GLfloat, 4> const_color[6]; 302 GLvec4 const_color[6];
198 std::array<GLfloat, 4> tev_combiner_buffer_color; 303 GLvec4 tev_combiner_buffer_color;
199 GLint alphatest_ref; 304 GLint alphatest_ref;
200 INSERT_PADDING_BYTES(12); 305 GLfloat depth_offset;
306 alignas(16) GLvec3 lighting_global_ambient;
307 LightSrc light_src[8];
201 }; 308 };
202 309
203 static_assert(sizeof(UniformData) == 0x80, "The size of the UniformData structure has changed, update the structure in the shader"); 310 static_assert(sizeof(UniformData) == 0x310, "The size of the UniformData structure has changed, update the structure in the shader");
204 static_assert(sizeof(UniformData) < 16000, "UniformData structure must be less than 16kb as per the OpenGL spec"); 311 static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec");
205 312
206 /// Reconfigure the OpenGL color texture to use the given format and dimensions 313 /// Reconfigure the OpenGL color texture to use the given format and dimensions
207 void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height); 314 void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height);
@@ -218,6 +325,9 @@ private:
218 /// Syncs the cull mode to match the PICA register 325 /// Syncs the cull mode to match the PICA register
219 void SyncCullMode(); 326 void SyncCullMode();
220 327
328 /// Syncs the depth scale and offset to match the PICA registers
329 void SyncDepthModifiers();
330
221 /// Syncs the blend enabled status to match the PICA register 331 /// Syncs the blend enabled status to match the PICA register
222 void SyncBlendEnabled(); 332 void SyncBlendEnabled();
223 333
@@ -245,6 +355,27 @@ private:
245 /// Syncs the TEV combiner color buffer to match the PICA register 355 /// Syncs the TEV combiner color buffer to match the PICA register
246 void SyncCombinerColor(); 356 void SyncCombinerColor();
247 357
358 /// Syncs the lighting global ambient color to match the PICA register
359 void SyncGlobalAmbient();
360
361 /// Syncs the lighting lookup tables
362 void SyncLightingLUT(unsigned index);
363
364 /// Syncs the specified light's diffuse color to match the PICA register
365 void SyncLightDiffuse(int light_index);
366
367 /// Syncs the specified light's ambient color to match the PICA register
368 void SyncLightAmbient(int light_index);
369
370 /// Syncs the specified light's position to match the PICA register
371 void SyncLightPosition(int light_index);
372
373 /// Syncs the specified light's specular 0 color to match the PICA register
374 void SyncLightSpecular0(int light_index);
375
376 /// Syncs the specified light's specular 1 color to match the PICA register
377 void SyncLightSpecular1(int light_index);
378
248 /// Syncs the remaining OpenGL drawing state to match the current PICA state 379 /// Syncs the remaining OpenGL drawing state to match the current PICA state
249 void SyncDrawState(); 380 void SyncDrawState();
250 381
@@ -274,8 +405,8 @@ private:
274 405
275 OpenGLState state; 406 OpenGLState state;
276 407
277 PAddr last_fb_color_addr; 408 PAddr cached_fb_color_addr;
278 PAddr last_fb_depth_addr; 409 PAddr cached_fb_depth_addr;
279 410
280 // Hardware rasterizer 411 // Hardware rasterizer
281 std::array<SamplerInfo, 3> texture_samplers; 412 std::array<SamplerInfo, 3> texture_samplers;
@@ -287,6 +418,7 @@ private:
287 418
288 struct { 419 struct {
289 UniformData data; 420 UniformData data;
421 bool lut_dirty[6];
290 bool dirty; 422 bool dirty;
291 } uniform_block_data; 423 } uniform_block_data;
292 424
@@ -294,4 +426,7 @@ private:
294 OGLBuffer vertex_buffer; 426 OGLBuffer vertex_buffer;
295 OGLBuffer uniform_buffer; 427 OGLBuffer uniform_buffer;
296 OGLFramebuffer framebuffer; 428 OGLFramebuffer framebuffer;
429
430 std::array<OGLTexture, 6> lighting_lut;
431 std::array<std::array<GLvec4, 256>, 6> lighting_lut_data;
297}; 432};
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 38de5d469..ee4b54ab9 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -32,12 +32,10 @@ static void AppendSource(std::string& out, TevStageConfig::Source source,
32 out += "primary_color"; 32 out += "primary_color";
33 break; 33 break;
34 case Source::PrimaryFragmentColor: 34 case Source::PrimaryFragmentColor:
35 // HACK: Until we implement fragment lighting, use primary_color 35 out += "primary_fragment_color";
36 out += "primary_color";
37 break; 36 break;
38 case Source::SecondaryFragmentColor: 37 case Source::SecondaryFragmentColor:
39 // HACK: Until we implement fragment lighting, use zero 38 out += "secondary_fragment_color";
40 out += "vec4(0.0)";
41 break; 39 break;
42 case Source::Texture0: 40 case Source::Texture0:
43 out += "texture(tex[0], texcoord[0])"; 41 out += "texture(tex[0], texcoord[0])";
@@ -320,25 +318,229 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi
320 out += "next_combiner_buffer.a = last_tex_env_out.a;\n"; 318 out += "next_combiner_buffer.a = last_tex_env_out.a;\n";
321} 319}
322 320
321/// Writes the code to emulate fragment lighting
322static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
323 // Define lighting globals
324 out += "vec4 diffuse_sum = vec4(0.0, 0.0, 0.0, 1.0);\n"
325 "vec4 specular_sum = vec4(0.0, 0.0, 0.0, 1.0);\n"
326 "vec3 light_vector = vec3(0.0);\n"
327 "vec3 refl_value = vec3(0.0);\n";
328
329 // Compute fragment normals
330 if (config.lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) {
331 // Bump mapping is enabled using a normal map, read perturbation vector from the selected texture
332 std::string bump_selector = std::to_string(config.lighting.bump_selector);
333 out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" + bump_selector + "]).rgb - 1.0;\n";
334
335 // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher precision result
336 if (config.lighting.bump_renorm) {
337 std::string val = "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))";
338 out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n";
339 }
340 } else if (config.lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) {
341 // Bump mapping is enabled using a tangent map
342 LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)");
343 UNIMPLEMENTED();
344 } else {
345 // No bump mapping - surface local normal is just a unit normal
346 out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n";
347 }
348
349 // Rotate the surface-local normal by the interpolated normal quaternion to convert it to eyespace
350 out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n";
351
352 // Gets the index into the specified lookup table for specular lighting
353 auto GetLutIndex = [config](unsigned light_num, Regs::LightingLutInput input, bool abs) {
354 const std::string half_angle = "normalize(normalize(view) + light_vector)";
355 std::string index;
356 switch (input) {
357 case Regs::LightingLutInput::NH:
358 index = "dot(normal, " + half_angle + ")";
359 break;
360
361 case Regs::LightingLutInput::VH:
362 index = std::string("dot(normalize(view), " + half_angle + ")");
363 break;
364
365 case Regs::LightingLutInput::NV:
366 index = std::string("dot(normal, normalize(view))");
367 break;
368
369 case Regs::LightingLutInput::LN:
370 index = std::string("dot(light_vector, normal)");
371 break;
372
373 default:
374 LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input);
375 UNIMPLEMENTED();
376 break;
377 }
378
379 if (abs) {
380 // LUT index is in the range of (0.0, 1.0)
381 index = config.lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)";
382 return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))";
383 } else {
384 // LUT index is in the range of (-1.0, 1.0)
385 index = "clamp(" + index + ", -1.0, 1.0)";
386 return "(FLOAT_255 * ((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0)";
387 }
388
389 return std::string();
390 };
391
392 // Gets the lighting lookup table value given the specified sampler and index
393 auto GetLutValue = [](Regs::LightingSampler sampler, std::string lut_index) {
394 return std::string("texture(lut[" + std::to_string((unsigned)sampler / 4) + "], " +
395 lut_index + ")[" + std::to_string((unsigned)sampler & 3) + "]");
396 };
397
398 // Write the code to emulate each enabled light
399 for (unsigned light_index = 0; light_index < config.lighting.src_num; ++light_index) {
400 const auto& light_config = config.lighting.light[light_index];
401 std::string light_src = "light_src[" + std::to_string(light_config.num) + "]";
402
403 // Compute light vector (directional or positional)
404 if (light_config.directional)
405 out += "light_vector = normalize(" + light_src + ".position);\n";
406 else
407 out += "light_vector = normalize(" + light_src + ".position + view);\n";
408
409 // Compute dot product of light_vector and normal, adjust if lighting is one-sided or two-sided
410 std::string dot_product = light_config.two_sided_diffuse ? "abs(dot(light_vector, normal))" : "max(dot(light_vector, normal), 0.0)";
411
412 // If enabled, compute distance attenuation value
413 std::string dist_atten = "1.0";
414 if (light_config.dist_atten_enable) {
415 std::string scale = std::to_string(light_config.dist_atten_scale);
416 std::string bias = std::to_string(light_config.dist_atten_bias);
417 std::string index = "(" + scale + " * length(-view - " + light_src + ".position) + " + bias + ")";
418 index = "((clamp(" + index + ", 0.0, FLOAT_255)))";
419 const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num);
420 dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index);
421 }
422
423 // If enabled, clamp specular component if lighting result is negative
424 std::string clamp_highlights = config.lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0";
425
426 // Specular 0 component
427 std::string d0_lut_value = "1.0";
428 if (config.lighting.lut_d0.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::Distribution0)) {
429 // Lookup specular "distribution 0" LUT value
430 std::string index = GetLutIndex(light_config.num, config.lighting.lut_d0.type, config.lighting.lut_d0.abs_input);
431 d0_lut_value = "(" + std::to_string(config.lighting.lut_d0.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution0, index) + ")";
432 }
433 std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)";
434
435 // If enabled, lookup ReflectRed value, otherwise, 1.0 is used
436 if (config.lighting.lut_rr.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::ReflectRed)) {
437 std::string index = GetLutIndex(light_config.num, config.lighting.lut_rr.type, config.lighting.lut_rr.abs_input);
438 std::string value = "(" + std::to_string(config.lighting.lut_rr.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")";
439 out += "refl_value.r = " + value + ";\n";
440 } else {
441 out += "refl_value.r = 1.0;\n";
442 }
443
444 // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
445 if (config.lighting.lut_rg.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::ReflectGreen)) {
446 std::string index = GetLutIndex(light_config.num, config.lighting.lut_rg.type, config.lighting.lut_rg.abs_input);
447 std::string value = "(" + std::to_string(config.lighting.lut_rg.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")";
448 out += "refl_value.g = " + value + ";\n";
449 } else {
450 out += "refl_value.g = refl_value.r;\n";
451 }
452
453 // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
454 if (config.lighting.lut_rb.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::ReflectBlue)) {
455 std::string index = GetLutIndex(light_config.num, config.lighting.lut_rb.type, config.lighting.lut_rb.abs_input);
456 std::string value = "(" + std::to_string(config.lighting.lut_rb.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")";
457 out += "refl_value.b = " + value + ";\n";
458 } else {
459 out += "refl_value.b = refl_value.r;\n";
460 }
461
462 // Specular 1 component
463 std::string d1_lut_value = "1.0";
464 if (config.lighting.lut_d1.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::Distribution1)) {
465 // Lookup specular "distribution 1" LUT value
466 std::string index = GetLutIndex(light_config.num, config.lighting.lut_d1.type, config.lighting.lut_d1.abs_input);
467 d1_lut_value = "(" + std::to_string(config.lighting.lut_d1.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution1, index) + ")";
468 }
469 std::string specular_1 = "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)";
470
471 // Fresnel
472 if (config.lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::Fresnel)) {
473 // Lookup fresnel LUT value
474 std::string index = GetLutIndex(light_config.num, config.lighting.lut_fr.type, config.lighting.lut_fr.abs_input);
475 std::string value = "(" + std::to_string(config.lighting.lut_fr.scale) + " * " + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")";
476
477 // Enabled for difffuse lighting alpha component
478 if (config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha ||
479 config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
480 out += "diffuse_sum.a *= " + value + ";\n";
481
482 // Enabled for the specular lighting alpha component
483 if (config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha ||
484 config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
485 out += "specular_sum.a *= " + value + ";\n";
486 }
487
488 // Compute primary fragment color (diffuse lighting) function
489 out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * " + dot_product + ") + " + light_src + ".ambient) * " + dist_atten + ";\n";
490
491 // Compute secondary fragment color (specular lighting) function
492 out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 + ") * " + clamp_highlights + " * " + dist_atten + ";\n";
493 }
494
495 // Sum final lighting result
496 out += "diffuse_sum.rgb += lighting_global_ambient;\n";
497 out += "primary_fragment_color = clamp(diffuse_sum, vec4(0.0), vec4(1.0));\n";
498 out += "secondary_fragment_color = clamp(specular_sum, vec4(0.0), vec4(1.0));\n";
499}
500
323std::string GenerateFragmentShader(const PicaShaderConfig& config) { 501std::string GenerateFragmentShader(const PicaShaderConfig& config) {
324 std::string out = R"( 502 std::string out = R"(
325#version 330 core 503#version 330 core
326#define NUM_TEV_STAGES 6 504#define NUM_TEV_STAGES 6
505#define NUM_LIGHTS 8
506#define LIGHTING_LUT_SIZE 256
507#define FLOAT_255 (255.0 / 256.0)
327 508
328in vec4 primary_color; 509in vec4 primary_color;
329in vec2 texcoord[3]; 510in vec2 texcoord[3];
511in vec4 normquat;
512in vec3 view;
330 513
331out vec4 color; 514out vec4 color;
332 515
516struct LightSrc {
517 vec3 specular_0;
518 vec3 specular_1;
519 vec3 diffuse;
520 vec3 ambient;
521 vec3 position;
522};
523
333layout (std140) uniform shader_data { 524layout (std140) uniform shader_data {
334 vec4 const_color[NUM_TEV_STAGES]; 525 vec4 const_color[NUM_TEV_STAGES];
335 vec4 tev_combiner_buffer_color; 526 vec4 tev_combiner_buffer_color;
336 int alphatest_ref; 527 int alphatest_ref;
528 float depth_offset;
529 vec3 lighting_global_ambient;
530 LightSrc light_src[NUM_LIGHTS];
337}; 531};
338 532
339uniform sampler2D tex[3]; 533uniform sampler2D tex[3];
534uniform sampler1D lut[6];
535
536// Rotate the vector v by the quaternion q
537vec3 quaternion_rotate(vec4 q, vec3 v) {
538 return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);
539}
340 540
341void main() { 541void main() {
542vec4 primary_fragment_color = vec4(0.0);
543vec4 secondary_fragment_color = vec4(0.0);
342)"; 544)";
343 545
344 // Do not do any sort of processing if it's obvious we're not going to pass the alpha test 546 // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
@@ -347,6 +549,9 @@ void main() {
347 return out; 549 return out;
348 } 550 }
349 551
552 if (config.lighting.enable)
553 WriteLighting(out, config);
554
350 out += "vec4 combiner_buffer = vec4(0.0);\n"; 555 out += "vec4 combiner_buffer = vec4(0.0);\n";
351 out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\n"; 556 out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\n";
352 out += "vec4 last_tex_env_out = vec4(0.0);\n"; 557 out += "vec4 last_tex_env_out = vec4(0.0);\n";
@@ -360,28 +565,36 @@ void main() {
360 out += ") discard;\n"; 565 out += ") discard;\n";
361 } 566 }
362 567
363 out += "color = last_tex_env_out;\n}"; 568 out += "color = last_tex_env_out;\n";
569 out += "gl_FragDepth = gl_FragCoord.z + depth_offset;\n}";
364 570
365 return out; 571 return out;
366} 572}
367 573
368std::string GenerateVertexShader() { 574std::string GenerateVertexShader() {
369 std::string out = "#version 330 core\n"; 575 std::string out = "#version 330 core\n";
576
370 out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n"; 577 out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n";
371 out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n"; 578 out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n";
372 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n"; 579 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n";
373 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n"; 580 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n";
374 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n"; 581 out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n";
582 out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) + ") in vec4 vert_normquat;\n";
583 out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n";
375 584
376 out += R"( 585 out += R"(
377out vec4 primary_color; 586out vec4 primary_color;
378out vec2 texcoord[3]; 587out vec2 texcoord[3];
588out vec4 normquat;
589out vec3 view;
379 590
380void main() { 591void main() {
381 primary_color = vert_color; 592 primary_color = vert_color;
382 texcoord[0] = vert_texcoord0; 593 texcoord[0] = vert_texcoord0;
383 texcoord[1] = vert_texcoord1; 594 texcoord[1] = vert_texcoord1;
384 texcoord[2] = vert_texcoord2; 595 texcoord[2] = vert_texcoord2;
596 normquat = vert_normquat;
597 view = vert_view;
385 gl_Position = vec4(vert_position.x, vert_position.y, -vert_position.z, vert_position.w); 598 gl_Position = vec4(vert_position.x, vert_position.y, -vert_position.z, vert_position.w);
386} 599}
387)"; 600)";
diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h
index 046aae14f..097242f6f 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.h
+++ b/src/video_core/renderer_opengl/gl_shader_util.h
@@ -14,6 +14,8 @@ enum Attributes {
14 ATTRIBUTE_TEXCOORD0, 14 ATTRIBUTE_TEXCOORD0,
15 ATTRIBUTE_TEXCOORD1, 15 ATTRIBUTE_TEXCOORD1,
16 ATTRIBUTE_TEXCOORD2, 16 ATTRIBUTE_TEXCOORD2,
17 ATTRIBUTE_NORMQUAT,
18 ATTRIBUTE_VIEW,
17}; 19};
18 20
19/** 21/**
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index a82372995..08e4d0b54 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -48,6 +48,10 @@ OpenGLState::OpenGLState() {
48 texture_unit.sampler = 0; 48 texture_unit.sampler = 0;
49 } 49 }
50 50
51 for (auto& lut : lighting_lut) {
52 lut.texture_1d = 0;
53 }
54
51 draw.framebuffer = 0; 55 draw.framebuffer = 0;
52 draw.vertex_array = 0; 56 draw.vertex_array = 0;
53 draw.vertex_buffer = 0; 57 draw.vertex_buffer = 0;
@@ -170,6 +174,14 @@ void OpenGLState::Apply() {
170 } 174 }
171 } 175 }
172 176
177 // Lighting LUTs
178 for (unsigned i = 0; i < ARRAY_SIZE(lighting_lut); ++i) {
179 if (lighting_lut[i].texture_1d != cur_state.lighting_lut[i].texture_1d) {
180 glActiveTexture(GL_TEXTURE3 + i);
181 glBindTexture(GL_TEXTURE_1D, lighting_lut[i].texture_1d);
182 }
183 }
184
173 // Framebuffer 185 // Framebuffer
174 if (draw.framebuffer != cur_state.draw.framebuffer) { 186 if (draw.framebuffer != cur_state.draw.framebuffer) {
175 glBindFramebuffer(GL_FRAMEBUFFER, draw.framebuffer); 187 glBindFramebuffer(GL_FRAMEBUFFER, draw.framebuffer);
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index b8ab45bb8..e848058d7 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -62,6 +62,10 @@ public:
62 } texture_units[3]; 62 } texture_units[3];
63 63
64 struct { 64 struct {
65 GLuint texture_1d; // GL_TEXTURE_BINDING_1D
66 } lighting_lut[6];
67
68 struct {
65 GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING 69 GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
66 GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING 70 GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
67 GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING 71 GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index 04c1d1a34..3d6c4e9e5 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -10,6 +10,9 @@
10 10
11#include "video_core/pica.h" 11#include "video_core/pica.h"
12 12
13using GLvec3 = std::array<GLfloat, 3>;
14using GLvec4 = std::array<GLfloat, 4>;
15
13namespace PicaToGL { 16namespace PicaToGL {
14 17
15inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { 18inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
@@ -175,7 +178,7 @@ inline GLenum StencilOp(Pica::Regs::StencilAction action) {
175 return stencil_op_table[(unsigned)action]; 178 return stencil_op_table[(unsigned)action];
176} 179}
177 180
178inline std::array<GLfloat, 4> ColorRGBA8(const u32 color) { 181inline GLvec4 ColorRGBA8(const u32 color) {
179 return { { (color >> 0 & 0xFF) / 255.0f, 182 return { { (color >> 0 & 0xFF) / 255.0f,
180 (color >> 8 & 0xFF) / 255.0f, 183 (color >> 8 & 0xFF) / 255.0f,
181 (color >> 16 & 0xFF) / 255.0f, 184 (color >> 16 & 0xFF) / 255.0f,
@@ -183,4 +186,11 @@ inline std::array<GLfloat, 4> ColorRGBA8(const u32 color) {
183 } }; 186 } };
184} 187}
185 188
189inline std::array<GLfloat, 3> LightColor(const Pica::Regs::LightColor& color) {
190 return { { color.r / 255.0f,
191 color.g / 255.0f,
192 color.b / 255.0f
193 } };
194}
195
186} // namespace 196} // namespace
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index c34215340..ca3a6a6b4 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -81,8 +81,8 @@ struct ScreenRectVertex {
81 * The projection part of the matrix is trivial, hence these operations are represented 81 * The projection part of the matrix is trivial, hence these operations are represented
82 * by a 3x2 matrix. 82 * by a 3x2 matrix.
83 */ 83 */
84static std::array<GLfloat, 3*2> MakeOrthographicMatrix(const float width, const float height) { 84static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, const float height) {
85 std::array<GLfloat, 3*2> matrix; 85 std::array<GLfloat, 3 * 2> matrix;
86 86
87 matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; 87 matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f;
88 matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; 88 matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f;
@@ -436,8 +436,6 @@ static void DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity,
436 level = Log::Level::Warning; 436 level = Log::Level::Warning;
437 break; 437 break;
438 case GL_DEBUG_SEVERITY_NOTIFICATION: 438 case GL_DEBUG_SEVERITY_NOTIFICATION:
439 level = Log::Level::Info;
440 break;
441 case GL_DEBUG_SEVERITY_LOW: 439 case GL_DEBUG_SEVERITY_LOW:
442 level = Log::Level::Debug; 440 level = Log::Level::Debug;
443 break; 441 break;
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 59f54236b..44c234ed8 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -134,11 +134,13 @@ OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attr
134 std::fmin(std::fabs(ret.color[i].ToFloat32()), 1.0f)); 134 std::fmin(std::fabs(ret.color[i].ToFloat32()), 1.0f));
135 } 135 }
136 136
137 LOG_TRACE(Render_Software, "Output vertex: pos (%.2f, %.2f, %.2f, %.2f), quat (%.2f, %.2f, %.2f, %.2f), col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f)", 137 LOG_TRACE(Render_Software, "Output vertex: pos(%.2f, %.2f, %.2f, %.2f), quat(%.2f, %.2f, %.2f, %.2f), "
138 "col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f), view(%.2f, %.2f, %.2f)",
138 ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(), 139 ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(),
139 ret.quat.x.ToFloat32(), ret.quat.y.ToFloat32(), ret.quat.z.ToFloat32(), ret.quat.w.ToFloat32(), 140 ret.quat.x.ToFloat32(), ret.quat.y.ToFloat32(), ret.quat.z.ToFloat32(), ret.quat.w.ToFloat32(),
140 ret.color.x.ToFloat32(), ret.color.y.ToFloat32(), ret.color.z.ToFloat32(), ret.color.w.ToFloat32(), 141 ret.color.x.ToFloat32(), ret.color.y.ToFloat32(), ret.color.z.ToFloat32(), ret.color.w.ToFloat32(),
141 ret.tc0.u().ToFloat32(), ret.tc0.v().ToFloat32()); 142 ret.tc0.u().ToFloat32(), ret.tc0.v().ToFloat32(),
143 ret.view.x.ToFloat32(), ret.view.y.ToFloat32(), ret.view.z.ToFloat32());
142 144
143 return ret; 145 return ret;
144} 146}
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index 1c6fa592c..f068cd93f 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -37,17 +37,19 @@ struct OutputVertex {
37 Math::Vec4<float24> color; 37 Math::Vec4<float24> color;
38 Math::Vec2<float24> tc0; 38 Math::Vec2<float24> tc0;
39 Math::Vec2<float24> tc1; 39 Math::Vec2<float24> tc1;
40 float24 pad[6]; 40 INSERT_PADDING_WORDS(2);
41 Math::Vec3<float24> view;
42 INSERT_PADDING_WORDS(1);
41 Math::Vec2<float24> tc2; 43 Math::Vec2<float24> tc2;
42 44
43 // Padding for optimal alignment 45 // Padding for optimal alignment
44 float24 pad2[4]; 46 INSERT_PADDING_WORDS(4);
45 47
46 // Attributes used to store intermediate results 48 // Attributes used to store intermediate results
47 49
48 // position after perspective divide 50 // position after perspective divide
49 Math::Vec3<float24> screenpos; 51 Math::Vec3<float24> screenpos;
50 float24 pad3; 52 INSERT_PADDING_WORDS(1);
51 53
52 // Linear interpolation 54 // Linear interpolation
53 // factor: 0=this, 1=vtx 55 // factor: 0=this, 1=vtx
diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp
index 7b0c20b74..aeced71b0 100644
--- a/src/video_core/shader/shader_interpreter.cpp
+++ b/src/video_core/shader/shader_interpreter.cpp
@@ -515,7 +515,8 @@ void RunInterpreter(UnitState<Debug>& state) {
515 515
516 case OpCode::Id::JMPU: 516 case OpCode::Id::JMPU:
517 Record<DebugDataRecord::COND_BOOL_IN>(state.debug, iteration, uniforms.b[instr.flow_control.bool_uniform_id]); 517 Record<DebugDataRecord::COND_BOOL_IN>(state.debug, iteration, uniforms.b[instr.flow_control.bool_uniform_id]);
518 if (uniforms.b[instr.flow_control.bool_uniform_id]) { 518
519 if (uniforms.b[instr.flow_control.bool_uniform_id] == !(instr.flow_control.num_instructions & 1)) {
519 state.program_counter = instr.flow_control.dest_offset - 1; 520 state.program_counter = instr.flow_control.dest_offset - 1;
520 } 521 }
521 break; 522 break;
diff --git a/src/video_core/shader/shader_jit_x64.cpp b/src/video_core/shader/shader_jit_x64.cpp
index 00415e402..4249675a5 100644
--- a/src/video_core/shader/shader_jit_x64.cpp
+++ b/src/video_core/shader/shader_jit_x64.cpp
@@ -653,7 +653,7 @@ void JitCompiler::Compile_IF(Instruction instr) {
653 FixupBranch b = J_CC(CC_Z, true); 653 FixupBranch b = J_CC(CC_Z, true);
654 654
655 // Compile the code that corresponds to the condition evaluating as true 655 // Compile the code that corresponds to the condition evaluating as true
656 Compile_Block(instr.flow_control.dest_offset - 1); 656 Compile_Block(instr.flow_control.dest_offset);
657 657
658 // If there isn't an "ELSE" condition, we are done here 658 // If there isn't an "ELSE" condition, we are done here
659 if (instr.flow_control.num_instructions == 0) { 659 if (instr.flow_control.num_instructions == 0) {
@@ -667,7 +667,7 @@ void JitCompiler::Compile_IF(Instruction instr) {
667 667
668 // This code corresponds to the "ELSE" condition 668 // This code corresponds to the "ELSE" condition
669 // Comple the code that corresponds to the condition evaluating as false 669 // Comple the code that corresponds to the condition evaluating as false
670 Compile_Block(instr.flow_control.dest_offset + instr.flow_control.num_instructions - 1); 670 Compile_Block(instr.flow_control.dest_offset + instr.flow_control.num_instructions);
671 671
672 SetJumpTarget(b2); 672 SetJumpTarget(b2);
673} 673}
@@ -691,7 +691,7 @@ void JitCompiler::Compile_LOOP(Instruction instr) {
691 691
692 auto loop_start = GetCodePtr(); 692 auto loop_start = GetCodePtr();
693 693
694 Compile_Block(instr.flow_control.dest_offset); 694 Compile_Block(instr.flow_control.dest_offset + 1);
695 695
696 ADD(32, R(LOOPCOUNT_REG), R(LOOPINC)); // Increment LOOPCOUNT_REG by Z-component 696 ADD(32, R(LOOPCOUNT_REG), R(LOOPINC)); // Increment LOOPCOUNT_REG by Z-component
697 SUB(32, R(LOOPCOUNT), Imm8(1)); // Increment loop count by 1 697 SUB(32, R(LOOPCOUNT), Imm8(1)); // Increment loop count by 1
@@ -710,19 +710,21 @@ void JitCompiler::Compile_JMP(Instruction instr) {
710 else 710 else
711 UNREACHABLE(); 711 UNREACHABLE();
712 712
713 FixupBranch b = J_CC(CC_NZ, true); 713 bool inverted_condition = (instr.opcode.Value() == OpCode::Id::JMPU) &&
714 (instr.flow_control.num_instructions & 1);
715 FixupBranch b = J_CC(inverted_condition ? CC_Z : CC_NZ, true);
714 716
715 Compile_Block(instr.flow_control.dest_offset); 717 Compile_Block(instr.flow_control.dest_offset);
716 718
717 SetJumpTarget(b); 719 SetJumpTarget(b);
718} 720}
719 721
720void JitCompiler::Compile_Block(unsigned stop) { 722void JitCompiler::Compile_Block(unsigned end) {
721 // Save current offset pointer 723 // Save current offset pointer
722 unsigned* prev_offset_ptr = offset_ptr; 724 unsigned* prev_offset_ptr = offset_ptr;
723 unsigned offset = *prev_offset_ptr; 725 unsigned offset = *prev_offset_ptr;
724 726
725 while (offset <= stop) 727 while (offset < end)
726 Compile_NextInstr(&offset); 728 Compile_NextInstr(&offset);
727 729
728 // Restore current offset pointer 730 // Restore current offset pointer
diff --git a/src/video_core/shader/shader_jit_x64.h b/src/video_core/shader/shader_jit_x64.h
index 3afbceccf..5ad2d9606 100644
--- a/src/video_core/shader/shader_jit_x64.h
+++ b/src/video_core/shader/shader_jit_x64.h
@@ -61,7 +61,7 @@ public:
61 void Compile_MAD(Instruction instr); 61 void Compile_MAD(Instruction instr);
62 62
63private: 63private:
64 void Compile_Block(unsigned stop); 64 void Compile_Block(unsigned end);
65 void Compile_NextInstr(unsigned* offset); 65 void Compile_NextInstr(unsigned* offset);
66 66
67 void Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRegister src_reg, Gen::X64Reg dest); 67 void Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRegister src_reg, Gen::X64Reg dest);