summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.travis-build.sh4
-rwxr-xr-x.travis-deps.sh4
-rw-r--r--.travis.yml4
-rw-r--r--CMakeLists.txt2
-rw-r--r--externals/cmake-modules/FindSDL2.cmake8
-rw-r--r--src/audio_core/CMakeLists.txt5
-rw-r--r--src/audio_core/codec.cpp122
-rw-r--r--src/audio_core/codec.h50
-rw-r--r--src/audio_core/hle/common.h35
-rw-r--r--src/audio_core/hle/dsp.h17
-rw-r--r--src/audio_core/hle/filter.cpp115
-rw-r--r--src/audio_core/hle/filter.h112
-rw-r--r--src/citra_qt/game_list.cpp2
-rw-r--r--src/citra_qt/main.cpp8
-rw-r--r--src/common/emu_window.h52
-rw-r--r--src/common/file_util.cpp51
-rw-r--r--src/common/logging/backend.cpp2
-rw-r--r--src/common/logging/log.h2
-rw-r--r--src/common/string_util.cpp16
-rw-r--r--src/common/string_util.h2
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp83
-rw-r--r--src/core/arm/skyeye_common/armstate.cpp7
-rw-r--r--src/core/file_sys/archive_extsavedata.h3
-rw-r--r--src/core/hle/kernel/session.h12
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/cecd/cecd.cpp29
-rw-r--r--src/core/hle/service/cecd/cecd.h23
-rw-r--r--src/core/hle/service/cecd/cecd_u.cpp5
-rw-r--r--src/core/hle/service/cfg/cfg_i.cpp12
-rw-r--r--src/core/hle/service/cfg/cfg_s.cpp8
-rw-r--r--src/core/hle/service/cfg/cfg_u.cpp1
-rw-r--r--src/core/hle/service/dlp_srvr.cpp36
-rw-r--r--src/core/hle/service/dlp_srvr.h23
-rw-r--r--src/core/hle/service/gsp_gpu.cpp221
-rw-r--r--src/core/hle/service/gsp_gpu.h2
-rw-r--r--src/core/hle/service/hid/hid.cpp110
-rw-r--r--src/core/hle/service/hid/hid.h78
-rw-r--r--src/core/hle/service/hid/hid_spvr.cpp20
-rw-r--r--src/core/hle/service/hid/hid_user.cpp20
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/soc_u.cpp13
-rw-r--r--src/core/loader/loader.h2
-rw-r--r--src/video_core/command_processor.cpp46
-rw-r--r--src/video_core/pica.cpp15
-rw-r--r--src/video_core/pica.h15
-rw-r--r--src/video_core/pica_state.h15
-rw-r--r--src/video_core/primitive_assembly.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp6
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h12
-rw-r--r--src/video_core/shader/shader.cpp18
51 files changed, 1198 insertions, 257 deletions
diff --git a/.travis-build.sh b/.travis-build.sh
index 22a3a9fd6..e06a4299b 100755
--- a/.travis-build.sh
+++ b/.travis-build.sh
@@ -11,8 +11,8 @@ fi
11 11
12#if OS is linux or is not set 12#if OS is linux or is not set
13if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then 13if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then
14 export CC=gcc-4.9 14 export CC=gcc-5
15 export CXX=g++-4.9 15 export CXX=g++-5
16 export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH 16 export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH
17 17
18 mkdir build && cd build 18 mkdir build && cd build
diff --git a/.travis-deps.sh b/.travis-deps.sh
index eb99ead4f..c7bb7e785 100755
--- a/.travis-deps.sh
+++ b/.travis-deps.sh
@@ -5,8 +5,8 @@ set -x
5 5
6#if OS is linux or is not set 6#if OS is linux or is not set
7if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then 7if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then
8 export CC=gcc-4.9 8 export CC=gcc-5
9 export CXX=g++-4.9 9 export CXX=g++-5
10 mkdir -p $HOME/.local 10 mkdir -p $HOME/.local
11 11
12 curl -L http://www.cmake.org/files/v2.8/cmake-2.8.11-Linux-i386.tar.gz \ 12 curl -L http://www.cmake.org/files/v2.8/cmake-2.8.11-Linux-i386.tar.gz \
diff --git a/.travis.yml b/.travis.yml
index 2e875cccf..8d86baece 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,8 +15,8 @@ addons:
15 sources: 15 sources:
16 - ubuntu-toolchain-r-test 16 - ubuntu-toolchain-r-test
17 packages: 17 packages:
18 - gcc-4.9 18 - gcc-5
19 - g++-4.9 19 - g++-5
20 - xorg-dev 20 - xorg-dev
21 - lib32stdc++6 # For CMake 21 - lib32stdc++6 # For CMake
22 - lftp # To upload builds 22 - lftp # To upload builds
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d6a4a915a..3a0a161e7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,7 +65,7 @@ endif()
65message(STATUS "Target architecture: ${ARCHITECTURE}") 65message(STATUS "Target architecture: ${ARCHITECTURE}")
66 66
67if (NOT MSVC) 67if (NOT MSVC)
68 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-attributes -pthread") 68 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -Wno-attributes -pthread")
69 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") 69 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
70 70
71 if (ARCHITECTURE_x86_64) 71 if (ARCHITECTURE_x86_64)
diff --git a/externals/cmake-modules/FindSDL2.cmake b/externals/cmake-modules/FindSDL2.cmake
index 0af86840a..9b8daa0d1 100644
--- a/externals/cmake-modules/FindSDL2.cmake
+++ b/externals/cmake-modules/FindSDL2.cmake
@@ -134,11 +134,17 @@ SET(SDL2_SEARCH_PATHS
134 ${SDL2_PATH} 134 ${SDL2_PATH}
135) 135)
136 136
137if(CMAKE_SIZEOF_VOID_P EQUAL 8)
138 set(VC_LIB_PATH_SUFFIX lib/x64)
139else()
140 set(VC_LIB_PATH_SUFFIX lib/x86)
141endif()
142
137FIND_LIBRARY(SDL2_LIBRARY_TEMP 143FIND_LIBRARY(SDL2_LIBRARY_TEMP
138 NAMES SDL2 144 NAMES SDL2
139 HINTS 145 HINTS
140 $ENV{SDL2DIR} 146 $ENV{SDL2DIR}
141 PATH_SUFFIXES lib64 lib 147 PATH_SUFFIXES lib64 lib ${VC_LIB_PATH_SUFFIX}
142 PATHS ${SDL2_SEARCH_PATHS} 148 PATHS ${SDL2_SEARCH_PATHS}
143) 149)
144 150
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index b0d1c7eb6..869da5e83 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -1,12 +1,17 @@
1set(SRCS 1set(SRCS
2 audio_core.cpp 2 audio_core.cpp
3 codec.cpp
3 hle/dsp.cpp 4 hle/dsp.cpp
5 hle/filter.cpp
4 hle/pipe.cpp 6 hle/pipe.cpp
5 ) 7 )
6 8
7set(HEADERS 9set(HEADERS
8 audio_core.h 10 audio_core.h
11 codec.h
12 hle/common.h
9 hle/dsp.h 13 hle/dsp.h
14 hle/filter.h
10 hle/pipe.h 15 hle/pipe.h
11 sink.h 16 sink.h
12 ) 17 )
diff --git a/src/audio_core/codec.cpp b/src/audio_core/codec.cpp
new file mode 100644
index 000000000..ab65514b7
--- /dev/null
+++ b/src/audio_core/codec.cpp
@@ -0,0 +1,122 @@
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 <cstddef>
7#include <cstring>
8#include <vector>
9
10#include "audio_core/codec.h"
11
12#include "common/assert.h"
13#include "common/common_types.h"
14#include "common/math_util.h"
15
16namespace Codec {
17
18StereoBuffer16 DecodeADPCM(const u8* const data, const size_t sample_count, const std::array<s16, 16>& adpcm_coeff, ADPCMState& state) {
19 // GC-ADPCM with scale factor and variable coefficients.
20 // Frames are 8 bytes long containing 14 samples each.
21 // Samples are 4 bits (one nibble) long.
22
23 constexpr size_t FRAME_LEN = 8;
24 constexpr size_t SAMPLES_PER_FRAME = 14;
25 constexpr std::array<int, 16> SIGNED_NIBBLES {{ 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1 }};
26
27 const size_t ret_size = sample_count % 2 == 0 ? sample_count : sample_count + 1; // Ensure multiple of two.
28 StereoBuffer16 ret(ret_size);
29
30 int yn1 = state.yn1,
31 yn2 = state.yn2;
32
33 const size_t NUM_FRAMES = (sample_count + (SAMPLES_PER_FRAME - 1)) / SAMPLES_PER_FRAME; // Round up.
34 for (size_t framei = 0; framei < NUM_FRAMES; framei++) {
35 const int frame_header = data[framei * FRAME_LEN];
36 const int scale = 1 << (frame_header & 0xF);
37 const int idx = (frame_header >> 4) & 0x7;
38
39 // Coefficients are fixed point with 11 bits fractional part.
40 const int coef1 = adpcm_coeff[idx * 2 + 0];
41 const int coef2 = adpcm_coeff[idx * 2 + 1];
42
43 // Decodes an audio sample. One nibble produces one sample.
44 const auto decode_sample = [&](const int nibble) -> s16 {
45 const int xn = nibble * scale;
46 // We first transform everything into 11 bit fixed point, perform the second order digital filter, then transform back.
47 // 0x400 == 0.5 in 11 bit fixed point.
48 // Filter: y[n] = x[n] + 0.5 + c1 * y[n-1] + c2 * y[n-2]
49 int val = ((xn << 11) + 0x400 + coef1 * yn1 + coef2 * yn2) >> 11;
50 // Clamp to output range.
51 val = MathUtil::Clamp(val, -32768, 32767);
52 // Advance output feedback.
53 yn2 = yn1;
54 yn1 = val;
55 return (s16)val;
56 };
57
58 size_t outputi = framei * SAMPLES_PER_FRAME;
59 size_t datai = framei * FRAME_LEN + 1;
60 for (size_t i = 0; i < SAMPLES_PER_FRAME && outputi < sample_count; i += 2) {
61 const s16 sample1 = decode_sample(SIGNED_NIBBLES[data[datai] & 0xF]);
62 ret[outputi].fill(sample1);
63 outputi++;
64
65 const s16 sample2 = decode_sample(SIGNED_NIBBLES[data[datai] >> 4]);
66 ret[outputi].fill(sample2);
67 outputi++;
68
69 datai++;
70 }
71 }
72
73 state.yn1 = yn1;
74 state.yn2 = yn2;
75
76 return ret;
77}
78
79static s16 SignExtendS8(u8 x) {
80 // The data is actually signed PCM8.
81 // We sign extend this to signed PCM16.
82 return static_cast<s16>(static_cast<s8>(x));
83}
84
85StereoBuffer16 DecodePCM8(const unsigned num_channels, const u8* const data, const size_t sample_count) {
86 ASSERT(num_channels == 1 || num_channels == 2);
87
88 StereoBuffer16 ret(sample_count);
89
90 if (num_channels == 1) {
91 for (size_t i = 0; i < sample_count; i++) {
92 ret[i].fill(SignExtendS8(data[i]));
93 }
94 } else {
95 for (size_t i = 0; i < sample_count; i++) {
96 ret[i][0] = SignExtendS8(data[i * 2 + 0]);
97 ret[i][1] = SignExtendS8(data[i * 2 + 1]);
98 }
99 }
100
101 return ret;
102}
103
104StereoBuffer16 DecodePCM16(const unsigned num_channels, const u8* const data, const size_t sample_count) {
105 ASSERT(num_channels == 1 || num_channels == 2);
106
107 StereoBuffer16 ret(sample_count);
108
109 if (num_channels == 1) {
110 for (size_t i = 0; i < sample_count; i++) {
111 s16 sample;
112 std::memcpy(&sample, data + i * sizeof(s16), sizeof(s16));
113 ret[i].fill(sample);
114 }
115 } else {
116 std::memcpy(ret.data(), data, sample_count * 2 * sizeof(u16));
117 }
118
119 return ret;
120}
121
122};
diff --git a/src/audio_core/codec.h b/src/audio_core/codec.h
new file mode 100644
index 000000000..e695f2edc
--- /dev/null
+++ b/src/audio_core/codec.h
@@ -0,0 +1,50 @@
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 <array>
8#include <vector>
9
10#include "common/common_types.h"
11
12namespace Codec {
13
14/// A variable length buffer of signed PCM16 stereo samples.
15using StereoBuffer16 = std::vector<std::array<s16, 2>>;
16
17/// See: Codec::DecodeADPCM
18struct ADPCMState {
19 // Two historical samples from previous processed buffer,
20 // required for ADPCM decoding
21 s16 yn1; ///< y[n-1]
22 s16 yn2; ///< y[n-2]
23};
24
25/**
26 * @param data Pointer to buffer that contains ADPCM data to decode
27 * @param sample_count Length of buffer in terms of number of samples
28 * @param adpcm_coeff ADPCM coefficients
29 * @param state ADPCM state, this is updated with new state
30 * @return Decoded stereo signed PCM16 data, sample_count in length
31 */
32StereoBuffer16 DecodeADPCM(const u8* const data, const size_t sample_count, const std::array<s16, 16>& adpcm_coeff, ADPCMState& state);
33
34/**
35 * @param num_channels Number of channels
36 * @param data Pointer to buffer that contains PCM8 data to decode
37 * @param sample_count Length of buffer in terms of number of samples
38 * @return Decoded stereo signed PCM16 data, sample_count in length
39 */
40StereoBuffer16 DecodePCM8(const unsigned num_channels, const u8* const data, const size_t sample_count);
41
42/**
43 * @param num_channels Number of channels
44 * @param data Pointer to buffer that contains PCM16 data to decode
45 * @param sample_count Length of buffer in terms of number of samples
46 * @return Decoded stereo signed PCM16 data, sample_count in length
47 */
48StereoBuffer16 DecodePCM16(const unsigned num_channels, const u8* const data, const size_t sample_count);
49
50};
diff --git a/src/audio_core/hle/common.h b/src/audio_core/hle/common.h
new file mode 100644
index 000000000..37d441eb2
--- /dev/null
+++ b/src/audio_core/hle/common.h
@@ -0,0 +1,35 @@
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 <algorithm>
8#include <array>
9
10#include "audio_core/audio_core.h"
11
12#include "common/common_types.h"
13
14namespace DSP {
15namespace HLE {
16
17/// The final output to the speakers is stereo. Preprocessing output in Source is also stereo.
18using StereoFrame16 = std::array<std::array<s16, 2>, AudioCore::samples_per_frame>;
19
20/// The DSP is quadraphonic internally.
21using QuadFrame32 = std::array<std::array<s32, 4>, AudioCore::samples_per_frame>;
22
23/**
24 * This performs the filter operation defined by FilterT::ProcessSample on the frame in-place.
25 * FilterT::ProcessSample is called sequentially on the samples.
26 */
27template<typename FrameT, typename FilterT>
28void FilterFrame(FrameT& frame, FilterT& filter) {
29 std::transform(frame.begin(), frame.end(), frame.begin(), [&filter](const typename FrameT::value_type& sample) {
30 return filter.ProcessSample(sample);
31 });
32}
33
34} // namespace HLE
35} // namespace DSP
diff --git a/src/audio_core/hle/dsp.h b/src/audio_core/hle/dsp.h
index 376436c29..c15ef0b7a 100644
--- a/src/audio_core/hle/dsp.h
+++ b/src/audio_core/hle/dsp.h
@@ -126,8 +126,11 @@ struct SourceConfiguration {
126 union { 126 union {
127 u32_le dirty_raw; 127 u32_le dirty_raw;
128 128
129 BitField<0, 1, u32_le> format_dirty;
130 BitField<1, 1, u32_le> mono_or_stereo_dirty;
129 BitField<2, 1, u32_le> adpcm_coefficients_dirty; 131 BitField<2, 1, u32_le> adpcm_coefficients_dirty;
130 BitField<3, 1, u32_le> partial_embedded_buffer_dirty; ///< Tends to be set when a looped buffer is queued. 132 BitField<3, 1, u32_le> partial_embedded_buffer_dirty; ///< Tends to be set when a looped buffer is queued.
133 BitField<4, 1, u32_le> partial_reset_flag;
131 134
132 BitField<16, 1, u32_le> enable_dirty; 135 BitField<16, 1, u32_le> enable_dirty;
133 BitField<17, 1, u32_le> interpolation_dirty; 136 BitField<17, 1, u32_le> interpolation_dirty;
@@ -143,8 +146,7 @@ struct SourceConfiguration {
143 BitField<27, 1, u32_le> gain_2_dirty; 146 BitField<27, 1, u32_le> gain_2_dirty;
144 BitField<28, 1, u32_le> sync_dirty; 147 BitField<28, 1, u32_le> sync_dirty;
145 BitField<29, 1, u32_le> reset_flag; 148 BitField<29, 1, u32_le> reset_flag;
146 149 BitField<30, 1, u32_le> embedded_buffer_dirty;
147 BitField<31, 1, u32_le> embedded_buffer_dirty;
148 }; 150 };
149 151
150 // Gain control 152 // Gain control
@@ -175,7 +177,8 @@ struct SourceConfiguration {
175 /** 177 /**
176 * This is the simplest normalized first-order digital recursive filter. 178 * This is the simplest normalized first-order digital recursive filter.
177 * The transfer function of this filter is: 179 * The transfer function of this filter is:
178 * H(z) = b0 / (1 + a1 z^-1) 180 * H(z) = b0 / (1 - a1 z^-1)
181 * Note the feedbackward coefficient is negated.
179 * Values are signed fixed point with 15 fractional bits. 182 * Values are signed fixed point with 15 fractional bits.
180 */ 183 */
181 struct SimpleFilter { 184 struct SimpleFilter {
@@ -192,11 +195,11 @@ struct SourceConfiguration {
192 * Values are signed fixed point with 14 fractional bits. 195 * Values are signed fixed point with 14 fractional bits.
193 */ 196 */
194 struct BiquadFilter { 197 struct BiquadFilter {
195 s16_le b0;
196 s16_le b1;
197 s16_le b2;
198 s16_le a1;
199 s16_le a2; 198 s16_le a2;
199 s16_le a1;
200 s16_le b2;
201 s16_le b1;
202 s16_le b0;
200 }; 203 };
201 204
202 union { 205 union {
diff --git a/src/audio_core/hle/filter.cpp b/src/audio_core/hle/filter.cpp
new file mode 100644
index 000000000..2c65ef026
--- /dev/null
+++ b/src/audio_core/hle/filter.cpp
@@ -0,0 +1,115 @@
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 <cstddef>
7
8#include "audio_core/hle/common.h"
9#include "audio_core/hle/dsp.h"
10#include "audio_core/hle/filter.h"
11
12#include "common/common_types.h"
13#include "common/math_util.h"
14
15namespace DSP {
16namespace HLE {
17
18void SourceFilters::Reset() {
19 Enable(false, false);
20}
21
22void SourceFilters::Enable(bool simple, bool biquad) {
23 simple_filter_enabled = simple;
24 biquad_filter_enabled = biquad;
25
26 if (!simple)
27 simple_filter.Reset();
28 if (!biquad)
29 biquad_filter.Reset();
30}
31
32void SourceFilters::Configure(SourceConfiguration::Configuration::SimpleFilter config) {
33 simple_filter.Configure(config);
34}
35
36void SourceFilters::Configure(SourceConfiguration::Configuration::BiquadFilter config) {
37 biquad_filter.Configure(config);
38}
39
40void SourceFilters::ProcessFrame(StereoFrame16& frame) {
41 if (!simple_filter_enabled && !biquad_filter_enabled)
42 return;
43
44 if (simple_filter_enabled) {
45 FilterFrame(frame, simple_filter);
46 }
47
48 if (biquad_filter_enabled) {
49 FilterFrame(frame, biquad_filter);
50 }
51}
52
53// SimpleFilter
54
55void SourceFilters::SimpleFilter::Reset() {
56 y1.fill(0);
57 // Configure as passthrough.
58 a1 = 0;
59 b0 = 1 << 15;
60}
61
62void SourceFilters::SimpleFilter::Configure(SourceConfiguration::Configuration::SimpleFilter config) {
63 a1 = config.a1;
64 b0 = config.b0;
65}
66
67std::array<s16, 2> SourceFilters::SimpleFilter::ProcessSample(const std::array<s16, 2>& x0) {
68 std::array<s16, 2> y0;
69 for (size_t i = 0; i < 2; i++) {
70 const s32 tmp = (b0 * x0[i] + a1 * y1[i]) >> 15;
71 y0[i] = MathUtil::Clamp(tmp, -32768, 32767);
72 }
73
74 y1 = y0;
75
76 return y0;
77}
78
79// BiquadFilter
80
81void SourceFilters::BiquadFilter::Reset() {
82 x1.fill(0);
83 x2.fill(0);
84 y1.fill(0);
85 y2.fill(0);
86 // Configure as passthrough.
87 a1 = a2 = b1 = b2 = 0;
88 b0 = 1 << 14;
89}
90
91void SourceFilters::BiquadFilter::Configure(SourceConfiguration::Configuration::BiquadFilter config) {
92 a1 = config.a1;
93 a2 = config.a2;
94 b0 = config.b0;
95 b1 = config.b1;
96 b2 = config.b2;
97}
98
99std::array<s16, 2> SourceFilters::BiquadFilter::ProcessSample(const std::array<s16, 2>& x0) {
100 std::array<s16, 2> y0;
101 for (size_t i = 0; i < 2; i++) {
102 const s32 tmp = (b0 * x0[i] + b1 * x1[i] + b2 * x2[i] + a1 * y1[i] + a2 * y2[i]) >> 14;
103 y0[i] = MathUtil::Clamp(tmp, -32768, 32767);
104 }
105
106 x2 = x1;
107 x1 = x0;
108 y2 = y1;
109 y1 = y0;
110
111 return y0;
112}
113
114} // namespace HLE
115} // namespace DSP
diff --git a/src/audio_core/hle/filter.h b/src/audio_core/hle/filter.h
new file mode 100644
index 000000000..75738f600
--- /dev/null
+++ b/src/audio_core/hle/filter.h
@@ -0,0 +1,112 @@
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 <array>
8
9#include "audio_core/hle/common.h"
10#include "audio_core/hle/dsp.h"
11
12#include "common/common_types.h"
13
14namespace DSP {
15namespace HLE {
16
17/// Preprocessing filters. There is an independent set of filters for each Source.
18class SourceFilters final {
19 SourceFilters() { Reset(); }
20
21 /// Reset internal state.
22 void Reset();
23
24 /**
25 * Enable/Disable filters
26 * See also: SourceConfiguration::Configuration::simple_filter_enabled,
27 * SourceConfiguration::Configuration::biquad_filter_enabled.
28 * @param simple If true, enables the simple filter. If false, disables it.
29 * @param simple If true, enables the biquad filter. If false, disables it.
30 */
31 void Enable(bool simple, bool biquad);
32
33 /**
34 * Configure simple filter.
35 * @param config Configuration from DSP shared memory.
36 */
37 void Configure(SourceConfiguration::Configuration::SimpleFilter config);
38
39 /**
40 * Configure biquad filter.
41 * @param config Configuration from DSP shared memory.
42 */
43 void Configure(SourceConfiguration::Configuration::BiquadFilter config);
44
45 /**
46 * Processes a frame in-place.
47 * @param frame Audio samples to process. Modified in-place.
48 */
49 void ProcessFrame(StereoFrame16& frame);
50
51private:
52 bool simple_filter_enabled;
53 bool biquad_filter_enabled;
54
55 struct SimpleFilter {
56 SimpleFilter() { Reset(); }
57
58 /// Resets internal state.
59 void Reset();
60
61 /**
62 * Configures this filter with application settings.
63 * @param config Configuration from DSP shared memory.
64 */
65 void Configure(SourceConfiguration::Configuration::SimpleFilter config);
66
67 /**
68 * Processes a single stereo PCM16 sample.
69 * @param x0 Input sample
70 * @return Output sample
71 */
72 std::array<s16, 2> ProcessSample(const std::array<s16, 2>& x0);
73
74 private:
75 // Configuration
76 s32 a1, b0;
77 // Internal state
78 std::array<s16, 2> y1;
79 } simple_filter;
80
81 struct BiquadFilter {
82 BiquadFilter() { Reset(); }
83
84 /// Resets internal state.
85 void Reset();
86
87 /**
88 * Configures this filter with application settings.
89 * @param config Configuration from DSP shared memory.
90 */
91 void Configure(SourceConfiguration::Configuration::BiquadFilter config);
92
93 /**
94 * Processes a single stereo PCM16 sample.
95 * @param x0 Input sample
96 * @return Output sample
97 */
98 std::array<s16, 2> ProcessSample(const std::array<s16, 2>& x0);
99
100 private:
101 // Configuration
102 s32 a1, a2, b0, b1, b2;
103 // Internal state
104 std::array<s16, 2> x1;
105 std::array<s16, 2> x2;
106 std::array<s16, 2> y1;
107 std::array<s16, 2> y2;
108 } biquad_filter;
109};
110
111} // namespace HLE
112} // namespace DSP
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp
index 1f8d69a03..ffcab1f03 100644
--- a/src/citra_qt/game_list.cpp
+++ b/src/citra_qt/game_list.cpp
@@ -66,7 +66,7 @@ void GameList::ValidateEntry(const QModelIndex& item)
66 66
67 if (file_path.isEmpty()) 67 if (file_path.isEmpty())
68 return; 68 return;
69 std::string std_file_path = file_path.toStdString(); 69 std::string std_file_path(file_path.toStdString());
70 if (!FileUtil::Exists(std_file_path) || FileUtil::IsDirectory(std_file_path)) 70 if (!FileUtil::Exists(std_file_path) || FileUtil::IsDirectory(std_file_path))
71 return; 71 return;
72 emit GameChosen(file_path); 72 emit GameChosen(file_path);
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index ebd52a7b3..ca0ae6f7b 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -417,7 +417,7 @@ void GMainWindow::UpdateRecentFiles() {
417} 417}
418 418
419void GMainWindow::OnGameListLoadFile(QString game_path) { 419void GMainWindow::OnGameListLoadFile(QString game_path) {
420 BootGame(game_path.toLocal8Bit().data()); 420 BootGame(game_path.toStdString());
421} 421}
422 422
423void GMainWindow::OnMenuLoadFile() { 423void GMainWindow::OnMenuLoadFile() {
@@ -428,7 +428,7 @@ void GMainWindow::OnMenuLoadFile() {
428 if (!filename.isEmpty()) { 428 if (!filename.isEmpty()) {
429 settings.setValue("romsPath", QFileInfo(filename).path()); 429 settings.setValue("romsPath", QFileInfo(filename).path());
430 430
431 BootGame(filename.toLocal8Bit().data()); 431 BootGame(filename.toStdString());
432 } 432 }
433} 433}
434 434
@@ -440,7 +440,7 @@ void GMainWindow::OnMenuLoadSymbolMap() {
440 if (!filename.isEmpty()) { 440 if (!filename.isEmpty()) {
441 settings.setValue("symbolsPath", QFileInfo(filename).path()); 441 settings.setValue("symbolsPath", QFileInfo(filename).path());
442 442
443 LoadSymbolMap(filename.toLocal8Bit().data()); 443 LoadSymbolMap(filename.toStdString());
444 } 444 }
445} 445}
446 446
@@ -461,7 +461,7 @@ void GMainWindow::OnMenuRecentFile() {
461 QString filename = action->data().toString(); 461 QString filename = action->data().toString();
462 QFileInfo file_info(filename); 462 QFileInfo file_info(filename);
463 if (file_info.exists()) { 463 if (file_info.exists()) {
464 BootGame(filename.toLocal8Bit().data()); 464 BootGame(filename.toStdString());
465 } else { 465 } else {
466 // Display an error message and remove the file from the list. 466 // Display an error message and remove the file from the list.
467 QMessageBox::information(this, tr("File not found"), tr("File \"%1\" not found").arg(filename)); 467 QMessageBox::information(this, tr("File not found"), tr("File \"%1\" not found").arg(filename));
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index a0ae4c9fa..7c3486dea 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -105,7 +105,7 @@ public:
105 * @todo Fix this function to be thread-safe. 105 * @todo Fix this function to be thread-safe.
106 * @return PadState object indicating the current pad state 106 * @return PadState object indicating the current pad state
107 */ 107 */
108 const Service::HID::PadState GetPadState() const { 108 Service::HID::PadState GetPadState() const {
109 return pad_state; 109 return pad_state;
110 } 110 }
111 111
@@ -116,11 +116,59 @@ public:
116 * @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and 116 * @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and
117 * `pressed` is true if the touch screen is currently being pressed 117 * `pressed` is true if the touch screen is currently being pressed
118 */ 118 */
119 const std::tuple<u16, u16, bool> GetTouchState() const { 119 std::tuple<u16, u16, bool> GetTouchState() const {
120 return std::make_tuple(touch_x, touch_y, touch_pressed); 120 return std::make_tuple(touch_x, touch_y, touch_pressed);
121 } 121 }
122 122
123 /** 123 /**
124 * Gets the current accelerometer state (acceleration along each three axis).
125 * Axis explained:
126 * +x is the same direction as LEFT on D-pad.
127 * +y is normal to the touch screen, pointing outward.
128 * +z is the same direction as UP on D-pad.
129 * Units:
130 * 1 unit of return value = 1/512 g (measured by hw test),
131 * where g is the gravitational acceleration (9.8 m/sec2).
132 * @note This should be called by the core emu thread to get a state set by the window thread.
133 * @todo Implement accelerometer input in front-end.
134 * @return std::tuple of (x, y, z)
135 */
136 std::tuple<s16, s16, s16> GetAccelerometerState() const {
137 // stubbed
138 return std::make_tuple(0, -512, 0);
139 }
140
141 /**
142 * Gets the current gyroscope state (angular rates about each three axis).
143 * Axis explained:
144 * +x is the same direction as LEFT on D-pad.
145 * +y is normal to the touch screen, pointing outward.
146 * +z is the same direction as UP on D-pad.
147 * Orientation is determined by right-hand rule.
148 * Units:
149 * 1 unit of return value = (1/coef) deg/sec,
150 * where coef is the return value of GetGyroscopeRawToDpsCoefficient().
151 * @note This should be called by the core emu thread to get a state set by the window thread.
152 * @todo Implement gyroscope input in front-end.
153 * @return std::tuple of (x, y, z)
154 */
155 std::tuple<s16, s16, s16> GetGyroscopeState() const {
156 // stubbed
157 return std::make_tuple(0, 0, 0);
158 }
159
160 /**
161 * Gets the coefficient for units conversion of gyroscope state.
162 * The conversion formula is r = coefficient * v,
163 * where v is angular rate in deg/sec,
164 * and r is the gyroscope state.
165 * @return float-type coefficient
166 */
167 f32 GetGyroscopeRawToDpsCoefficient() const {
168 return 14.375f; // taken from hw test, and gyroscope's document
169 }
170
171 /**
124 * Returns currently active configuration. 172 * Returns currently active configuration.
125 * @note Accesses to the returned object need not be consistent because it may be modified in another thread 173 * @note Accesses to the returned object need not be consistent because it may be modified in another thread
126 */ 174 */
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index c3061479a..9ada09f8a 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -85,7 +85,7 @@ bool Exists(const std::string &filename)
85 StripTailDirSlashes(copy); 85 StripTailDirSlashes(copy);
86 86
87#ifdef _WIN32 87#ifdef _WIN32
88 int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info); 88 int result = _wstat64(Common::UTF8ToUTF16W(copy).c_str(), &file_info);
89#else 89#else
90 int result = stat64(copy.c_str(), &file_info); 90 int result = stat64(copy.c_str(), &file_info);
91#endif 91#endif
@@ -102,7 +102,7 @@ bool IsDirectory(const std::string &filename)
102 StripTailDirSlashes(copy); 102 StripTailDirSlashes(copy);
103 103
104#ifdef _WIN32 104#ifdef _WIN32
105 int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info); 105 int result = _wstat64(Common::UTF8ToUTF16W(copy).c_str(), &file_info);
106#else 106#else
107 int result = stat64(copy.c_str(), &file_info); 107 int result = stat64(copy.c_str(), &file_info);
108#endif 108#endif
@@ -138,7 +138,7 @@ bool Delete(const std::string &filename)
138 } 138 }
139 139
140#ifdef _WIN32 140#ifdef _WIN32
141 if (!DeleteFile(Common::UTF8ToTStr(filename).c_str())) 141 if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str()))
142 { 142 {
143 LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s", 143 LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s",
144 filename.c_str(), GetLastErrorMsg()); 144 filename.c_str(), GetLastErrorMsg());
@@ -160,7 +160,7 @@ bool CreateDir(const std::string &path)
160{ 160{
161 LOG_TRACE(Common_Filesystem, "directory %s", path.c_str()); 161 LOG_TRACE(Common_Filesystem, "directory %s", path.c_str());
162#ifdef _WIN32 162#ifdef _WIN32
163 if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), nullptr)) 163 if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr))
164 return true; 164 return true;
165 DWORD error = GetLastError(); 165 DWORD error = GetLastError();
166 if (error == ERROR_ALREADY_EXISTS) 166 if (error == ERROR_ALREADY_EXISTS)
@@ -241,7 +241,7 @@ bool DeleteDir(const std::string &filename)
241 } 241 }
242 242
243#ifdef _WIN32 243#ifdef _WIN32
244 if (::RemoveDirectory(Common::UTF8ToTStr(filename).c_str())) 244 if (::RemoveDirectoryW(Common::UTF8ToUTF16W(filename).c_str()))
245 return true; 245 return true;
246#else 246#else
247 if (rmdir(filename.c_str()) == 0) 247 if (rmdir(filename.c_str()) == 0)
@@ -257,8 +257,13 @@ bool Rename(const std::string &srcFilename, const std::string &destFilename)
257{ 257{
258 LOG_TRACE(Common_Filesystem, "%s --> %s", 258 LOG_TRACE(Common_Filesystem, "%s --> %s",
259 srcFilename.c_str(), destFilename.c_str()); 259 srcFilename.c_str(), destFilename.c_str());
260#ifdef _WIN32
261 if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(), Common::UTF8ToUTF16W(destFilename).c_str()) == 0)
262 return true;
263#else
260 if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) 264 if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
261 return true; 265 return true;
266#endif
262 LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", 267 LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s",
263 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 268 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
264 return false; 269 return false;
@@ -270,7 +275,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
270 LOG_TRACE(Common_Filesystem, "%s --> %s", 275 LOG_TRACE(Common_Filesystem, "%s --> %s",
271 srcFilename.c_str(), destFilename.c_str()); 276 srcFilename.c_str(), destFilename.c_str());
272#ifdef _WIN32 277#ifdef _WIN32
273 if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE)) 278 if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(), Common::UTF8ToUTF16W(destFilename).c_str(), FALSE))
274 return true; 279 return true;
275 280
276 LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", 281 LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s",
@@ -358,7 +363,7 @@ u64 GetSize(const std::string &filename)
358 363
359 struct stat64 buf; 364 struct stat64 buf;
360#ifdef _WIN32 365#ifdef _WIN32
361 if (_tstat64(Common::UTF8ToTStr(filename).c_str(), &buf) == 0) 366 if (_wstat64(Common::UTF8ToUTF16W(filename).c_str(), &buf) == 0)
362#else 367#else
363 if (stat64(filename.c_str(), &buf) == 0) 368 if (stat64(filename.c_str(), &buf) == 0)
364#endif 369#endif
@@ -432,16 +437,16 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
432 437
433#ifdef _WIN32 438#ifdef _WIN32
434 // Find the first file in the directory. 439 // Find the first file in the directory.
435 WIN32_FIND_DATA ffd; 440 WIN32_FIND_DATAW ffd;
436 441
437 HANDLE handle_find = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd); 442 HANDLE handle_find = FindFirstFileW(Common::UTF8ToUTF16W(directory + "\\*").c_str(), &ffd);
438 if (handle_find == INVALID_HANDLE_VALUE) { 443 if (handle_find == INVALID_HANDLE_VALUE) {
439 FindClose(handle_find); 444 FindClose(handle_find);
440 return false; 445 return false;
441 } 446 }
442 // windows loop 447 // windows loop
443 do { 448 do {
444 const std::string virtual_name(Common::TStrToUTF8(ffd.cFileName)); 449 const std::string virtual_name(Common::UTF16ToUTF8(ffd.cFileName));
445#else 450#else
446 struct dirent dirent, *result = nullptr; 451 struct dirent dirent, *result = nullptr;
447 452
@@ -465,7 +470,7 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
465 found_entries += ret_entries; 470 found_entries += ret_entries;
466 471
467#ifdef _WIN32 472#ifdef _WIN32
468 } while (FindNextFile(handle_find, &ffd) != 0); 473 } while (FindNextFileW(handle_find, &ffd) != 0);
469 FindClose(handle_find); 474 FindClose(handle_find);
470#else 475#else
471 } 476 }
@@ -572,15 +577,23 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
572// Returns the current directory 577// Returns the current directory
573std::string GetCurrentDir() 578std::string GetCurrentDir()
574{ 579{
575 char *dir;
576 // Get the current working directory (getcwd uses malloc) 580 // Get the current working directory (getcwd uses malloc)
581#ifdef _WIN32
582 wchar_t *dir;
583 if (!(dir = _wgetcwd(nullptr, 0))) {
584#else
585 char *dir;
577 if (!(dir = getcwd(nullptr, 0))) { 586 if (!(dir = getcwd(nullptr, 0))) {
578 587#endif
579 LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s", 588 LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s",
580 GetLastErrorMsg()); 589 GetLastErrorMsg());
581 return nullptr; 590 return nullptr;
582 } 591 }
592#ifdef _WIN32
593 std::string strDir = Common::UTF16ToUTF8(dir);
594#else
583 std::string strDir = dir; 595 std::string strDir = dir;
596#endif
584 free(dir); 597 free(dir);
585 return strDir; 598 return strDir;
586} 599}
@@ -588,7 +601,11 @@ std::string GetCurrentDir()
588// Sets the current directory to the given directory 601// Sets the current directory to the given directory
589bool SetCurrentDir(const std::string &directory) 602bool SetCurrentDir(const std::string &directory)
590{ 603{
604#ifdef _WIN32
605 return _wchdir(Common::UTF8ToUTF16W(directory).c_str()) == 0;
606#else
591 return chdir(directory.c_str()) == 0; 607 return chdir(directory.c_str()) == 0;
608#endif
592} 609}
593 610
594#if defined(__APPLE__) 611#if defined(__APPLE__)
@@ -613,9 +630,9 @@ std::string& GetExeDirectory()
613 static std::string exe_path; 630 static std::string exe_path;
614 if (exe_path.empty()) 631 if (exe_path.empty())
615 { 632 {
616 TCHAR tchar_exe_path[2048]; 633 wchar_t wchar_exe_path[2048];
617 GetModuleFileName(nullptr, tchar_exe_path, 2048); 634 GetModuleFileNameW(nullptr, wchar_exe_path, 2048);
618 exe_path = Common::TStrToUTF8(tchar_exe_path); 635 exe_path = Common::UTF16ToUTF8(wchar_exe_path);
619 exe_path = exe_path.substr(0, exe_path.find_last_of('\\')); 636 exe_path = exe_path.substr(0, exe_path.find_last_of('\\'));
620 } 637 }
621 return exe_path; 638 return exe_path;
@@ -900,7 +917,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[])
900{ 917{
901 Close(); 918 Close();
902#ifdef _WIN32 919#ifdef _WIN32
903 _tfopen_s(&m_file, Common::UTF8ToTStr(filename).c_str(), Common::UTF8ToTStr(openmode).c_str()); 920 _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), Common::UTF8ToUTF16W(openmode).c_str());
904#else 921#else
905 m_file = fopen(filename.c_str(), openmode); 922 m_file = fopen(filename.c_str(), openmode);
906#endif 923#endif
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 4c86151ab..cfbfbc2a7 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -46,8 +46,10 @@ namespace Log {
46 SUB(Service, NIM) \ 46 SUB(Service, NIM) \
47 SUB(Service, NWM) \ 47 SUB(Service, NWM) \
48 SUB(Service, CAM) \ 48 SUB(Service, CAM) \
49 SUB(Service, CECD) \
49 SUB(Service, CFG) \ 50 SUB(Service, CFG) \
50 SUB(Service, DSP) \ 51 SUB(Service, DSP) \
52 SUB(Service, DLP) \
51 SUB(Service, HID) \ 53 SUB(Service, HID) \
52 SUB(Service, SOC) \ 54 SUB(Service, SOC) \
53 SUB(Service, IR) \ 55 SUB(Service, IR) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index e4c39c308..4f6856f3d 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -61,8 +61,10 @@ enum class Class : ClassType {
61 Service_NIM, ///< The NIM (Network interface manager) service 61 Service_NIM, ///< The NIM (Network interface manager) service
62 Service_NWM, ///< The NWM (Network wlan manager) service 62 Service_NWM, ///< The NWM (Network wlan manager) service
63 Service_CAM, ///< The CAM (Camera) service 63 Service_CAM, ///< The CAM (Camera) service
64 Service_CECD, ///< The CECD service
64 Service_CFG, ///< The CFG (Configuration) service 65 Service_CFG, ///< The CFG (Configuration) service
65 Service_DSP, ///< The DSP (DSP control) service 66 Service_DSP, ///< The DSP (DSP control) service
67 Service_DLP, ///< The DLP (Download Play) service
66 Service_HID, ///< The HID (Human interface device) service 68 Service_HID, ///< The HID (Human interface device) service
67 Service_SOC, ///< The SOC (Socket) service 69 Service_SOC, ///< The SOC (Socket) service
68 Service_IR, ///< The IR service 70 Service_IR, ///< The IR service
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 6d6fc591f..f0aa072db 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -320,27 +320,27 @@ std::u16string UTF8ToUTF16(const std::string& input)
320#endif 320#endif
321} 321}
322 322
323static std::string UTF16ToUTF8(const std::wstring& input) 323static std::wstring CPToUTF16(u32 code_page, const std::string& input)
324{ 324{
325 auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), nullptr, 0, nullptr, nullptr); 325 auto const size = MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);
326 326
327 std::string output; 327 std::wstring output;
328 output.resize(size); 328 output.resize(size);
329 329
330 if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()), nullptr, nullptr)) 330 if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size())))
331 output.clear(); 331 output.clear();
332 332
333 return output; 333 return output;
334} 334}
335 335
336static std::wstring CPToUTF16(u32 code_page, const std::string& input) 336std::string UTF16ToUTF8(const std::wstring& input)
337{ 337{
338 auto const size = MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0); 338 auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), nullptr, 0, nullptr, nullptr);
339 339
340 std::wstring output; 340 std::string output;
341 output.resize(size); 341 output.resize(size);
342 342
343 if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()))) 343 if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()), nullptr, nullptr))
344 output.clear(); 344 output.clear();
345 345
346 return output; 346 return output;
diff --git a/src/common/string_util.h b/src/common/string_util.h
index c5c474c6f..89d9f133e 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -95,7 +95,7 @@ std::string CP1252ToUTF8(const std::string& str);
95std::string SHIFTJISToUTF8(const std::string& str); 95std::string SHIFTJISToUTF8(const std::string& str);
96 96
97#ifdef _WIN32 97#ifdef _WIN32
98 98std::string UTF16ToUTF8(const std::wstring& input);
99std::wstring UTF8ToUTF16W(const std::string& str); 99std::wstring UTF8ToUTF16W(const std::string& str);
100 100
101#ifdef _UNICODE 101#ifdef _UNICODE
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 3473e2f5b..a8d891689 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -68,6 +68,7 @@ set(SRCS
68 hle/service/cfg/cfg_s.cpp 68 hle/service/cfg/cfg_s.cpp
69 hle/service/cfg/cfg_u.cpp 69 hle/service/cfg/cfg_u.cpp
70 hle/service/csnd_snd.cpp 70 hle/service/csnd_snd.cpp
71 hle/service/dlp_srvr.cpp
71 hle/service/dsp_dsp.cpp 72 hle/service/dsp_dsp.cpp
72 hle/service/err_f.cpp 73 hle/service/err_f.cpp
73 hle/service/frd/frd.cpp 74 hle/service/frd/frd.cpp
@@ -200,6 +201,7 @@ set(HEADERS
200 hle/service/cfg/cfg_s.h 201 hle/service/cfg/cfg_s.h
201 hle/service/cfg/cfg_u.h 202 hle/service/cfg/cfg_u.h
202 hle/service/csnd_snd.h 203 hle/service/csnd_snd.h
204 hle/service/dlp_srvr.h
203 hle/service/dsp_dsp.h 205 hle/service/dsp_dsp.h
204 hle/service/err_f.h 206 hle/service/err_f.h
205 hle/service/frd/frd.h 207 hle/service/frd/frd.h
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 5f8826034..9ed61947e 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -36,7 +36,8 @@ enum {
36 CALL = (1 << 4), 36 CALL = (1 << 4),
37 RET = (1 << 5), 37 RET = (1 << 5),
38 END_OF_PAGE = (1 << 6), 38 END_OF_PAGE = (1 << 6),
39 THUMB = (1 << 7) 39 THUMB = (1 << 7),
40 SINGLE_STEP = (1 << 8)
40}; 41};
41 42
42#define RM BITS(sht_oper, 0, 3) 43#define RM BITS(sht_oper, 0, 3)
@@ -3466,7 +3467,35 @@ enum {
3466 3467
3467MICROPROFILE_DEFINE(DynCom_Decode, "DynCom", "Decode", MP_RGB(255, 64, 64)); 3468MICROPROFILE_DEFINE(DynCom_Decode, "DynCom", "Decode", MP_RGB(255, 64, 64));
3468 3469
3469static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { 3470static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, const u32 phys_addr, ARM_INST_PTR& inst_base) {
3471 unsigned int inst_size = 4;
3472 unsigned int inst = Memory::Read32(phys_addr & 0xFFFFFFFC);
3473
3474 // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM instruction
3475 if (cpu->TFlag) {
3476 u32 arm_inst;
3477 ThumbDecodeStatus state = DecodeThumbInstruction(inst, phys_addr, &arm_inst, &inst_size, &inst_base);
3478
3479 // We have translated the Thumb branch instruction in the Thumb decoder
3480 if (state == ThumbDecodeStatus::BRANCH) {
3481 return inst_size;
3482 }
3483 inst = arm_inst;
3484 }
3485
3486 int idx;
3487 if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) {
3488 std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst);
3489 LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, disasm.c_str(), inst);
3490 LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]);
3491 CITRA_IGNORE_EXIT(-1);
3492 }
3493 inst_base = arm_instruction_trans[idx](inst, idx);
3494
3495 return inst_size;
3496}
3497
3498static int InterpreterTranslateBlock(ARMul_State* cpu, int& bb_start, u32 addr) {
3470 Common::Profiling::ScopeTimer timer_decode(profile_decode); 3499 Common::Profiling::ScopeTimer timer_decode(profile_decode);
3471 MICROPROFILE_SCOPE(DynCom_Decode); 3500 MICROPROFILE_SCOPE(DynCom_Decode);
3472 3501
@@ -3475,8 +3504,6 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) {
3475 // Go on next, until terminal instruction 3504 // Go on next, until terminal instruction
3476 // Save start addr of basicblock in CreamCache 3505 // Save start addr of basicblock in CreamCache
3477 ARM_INST_PTR inst_base = nullptr; 3506 ARM_INST_PTR inst_base = nullptr;
3478 unsigned int inst, inst_size = 4;
3479 int idx;
3480 int ret = NON_BRANCH; 3507 int ret = NON_BRANCH;
3481 int size = 0; // instruction size of basic block 3508 int size = 0; // instruction size of basic block
3482 bb_start = top; 3509 bb_start = top;
@@ -3485,30 +3512,10 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) {
3485 u32 pc_start = cpu->Reg[15]; 3512 u32 pc_start = cpu->Reg[15];
3486 3513
3487 while (ret == NON_BRANCH) { 3514 while (ret == NON_BRANCH) {
3488 inst = Memory::Read32(phys_addr & 0xFFFFFFFC); 3515 unsigned int inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base);
3489 3516
3490 size++; 3517 size++;
3491 // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM instruction
3492 if (cpu->TFlag) {
3493 u32 arm_inst;
3494 ThumbDecodeStatus state = DecodeThumbInstruction(inst, phys_addr, &arm_inst, &inst_size, &inst_base);
3495
3496 // We have translated the Thumb branch instruction in the Thumb decoder
3497 if (state == ThumbDecodeStatus::BRANCH) {
3498 goto translated;
3499 }
3500 inst = arm_inst;
3501 }
3502
3503 if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) {
3504 std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst);
3505 LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, disasm.c_str(), inst);
3506 LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]);
3507 CITRA_IGNORE_EXIT(-1);
3508 }
3509 inst_base = arm_instruction_trans[idx](inst, idx);
3510 3518
3511translated:
3512 phys_addr += inst_size; 3519 phys_addr += inst_size;
3513 3520
3514 if ((phys_addr & 0xfff) == 0) { 3521 if ((phys_addr & 0xfff) == 0) {
@@ -3522,6 +3529,27 @@ translated:
3522 return KEEP_GOING; 3529 return KEEP_GOING;
3523} 3530}
3524 3531
3532static int InterpreterTranslateSingle(ARMul_State* cpu, int& bb_start, u32 addr) {
3533 Common::Profiling::ScopeTimer timer_decode(profile_decode);
3534 MICROPROFILE_SCOPE(DynCom_Decode);
3535
3536 ARM_INST_PTR inst_base = nullptr;
3537 bb_start = top;
3538
3539 u32 phys_addr = addr;
3540 u32 pc_start = cpu->Reg[15];
3541
3542 InterpreterTranslateInstruction(cpu, phys_addr, inst_base);
3543
3544 if (inst_base->br == NON_BRANCH) {
3545 inst_base->br = SINGLE_STEP;
3546 }
3547
3548 cpu->instruction_cache[pc_start] = bb_start;
3549
3550 return KEEP_GOING;
3551}
3552
3525static int clz(unsigned int x) { 3553static int clz(unsigned int x) {
3526 int n; 3554 int n;
3527 if (x == 0) return (32); 3555 if (x == 0) return (32);
@@ -3871,8 +3899,11 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
3871 auto itr = cpu->instruction_cache.find(cpu->Reg[15]); 3899 auto itr = cpu->instruction_cache.find(cpu->Reg[15]);
3872 if (itr != cpu->instruction_cache.end()) { 3900 if (itr != cpu->instruction_cache.end()) {
3873 ptr = itr->second; 3901 ptr = itr->second;
3902 } else if (cpu->NumInstrsToExecute != 1) {
3903 if (InterpreterTranslateBlock(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
3904 goto END;
3874 } else { 3905 } else {
3875 if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION) 3906 if (InterpreterTranslateSingle(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
3876 goto END; 3907 goto END;
3877 } 3908 }
3878 3909
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp
index 2d814345a..5550c112e 100644
--- a/src/core/arm/skyeye_common/armstate.cpp
+++ b/src/core/arm/skyeye_common/armstate.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 <algorithm>
5#include "common/swap.h" 6#include "common/swap.h"
6#include "common/logging/log.h" 7#include "common/logging/log.h"
7#include "core/memory.h" 8#include "core/memory.h"
@@ -48,8 +49,7 @@ void ARMul_State::ChangePrivilegeMode(u32 new_mode)
48 Spsr[UNDEFBANK] = Spsr_copy; 49 Spsr[UNDEFBANK] = Spsr_copy;
49 break; 50 break;
50 case FIQ32MODE: 51 case FIQ32MODE:
51 Reg_firq[0] = Reg[13]; 52 std::copy(Reg.begin() + 8, Reg.end() - 1, Reg_firq.begin());
52 Reg_firq[1] = Reg[14];
53 Spsr[FIQBANK] = Spsr_copy; 53 Spsr[FIQBANK] = Spsr_copy;
54 break; 54 break;
55 } 55 }
@@ -85,8 +85,7 @@ void ARMul_State::ChangePrivilegeMode(u32 new_mode)
85 Bank = UNDEFBANK; 85 Bank = UNDEFBANK;
86 break; 86 break;
87 case FIQ32MODE: 87 case FIQ32MODE:
88 Reg[13] = Reg_firq[0]; 88 std::copy(Reg_firq.begin(), Reg_firq.end(), Reg.begin() + 8);
89 Reg[14] = Reg_firq[1];
90 Spsr_copy = Spsr[FIQBANK]; 89 Spsr_copy = Spsr[FIQBANK];
91 Bank = FIQBANK; 90 Bank = FIQBANK;
92 break; 91 break;
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index 287a6fee1..e9a72850d 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -45,13 +45,14 @@ public:
45 void WriteIcon(const Path& path, const u8* icon_data, size_t icon_size); 45 void WriteIcon(const Path& path, const u8* icon_data, size_t icon_size);
46 46
47private: 47private:
48 bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData archive
49
48 /** 50 /**
49 * This holds the full directory path for this archive, it is only set after a successful call 51 * This holds the full directory path for this archive, it is only set after a successful call
50 * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>. 52 * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>.
51 * See GetExtSaveDataPath for the code that extracts this data from an archive path. 53 * See GetExtSaveDataPath for the code that extracts this data from an archive path.
52 */ 54 */
53 std::string mount_point; 55 std::string mount_point;
54 bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData archive
55}; 56};
56 57
57/** 58/**
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index adaffcafe..6ddaf970e 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -16,23 +16,23 @@
16 16
17namespace IPC { 17namespace IPC {
18 18
19inline u32 MakeHeader(u16 command_id, unsigned int regular_params, unsigned int translate_params) { 19constexpr u32 MakeHeader(u16 command_id, unsigned int regular_params, unsigned int translate_params) {
20 return ((u32)command_id << 16) | (((u32)regular_params & 0x3F) << 6) | (((u32)translate_params & 0x3F) << 0); 20 return ((u32)command_id << 16) | (((u32)regular_params & 0x3F) << 6) | (((u32)translate_params & 0x3F) << 0);
21} 21}
22 22
23inline u32 MoveHandleDesc(unsigned int num_handles = 1) { 23constexpr u32 MoveHandleDesc(unsigned int num_handles = 1) {
24 return 0x0 | ((num_handles - 1) << 26); 24 return 0x0 | ((num_handles - 1) << 26);
25} 25}
26 26
27inline u32 CopyHandleDesc(unsigned int num_handles = 1) { 27constexpr u32 CopyHandleDesc(unsigned int num_handles = 1) {
28 return 0x10 | ((num_handles - 1) << 26); 28 return 0x10 | ((num_handles - 1) << 26);
29} 29}
30 30
31inline u32 CallingPidDesc() { 31constexpr u32 CallingPidDesc() {
32 return 0x20; 32 return 0x20;
33} 33}
34 34
35inline u32 StaticBufferDesc(u32 size, unsigned int buffer_id) { 35constexpr u32 StaticBufferDesc(u32 size, unsigned int buffer_id) {
36 return 0x2 | (size << 14) | ((buffer_id & 0xF) << 10); 36 return 0x2 | (size << 14) | ((buffer_id & 0xF) << 10);
37} 37}
38 38
@@ -42,7 +42,7 @@ enum MappedBufferPermissions {
42 RW = R | W, 42 RW = R | W,
43}; 43};
44 44
45inline u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) { 45constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) {
46 return 0x8 | (size << 4) | (u32)perms; 46 return 0x8 | (size << 4) | (u32)perms;
47} 47}
48 48
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 0cb76ba1c..2d22652d9 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -24,6 +24,7 @@ enum class ErrorDescription : u32 {
24 FS_InvalidOpenFlags = 230, 24 FS_InvalidOpenFlags = 230,
25 FS_NotAFile = 250, 25 FS_NotAFile = 250,
26 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive 26 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
27 OutofRangeOrMisalignedAddress = 513, // TODO(purpasmart): Check if this name fits its actual usage
27 FS_InvalidPath = 702, 28 FS_InvalidPath = 702,
28 InvalidSection = 1000, 29 InvalidSection = 1000,
29 TooLarge = 1001, 30 TooLarge = 1001,
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index 6d79ce9b4..e6e36e7ec 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6 6
7#include "core/hle/kernel/event.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8#include "core/hle/service/cecd/cecd.h" 9#include "core/hle/service/cecd/cecd.h"
9#include "core/hle/service/cecd/cecd_s.h" 10#include "core/hle/service/cecd/cecd_s.h"
@@ -12,14 +13,38 @@
12namespace Service { 13namespace Service {
13namespace CECD { 14namespace CECD {
14 15
15void Init() { 16static Kernel::SharedPtr<Kernel::Event> cecinfo_event;
16 using namespace Kernel; 17static Kernel::SharedPtr<Kernel::Event> change_state_event;
18
19void GetCecInfoEventHandle(Service::Interface* self) {
20 u32* cmd_buff = Kernel::GetCommandBuffer();
21
22 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
23 cmd_buff[3] = Kernel::g_handle_table.Create(cecinfo_event).MoveFrom(); // Event handle
24
25 LOG_WARNING(Service_CECD, "(STUBBED) called");
26}
27
28void GetChangeStateEventHandle(Service::Interface* self) {
29 u32* cmd_buff = Kernel::GetCommandBuffer();
17 30
31 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
32 cmd_buff[3] = Kernel::g_handle_table.Create(change_state_event).MoveFrom(); // Event handle
33
34 LOG_WARNING(Service_CECD, "(STUBBED) called");
35}
36
37void Init() {
18 AddService(new CECD_S_Interface); 38 AddService(new CECD_S_Interface);
19 AddService(new CECD_U_Interface); 39 AddService(new CECD_U_Interface);
40
41 cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::cecinfo_event");
42 change_state_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::change_state_event");
20} 43}
21 44
22void Shutdown() { 45void Shutdown() {
46 cecinfo_event = nullptr;
47 change_state_event = nullptr;
23} 48}
24 49
25} // namespace CECD 50} // namespace CECD
diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h
index 9e158521b..89a8d67bb 100644
--- a/src/core/hle/service/cecd/cecd.h
+++ b/src/core/hle/service/cecd/cecd.h
@@ -5,8 +5,31 @@
5#pragma once 5#pragma once
6 6
7namespace Service { 7namespace Service {
8
9class Interface;
10
8namespace CECD { 11namespace CECD {
9 12
13/**
14 * GetCecInfoEventHandle service function
15 * Inputs:
16 * 0: 0x000F0000
17 * Outputs:
18 * 1: ResultCode
19 * 3: Event Handle
20 */
21void GetCecInfoEventHandle(Service::Interface* self);
22
23/**
24 * GetChangeStateEventHandle service function
25 * Inputs:
26 * 0: 0x00100000
27 * Outputs:
28 * 1: ResultCode
29 * 3: Event Handle
30 */
31void GetChangeStateEventHandle(Service::Interface* self);
32
10/// Initialize CECD service(s) 33/// Initialize CECD service(s)
11void Init(); 34void Init();
12 35
diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp
index 9b720a738..ace1c73c0 100644
--- a/src/core/hle/service/cecd/cecd_u.cpp
+++ b/src/core/hle/service/cecd/cecd_u.cpp
@@ -2,13 +2,16 @@
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/service/cecd/cecd.h"
5#include "core/hle/service/cecd/cecd_u.h" 6#include "core/hle/service/cecd/cecd_u.h"
6 7
7namespace Service { 8namespace Service {
8namespace CECD { 9namespace CECD {
9 10
10static const Interface::FunctionInfo FunctionTable[] = { 11static const Interface::FunctionInfo FunctionTable[] = {
11 { 0x00120104, nullptr, "ReadSavedData" }, 12 {0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"},
13 {0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"},
14 {0x00120104, nullptr, "ReadSavedData"},
12}; 15};
13 16
14CECD_U_Interface::CECD_U_Interface() { 17CECD_U_Interface::CECD_U_Interface() {
diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp
index 0559a07b2..b18060f6d 100644
--- a/src/core/hle/service/cfg/cfg_i.cpp
+++ b/src/core/hle/service/cfg/cfg_i.cpp
@@ -9,6 +9,18 @@ namespace Service {
9namespace CFG { 9namespace CFG {
10 10
11const Interface::FunctionInfo FunctionTable[] = { 11const Interface::FunctionInfo FunctionTable[] = {
12 // cfg common
13 {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
14 {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
15 {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
16 {0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
17 {0x00050000, GetSystemModel, "GetSystemModel"},
18 {0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
19 {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
20 {0x00080080, nullptr, "GoThroughTable"},
21 {0x00090040, GetCountryCodeString, "GetCountryCodeString"},
22 {0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
23 // cfg:i
12 {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, 24 {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
13 {0x04020082, nullptr, "SetConfigInfoBlk4"}, 25 {0x04020082, nullptr, "SetConfigInfoBlk4"},
14 {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, 26 {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp
index b03d290e5..e001f7687 100644
--- a/src/core/hle/service/cfg/cfg_s.cpp
+++ b/src/core/hle/service/cfg/cfg_s.cpp
@@ -9,10 +9,18 @@ namespace Service {
9namespace CFG { 9namespace CFG {
10 10
11const Interface::FunctionInfo FunctionTable[] = { 11const Interface::FunctionInfo FunctionTable[] = {
12 // cfg common
12 {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, 13 {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
13 {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"}, 14 {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
14 {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"}, 15 {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
16 {0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
15 {0x00050000, GetSystemModel, "GetSystemModel"}, 17 {0x00050000, GetSystemModel, "GetSystemModel"},
18 {0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
19 {0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
20 {0x00080080, nullptr, "GoThroughTable"},
21 {0x00090040, GetCountryCodeString, "GetCountryCodeString"},
22 {0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
23 // cfg:s
16 {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, 24 {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
17 {0x04020082, nullptr, "SetConfigInfoBlk4"}, 25 {0x04020082, nullptr, "SetConfigInfoBlk4"},
18 {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, 26 {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp
index 89ae96c9e..606f7b2eb 100644
--- a/src/core/hle/service/cfg/cfg_u.cpp
+++ b/src/core/hle/service/cfg/cfg_u.cpp
@@ -9,6 +9,7 @@ namespace Service {
9namespace CFG { 9namespace CFG {
10 10
11const Interface::FunctionInfo FunctionTable[] = { 11const Interface::FunctionInfo FunctionTable[] = {
12 // cfg common
12 {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, 13 {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
13 {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"}, 14 {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
14 {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"}, 15 {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
diff --git a/src/core/hle/service/dlp_srvr.cpp b/src/core/hle/service/dlp_srvr.cpp
new file mode 100644
index 000000000..1f30188da
--- /dev/null
+++ b/src/core/hle/service/dlp_srvr.cpp
@@ -0,0 +1,36 @@
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 "common/logging/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/dlp_srvr.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace DLP_SRVR
11
12namespace DLP_SRVR {
13
14static void unk_0x000E0040(Service::Interface* self) {
15 u32* cmd_buff = Kernel::GetCommandBuffer();
16
17 cmd_buff[1] = RESULT_SUCCESS.raw;
18 cmd_buff[2] = 0;
19
20 LOG_WARNING(Service_DLP, "(STUBBED) called");
21}
22
23const Interface::FunctionInfo FunctionTable[] = {
24 {0x00010183, nullptr, "Initialize"},
25 {0x00020000, nullptr, "Finalize"},
26 {0x000E0040, unk_0x000E0040, "unk_0x000E0040"},
27};
28
29////////////////////////////////////////////////////////////////////////////////////////////////////
30// Interface class
31
32Interface::Interface() {
33 Register(FunctionTable);
34}
35
36} // namespace
diff --git a/src/core/hle/service/dlp_srvr.h b/src/core/hle/service/dlp_srvr.h
new file mode 100644
index 000000000..d65d00814
--- /dev/null
+++ b/src/core/hle/service/dlp_srvr.h
@@ -0,0 +1,23 @@
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 "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace DLP_SRVR
11
12namespace DLP_SRVR {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "dlp:SRVR";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 2ace2cade..0c655395e 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -31,6 +31,13 @@ const static u32 REGS_BEGIN = 0x1EB00000;
31 31
32namespace GSP_GPU { 32namespace GSP_GPU {
33 33
34const ResultCode ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED(ErrorDescription::OutofRangeOrMisalignedAddress, ErrorModule::GX,
35 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02A01
36const ResultCode ERR_GSP_REGS_MISALIGNED(ErrorDescription::MisalignedSize, ErrorModule::GX,
37 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02BF2
38const ResultCode ERR_GSP_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorModule::GX,
39 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02BEC
40
34/// Event triggered when GSP interrupt has been signalled 41/// Event triggered when GSP interrupt has been signalled
35Kernel::SharedPtr<Kernel::Event> g_interrupt_event; 42Kernel::SharedPtr<Kernel::Event> g_interrupt_event;
36/// GSP shared memoryings 43/// GSP shared memoryings
@@ -59,47 +66,87 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
59} 66}
60 67
61/** 68/**
62 * Checks if the parameters in a register write call are valid and logs in the case that 69 * Writes sequential GSP GPU hardware registers using an array of source data
63 * they are not 70 *
64 * @param base_address The first address in the sequence of registers that will be written 71 * @param base_address The address of the first register in the sequence
65 * @param size_in_bytes The number of registers that will be written 72 * @param size_in_bytes The number of registers to update (size of data)
66 * @return true if the parameters are valid, false otherwise 73 * @param data A pointer to the source data
74 * @return RESULT_SUCCESS if the parameters are valid, error code otherwise
67 */ 75 */
68static bool CheckWriteParameters(u32 base_address, u32 size_in_bytes) { 76static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
69 // TODO: Return proper error codes 77 // This magic number is verified to be done by the gsp module
70 if (base_address + size_in_bytes >= 0x420000) { 78 const u32 max_size_in_bytes = 0x80;
71 LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)", 79
80 if (base_address & 3 || base_address >= 0x420000) {
81 LOG_ERROR(Service_GSP, "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)",
72 base_address, size_in_bytes); 82 base_address, size_in_bytes);
73 return false; 83 return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED;
74 } 84 } else if (size_in_bytes <= max_size_in_bytes) {
85 if (size_in_bytes & 3) {
86 LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes);
87 return ERR_GSP_REGS_MISALIGNED;
88 } else {
89 while (size_in_bytes > 0) {
90 HW::Write<u32>(base_address + REGS_BEGIN, *data);
91
92 size_in_bytes -= 4;
93 ++data;
94 base_address += 4;
95 }
96 return RESULT_SUCCESS;
97 }
75 98
76 // size should be word-aligned 99 } else {
77 if ((size_in_bytes % 4) != 0) { 100 LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes);
78 LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes); 101 return ERR_GSP_REGS_INVALID_SIZE;
79 return false;
80 } 102 }
81
82 return true;
83} 103}
84 104
85/** 105/**
86 * Writes sequential GSP GPU hardware registers using an array of source data 106 * Updates sequential GSP GPU hardware registers using parallel arrays of source data and masks.
107 * For each register, the value is updated only where the mask is high
87 * 108 *
88 * @param base_address The address of the first register in the sequence 109 * @param base_address The address of the first register in the sequence
89 * @param size_in_bytes The number of registers to update (size of data) 110 * @param size_in_bytes The number of registers to update (size of data)
90 * @param data A pointer to the source data 111 * @param data A pointer to the source data to use for updates
112 * @param masks A pointer to the masks
113 * @return RESULT_SUCCESS if the parameters are valid, error code otherwise
91 */ 114 */
92static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { 115static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) {
93 // TODO: Return proper error codes 116 // This magic number is verified to be done by the gsp module
94 if (!CheckWriteParameters(base_address, size_in_bytes)) 117 const u32 max_size_in_bytes = 0x80;
95 return;
96 118
97 while (size_in_bytes > 0) { 119 if (base_address & 3 || base_address >= 0x420000) {
98 HW::Write<u32>(base_address + REGS_BEGIN, *data); 120 LOG_ERROR(Service_GSP, "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)",
121 base_address, size_in_bytes);
122 return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED;
123 } else if (size_in_bytes <= max_size_in_bytes) {
124 if (size_in_bytes & 3) {
125 LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes);
126 return ERR_GSP_REGS_MISALIGNED;
127 } else {
128 while (size_in_bytes > 0) {
129 const u32 reg_address = base_address + REGS_BEGIN;
130
131 u32 reg_value;
132 HW::Read<u32>(reg_value, reg_address);
133
134 // Update the current value of the register only for set mask bits
135 reg_value = (reg_value & ~*masks) | (*data | *masks);
136
137 HW::Write<u32>(reg_address, reg_value);
138
139 size_in_bytes -= 4;
140 ++data;
141 ++masks;
142 base_address += 4;
143 }
144 return RESULT_SUCCESS;
145 }
99 146
100 size_in_bytes -= 4; 147 } else {
101 ++data; 148 LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes);
102 base_address += 4; 149 return ERR_GSP_REGS_INVALID_SIZE;
103 } 150 }
104} 151}
105 152
@@ -120,39 +167,7 @@ static void WriteHWRegs(Service::Interface* self) {
120 167
121 u32* src = (u32*)Memory::GetPointer(cmd_buff[4]); 168 u32* src = (u32*)Memory::GetPointer(cmd_buff[4]);
122 169
123 WriteHWRegs(reg_addr, size, src); 170 cmd_buff[1] = WriteHWRegs(reg_addr, size, src).raw;
124}
125
126/**
127 * Updates sequential GSP GPU hardware registers using parallel arrays of source data and masks.
128 * For each register, the value is updated only where the mask is high
129 *
130 * @param base_address The address of the first register in the sequence
131 * @param size_in_bytes The number of registers to update (size of data)
132 * @param data A pointer to the source data to use for updates
133 * @param masks A pointer to the masks
134 */
135static void WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) {
136 // TODO: Return proper error codes
137 if (!CheckWriteParameters(base_address, size_in_bytes))
138 return;
139
140 while (size_in_bytes > 0) {
141 const u32 reg_address = base_address + REGS_BEGIN;
142
143 u32 reg_value;
144 HW::Read<u32>(reg_value, reg_address);
145
146 // Update the current value of the register only for set mask bits
147 reg_value = (reg_value & ~*masks) | (*data | *masks);
148
149 HW::Write<u32>(reg_address, reg_value);
150
151 size_in_bytes -= 4;
152 ++data;
153 ++masks;
154 base_address += 4;
155 }
156} 171}
157 172
158/** 173/**
@@ -174,7 +189,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) {
174 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); 189 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
175 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); 190 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
176 191
177 WriteHWRegsWithMask(reg_addr, size, src_data, mask_data); 192 cmd_buff[1] = WriteHWRegsWithMask(reg_addr, size, src_data, mask_data).raw;
178} 193}
179 194
180/// Read a GSP GPU hardware register 195/// Read a GSP GPU hardware register
@@ -206,27 +221,27 @@ static void ReadHWRegs(Service::Interface* self) {
206 } 221 }
207} 222}
208 223
209void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { 224ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
210 u32 base_address = 0x400000; 225 u32 base_address = 0x400000;
211 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); 226 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
212 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); 227 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
213 if (info.active_fb == 0) { 228 if (info.active_fb == 0) {
214 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4, 229 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)),
215 &phys_address_left); 230 4, &phys_address_left);
216 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4, 231 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)),
217 &phys_address_right); 232 4, &phys_address_right);
218 } else { 233 } else {
219 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4, 234 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)),
220 &phys_address_left); 235 4, &phys_address_left);
221 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4, 236 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)),
222 &phys_address_right); 237 4, &phys_address_right);
223 } 238 }
224 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4, 239 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)),
225 &info.stride); 240 4, &info.stride);
226 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4, 241 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)),
227 &info.format); 242 4, &info.format);
228 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, 243 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)),
229 &info.shown_fb); 244 4, &info.shown_fb);
230 245
231 if (Pica::g_debug_context) 246 if (Pica::g_debug_context)
232 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr); 247 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
@@ -234,6 +249,8 @@ void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
234 if (screen_id == 0) { 249 if (screen_id == 0) {
235 MicroProfileFlip(); 250 MicroProfileFlip();
236 } 251 }
252
253 return RESULT_SUCCESS;
237} 254}
238 255
239/** 256/**
@@ -251,9 +268,8 @@ static void SetBufferSwap(Service::Interface* self) {
251 u32* cmd_buff = Kernel::GetCommandBuffer(); 268 u32* cmd_buff = Kernel::GetCommandBuffer();
252 u32 screen_id = cmd_buff[1]; 269 u32 screen_id = cmd_buff[1];
253 FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2]; 270 FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2];
254 SetBufferSwap(screen_id, *fb_info);
255 271
256 cmd_buff[1] = 0; // No error 272 cmd_buff[1] = SetBufferSwap(screen_id, *fb_info).raw;
257} 273}
258 274
259/** 275/**
@@ -286,6 +302,22 @@ static void FlushDataCache(Service::Interface* self) {
286} 302}
287 303
288/** 304/**
305 * GSP_GPU::SetAxiConfigQoSMode service function
306 * Inputs:
307 * 1 : Mode, unused in emulator
308 * Outputs:
309 * 1 : Result of function, 0 on success, otherwise error code
310 */
311static void SetAxiConfigQoSMode(Service::Interface* self) {
312 u32* cmd_buff = Kernel::GetCommandBuffer();
313 u32 mode = cmd_buff[1];
314
315 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
316
317 LOG_WARNING(Service_GSP, "(STUBBED) called mode=0x%08X", mode);
318}
319
320/**
289 * GSP_GPU::RegisterInterruptRelayQueue service function 321 * GSP_GPU::RegisterInterruptRelayQueue service function
290 * Inputs: 322 * Inputs:
291 * 1 : "Flags" field, purpose is unknown 323 * 1 : "Flags" field, purpose is unknown
@@ -302,6 +334,12 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
302 g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]); 334 g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]);
303 ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!"); 335 ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!");
304 336
337 g_interrupt_event->name = "GSP_GPU::interrupt_event";
338
339 using Kernel::MemoryPermission;
340 g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
341 MemoryPermission::ReadWrite, "GSPSharedMem");
342
305 Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); 343 Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom();
306 344
307 // This specific code is required for a successful initialization, rather than 0 345 // This specific code is required for a successful initialization, rather than 0
@@ -314,6 +352,22 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
314} 352}
315 353
316/** 354/**
355 * GSP_GPU::UnregisterInterruptRelayQueue service function
356 * Outputs:
357 * 1 : Result of function, 0 on success, otherwise error code
358 */
359static void UnregisterInterruptRelayQueue(Service::Interface* self) {
360 u32* cmd_buff = Kernel::GetCommandBuffer();
361
362 g_shared_memory = nullptr;
363 g_interrupt_event = nullptr;
364
365 cmd_buff[1] = RESULT_SUCCESS.raw;
366
367 LOG_WARNING(Service_GSP, "called");
368}
369
370/**
317 * Signals that the specified interrupt type has occurred to userland code 371 * Signals that the specified interrupt type has occurred to userland code
318 * @param interrupt_id ID of interrupt that is being signalled 372 * @param interrupt_id ID of interrupt that is being signalled
319 * @todo This should probably take a thread_id parameter and only signal this thread? 373 * @todo This should probably take a thread_id parameter and only signal this thread?
@@ -591,11 +645,11 @@ const Interface::FunctionInfo FunctionTable[] = {
591 {0x000D0140, nullptr, "SetDisplayTransfer"}, 645 {0x000D0140, nullptr, "SetDisplayTransfer"},
592 {0x000E0180, nullptr, "SetTextureCopy"}, 646 {0x000E0180, nullptr, "SetTextureCopy"},
593 {0x000F0200, nullptr, "SetMemoryFill"}, 647 {0x000F0200, nullptr, "SetMemoryFill"},
594 {0x00100040, nullptr, "SetAxiConfigQoSMode"}, 648 {0x00100040, SetAxiConfigQoSMode, "SetAxiConfigQoSMode"},
595 {0x00110040, nullptr, "SetPerfLogMode"}, 649 {0x00110040, nullptr, "SetPerfLogMode"},
596 {0x00120000, nullptr, "GetPerfLog"}, 650 {0x00120000, nullptr, "GetPerfLog"},
597 {0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"}, 651 {0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"},
598 {0x00140000, nullptr, "UnregisterInterruptRelayQueue"}, 652 {0x00140000, UnregisterInterruptRelayQueue, "UnregisterInterruptRelayQueue"},
599 {0x00150002, nullptr, "TryAcquireRight"}, 653 {0x00150002, nullptr, "TryAcquireRight"},
600 {0x00160042, nullptr, "AcquireRight"}, 654 {0x00160042, nullptr, "AcquireRight"},
601 {0x00170000, nullptr, "ReleaseRight"}, 655 {0x00170000, nullptr, "ReleaseRight"},
@@ -616,10 +670,7 @@ Interface::Interface() {
616 Register(FunctionTable); 670 Register(FunctionTable);
617 671
618 g_interrupt_event = nullptr; 672 g_interrupt_event = nullptr;
619 673 g_shared_memory = nullptr;
620 using Kernel::MemoryPermission;
621 g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
622 MemoryPermission::ReadWrite, "GSPSharedMem");
623 674
624 g_thread_id = 0; 675 g_thread_id = 0;
625} 676}
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index 0e2f7a21e..55a993bb8 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -194,7 +194,7 @@ public:
194 */ 194 */
195void SignalInterrupt(InterruptId interrupt_id); 195void SignalInterrupt(InterruptId interrupt_id);
196 196
197void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info); 197ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
198 198
199/** 199/**
200 * Retrieves the framebuffer info stored in the GSP shared memory for the 200 * Retrieves the framebuffer info stored in the GSP shared memory for the
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index cb4fd38e2..1053d0f40 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -33,6 +33,11 @@ static Kernel::SharedPtr<Kernel::Event> event_debug_pad;
33 33
34static u32 next_pad_index; 34static u32 next_pad_index;
35static u32 next_touch_index; 35static u32 next_touch_index;
36static u32 next_accelerometer_index;
37static u32 next_gyroscope_index;
38
39static int enable_accelerometer_count = 0; // positive means enabled
40static int enable_gyroscope_count = 0; // positive means enabled
36 41
37const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{ 42const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{
38 Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y, 43 Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y,
@@ -78,17 +83,17 @@ void Update() {
78 PadState changed = { { (state.hex ^ old_state.hex) } }; 83 PadState changed = { { (state.hex ^ old_state.hex) } };
79 84
80 // Get the current Pad entry 85 // Get the current Pad entry
81 PadDataEntry* pad_entry = &mem->pad.entries[mem->pad.index]; 86 PadDataEntry& pad_entry = mem->pad.entries[mem->pad.index];
82 87
83 // Update entry properties 88 // Update entry properties
84 pad_entry->current_state.hex = state.hex; 89 pad_entry.current_state.hex = state.hex;
85 pad_entry->delta_additions.hex = changed.hex & state.hex; 90 pad_entry.delta_additions.hex = changed.hex & state.hex;
86 pad_entry->delta_removals.hex = changed.hex & old_state.hex;; 91 pad_entry.delta_removals.hex = changed.hex & old_state.hex;;
87 92
88 // Set circle Pad 93 // Set circle Pad
89 pad_entry->circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS : 94 pad_entry.circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS :
90 state.circle_right ? MAX_CIRCLEPAD_POS : 0x0; 95 state.circle_right ? MAX_CIRCLEPAD_POS : 0x0;
91 pad_entry->circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS : 96 pad_entry.circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS :
92 state.circle_up ? MAX_CIRCLEPAD_POS : 0x0; 97 state.circle_up ? MAX_CIRCLEPAD_POS : 0x0;
93 98
94 // If we just updated index 0, provide a new timestamp 99 // If we just updated index 0, provide a new timestamp
@@ -101,11 +106,11 @@ void Update() {
101 next_touch_index = (next_touch_index + 1) % mem->touch.entries.size(); 106 next_touch_index = (next_touch_index + 1) % mem->touch.entries.size();
102 107
103 // Get the current touch entry 108 // Get the current touch entry
104 TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index]; 109 TouchDataEntry& touch_entry = mem->touch.entries[mem->touch.index];
105 bool pressed = false; 110 bool pressed = false;
106 111
107 std::tie(touch_entry->x, touch_entry->y, pressed) = VideoCore::g_emu_window->GetTouchState(); 112 std::tie(touch_entry.x, touch_entry.y, pressed) = VideoCore::g_emu_window->GetTouchState();
108 touch_entry->valid.Assign(pressed ? 1 : 0); 113 touch_entry.valid.Assign(pressed ? 1 : 0);
109 114
110 // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which 115 // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which
111 // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being 116 // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being
@@ -120,6 +125,58 @@ void Update() {
120 // Signal both handles when there's an update to Pad or touch 125 // Signal both handles when there's an update to Pad or touch
121 event_pad_or_touch_1->Signal(); 126 event_pad_or_touch_1->Signal();
122 event_pad_or_touch_2->Signal(); 127 event_pad_or_touch_2->Signal();
128
129 // Update accelerometer
130 if (enable_accelerometer_count > 0) {
131 mem->accelerometer.index = next_accelerometer_index;
132 next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size();
133
134 AccelerometerDataEntry& accelerometer_entry = mem->accelerometer.entries[mem->accelerometer.index];
135 std::tie(accelerometer_entry.x, accelerometer_entry.y, accelerometer_entry.z)
136 = VideoCore::g_emu_window->GetAccelerometerState();
137
138 // Make up "raw" entry
139 // TODO(wwylele):
140 // From hardware testing, the raw_entry values are approximately,
141 // but not exactly, as twice as corresponding entries (or with a minus sign).
142 // It may caused by system calibration to the accelerometer.
143 // Figure out how it works, or, if no game reads raw_entry,
144 // the following three lines can be removed and leave raw_entry unimplemented.
145 mem->accelerometer.raw_entry.x = -2 * accelerometer_entry.x;
146 mem->accelerometer.raw_entry.z = 2 * accelerometer_entry.y;
147 mem->accelerometer.raw_entry.y = -2 * accelerometer_entry.z;
148
149 // If we just updated index 0, provide a new timestamp
150 if (mem->accelerometer.index == 0) {
151 mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks;
152 mem->accelerometer.index_reset_ticks = (s64)CoreTiming::GetTicks();
153 }
154
155 event_accelerometer->Signal();
156 }
157
158 // Update gyroscope
159 if (enable_gyroscope_count > 0) {
160 mem->gyroscope.index = next_gyroscope_index;
161 next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size();
162
163 GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index];
164 std::tie(gyroscope_entry.x, gyroscope_entry.y, gyroscope_entry.z)
165 = VideoCore::g_emu_window->GetGyroscopeState();
166
167 // Make up "raw" entry
168 mem->gyroscope.raw_entry.x = gyroscope_entry.x;
169 mem->gyroscope.raw_entry.z = -gyroscope_entry.y;
170 mem->gyroscope.raw_entry.y = gyroscope_entry.z;
171
172 // If we just updated index 0, provide a new timestamp
173 if (mem->gyroscope.index == 0) {
174 mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks;
175 mem->gyroscope.index_reset_ticks = (s64)CoreTiming::GetTicks();
176 }
177
178 event_gyroscope->Signal();
179 }
123} 180}
124 181
125void GetIPCHandles(Service::Interface* self) { 182void GetIPCHandles(Service::Interface* self) {
@@ -139,40 +196,69 @@ void GetIPCHandles(Service::Interface* self) {
139void EnableAccelerometer(Service::Interface* self) { 196void EnableAccelerometer(Service::Interface* self) {
140 u32* cmd_buff = Kernel::GetCommandBuffer(); 197 u32* cmd_buff = Kernel::GetCommandBuffer();
141 198
199 ++enable_accelerometer_count;
142 event_accelerometer->Signal(); 200 event_accelerometer->Signal();
143 201
144 cmd_buff[1] = RESULT_SUCCESS.raw; 202 cmd_buff[1] = RESULT_SUCCESS.raw;
145 203
146 LOG_WARNING(Service_HID, "(STUBBED) called"); 204 LOG_DEBUG(Service_HID, "called");
147} 205}
148 206
149void DisableAccelerometer(Service::Interface* self) { 207void DisableAccelerometer(Service::Interface* self) {
150 u32* cmd_buff = Kernel::GetCommandBuffer(); 208 u32* cmd_buff = Kernel::GetCommandBuffer();
151 209
210 --enable_accelerometer_count;
152 event_accelerometer->Signal(); 211 event_accelerometer->Signal();
153 212
154 cmd_buff[1] = RESULT_SUCCESS.raw; 213 cmd_buff[1] = RESULT_SUCCESS.raw;
155 214
156 LOG_WARNING(Service_HID, "(STUBBED) called"); 215 LOG_DEBUG(Service_HID, "called");
157} 216}
158 217
159void EnableGyroscopeLow(Service::Interface* self) { 218void EnableGyroscopeLow(Service::Interface* self) {
160 u32* cmd_buff = Kernel::GetCommandBuffer(); 219 u32* cmd_buff = Kernel::GetCommandBuffer();
161 220
221 ++enable_gyroscope_count;
162 event_gyroscope->Signal(); 222 event_gyroscope->Signal();
163 223
164 cmd_buff[1] = RESULT_SUCCESS.raw; 224 cmd_buff[1] = RESULT_SUCCESS.raw;
165 225
166 LOG_WARNING(Service_HID, "(STUBBED) called"); 226 LOG_DEBUG(Service_HID, "called");
167} 227}
168 228
169void DisableGyroscopeLow(Service::Interface* self) { 229void DisableGyroscopeLow(Service::Interface* self) {
170 u32* cmd_buff = Kernel::GetCommandBuffer(); 230 u32* cmd_buff = Kernel::GetCommandBuffer();
171 231
232 --enable_gyroscope_count;
172 event_gyroscope->Signal(); 233 event_gyroscope->Signal();
173 234
174 cmd_buff[1] = RESULT_SUCCESS.raw; 235 cmd_buff[1] = RESULT_SUCCESS.raw;
175 236
237 LOG_DEBUG(Service_HID, "called");
238}
239
240void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self) {
241 u32* cmd_buff = Kernel::GetCommandBuffer();
242
243 cmd_buff[1] = RESULT_SUCCESS.raw;
244
245 f32 coef = VideoCore::g_emu_window->GetGyroscopeRawToDpsCoefficient();
246 memcpy(&cmd_buff[2], &coef, 4);
247}
248
249void GetGyroscopeLowCalibrateParam(Service::Interface* self) {
250 u32* cmd_buff = Kernel::GetCommandBuffer();
251
252 cmd_buff[1] = RESULT_SUCCESS.raw;
253
254 const s16 param_unit = 6700; // an approximate value taken from hw
255 GyroscopeCalibrateParam param = {
256 { 0, param_unit, -param_unit },
257 { 0, param_unit, -param_unit },
258 { 0, param_unit, -param_unit },
259 };
260 memcpy(&cmd_buff[2], &param, sizeof(param));
261
176 LOG_WARNING(Service_HID, "(STUBBED) called"); 262 LOG_WARNING(Service_HID, "(STUBBED) called");
177} 263}
178 264
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 517f4f2ae..170d19ea8 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -78,6 +78,24 @@ struct TouchDataEntry {
78}; 78};
79 79
80/** 80/**
81 * Structure of a single entry of accelerometer state history within HID shared memory
82 */
83struct AccelerometerDataEntry {
84 s16 x;
85 s16 y;
86 s16 z;
87};
88
89/**
90 * Structure of a single entry of gyroscope state history within HID shared memory
91 */
92struct GyroscopeDataEntry {
93 s16 x;
94 s16 y;
95 s16 z;
96};
97
98/**
81 * Structure of data stored in HID shared memory 99 * Structure of data stored in HID shared memory
82 */ 100 */
83struct SharedMem { 101struct SharedMem {
@@ -112,6 +130,46 @@ struct SharedMem {
112 130
113 std::array<TouchDataEntry, 8> entries; ///< Last 8 touch entries, in pixel coordinates 131 std::array<TouchDataEntry, 8> entries; ///< Last 8 touch entries, in pixel coordinates
114 } touch; 132 } touch;
133
134 /// Accelerometer data
135 struct {
136 s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
137 s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
138 u32 index; ///< Index of the last updated accelerometer entry
139
140 INSERT_PADDING_WORDS(0x1);
141
142 AccelerometerDataEntry raw_entry;
143 INSERT_PADDING_BYTES(2);
144
145 std::array<AccelerometerDataEntry, 8> entries;
146 } accelerometer;
147
148 /// Gyroscope data
149 struct {
150 s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
151 s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
152 u32 index; ///< Index of the last updated accelerometer entry
153
154 INSERT_PADDING_WORDS(0x1);
155
156 GyroscopeDataEntry raw_entry;
157 INSERT_PADDING_BYTES(2);
158
159 std::array<GyroscopeDataEntry, 32> entries;
160 } gyroscope;
161};
162
163/**
164 * Structure of calibrate params that GetGyroscopeLowCalibrateParam returns
165 */
166struct GyroscopeCalibrateParam {
167 struct {
168 // TODO (wwylele): figure out the exact meaning of these params
169 s16 zero_point;
170 s16 positive_unit_point;
171 s16 negative_unit_point;
172 } x, y, z;
115}; 173};
116 174
117// TODO: MSVC does not support using offsetof() on non-static data members even though this 175// TODO: MSVC does not support using offsetof() on non-static data members even though this
@@ -222,6 +280,26 @@ void DisableGyroscopeLow(Interface* self);
222 */ 280 */
223void GetSoundVolume(Interface* self); 281void GetSoundVolume(Interface* self);
224 282
283/**
284 * HID::GetGyroscopeLowRawToDpsCoefficient service function
285 * Inputs:
286 * None
287 * Outputs:
288 * 1 : Result of function, 0 on success, otherwise error code
289 * 2 : float output value
290 */
291void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self);
292
293/**
294 * HID::GetGyroscopeLowCalibrateParam service function
295 * Inputs:
296 * None
297 * Outputs:
298 * 1 : Result of function, 0 on success, otherwise error code
299 * 2~6 (18 bytes) : struct GyroscopeCalibrateParam
300 */
301void GetGyroscopeLowCalibrateParam(Service::Interface* self);
302
225/// Checks for user input updates 303/// Checks for user input updates
226void Update(); 304void Update();
227 305
diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp
index c50f597eb..046e65b11 100644
--- a/src/core/hle/service/hid/hid_spvr.cpp
+++ b/src/core/hle/service/hid/hid_spvr.cpp
@@ -9,16 +9,16 @@ namespace Service {
9namespace HID { 9namespace HID {
10 10
11const Interface::FunctionInfo FunctionTable[] = { 11const Interface::FunctionInfo FunctionTable[] = {
12 {0x000A0000, GetIPCHandles, "GetIPCHandles"}, 12 {0x000A0000, GetIPCHandles, "GetIPCHandles"},
13 {0x000B0000, nullptr, "StartAnalogStickCalibration"}, 13 {0x000B0000, nullptr, "StartAnalogStickCalibration"},
14 {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, 14 {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
15 {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, 15 {0x00110000, EnableAccelerometer, "EnableAccelerometer"},
16 {0x00120000, DisableAccelerometer, "DisableAccelerometer"}, 16 {0x00120000, DisableAccelerometer, "DisableAccelerometer"},
17 {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, 17 {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"},
18 {0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"}, 18 {0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"},
19 {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, 19 {0x00150000, GetGyroscopeLowRawToDpsCoefficient, "GetGyroscopeLowRawToDpsCoefficient"},
20 {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, 20 {0x00160000, GetGyroscopeLowCalibrateParam, "GetGyroscopeLowCalibrateParam"},
21 {0x00170000, GetSoundVolume, "GetSoundVolume"}, 21 {0x00170000, GetSoundVolume, "GetSoundVolume"},
22}; 22};
23 23
24HID_SPVR_Interface::HID_SPVR_Interface() { 24HID_SPVR_Interface::HID_SPVR_Interface() {
diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp
index bbdde2abb..bb157b83d 100644
--- a/src/core/hle/service/hid/hid_user.cpp
+++ b/src/core/hle/service/hid/hid_user.cpp
@@ -9,16 +9,16 @@ namespace Service {
9namespace HID { 9namespace HID {
10 10
11const Interface::FunctionInfo FunctionTable[] = { 11const Interface::FunctionInfo FunctionTable[] = {
12 {0x000A0000, GetIPCHandles, "GetIPCHandles"}, 12 {0x000A0000, GetIPCHandles, "GetIPCHandles"},
13 {0x000B0000, nullptr, "StartAnalogStickCalibration"}, 13 {0x000B0000, nullptr, "StartAnalogStickCalibration"},
14 {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, 14 {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
15 {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, 15 {0x00110000, EnableAccelerometer, "EnableAccelerometer"},
16 {0x00120000, DisableAccelerometer, "DisableAccelerometer"}, 16 {0x00120000, DisableAccelerometer, "DisableAccelerometer"},
17 {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, 17 {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"},
18 {0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"}, 18 {0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"},
19 {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, 19 {0x00150000, GetGyroscopeLowRawToDpsCoefficient, "GetGyroscopeLowRawToDpsCoefficient"},
20 {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, 20 {0x00160000, GetGyroscopeLowCalibrateParam, "GetGyroscopeLowCalibrateParam"},
21 {0x00170000, GetSoundVolume, "GetSoundVolume"}, 21 {0x00170000, GetSoundVolume, "GetSoundVolume"},
22}; 22};
23 23
24HID_U_Interface::HID_U_Interface() { 24HID_U_Interface::HID_U_Interface() {
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 35b648409..7844d2330 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -9,6 +9,7 @@
9#include "core/hle/service/ac_u.h" 9#include "core/hle/service/ac_u.h"
10#include "core/hle/service/act_u.h" 10#include "core/hle/service/act_u.h"
11#include "core/hle/service/csnd_snd.h" 11#include "core/hle/service/csnd_snd.h"
12#include "core/hle/service/dlp_srvr.h"
12#include "core/hle/service/dsp_dsp.h" 13#include "core/hle/service/dsp_dsp.h"
13#include "core/hle/service/err_f.h" 14#include "core/hle/service/err_f.h"
14#include "core/hle/service/gsp_gpu.h" 15#include "core/hle/service/gsp_gpu.h"
@@ -121,6 +122,7 @@ void Init() {
121 AddService(new AC_U::Interface); 122 AddService(new AC_U::Interface);
122 AddService(new ACT_U::Interface); 123 AddService(new ACT_U::Interface);
123 AddService(new CSND_SND::Interface); 124 AddService(new CSND_SND::Interface);
125 AddService(new DLP_SRVR::Interface);
124 AddService(new DSP_DSP::Interface); 126 AddService(new DSP_DSP::Interface);
125 AddService(new GSP_GPU::Interface); 127 AddService(new GSP_GPU::Interface);
126 AddService(new GSP_LCD::Interface); 128 AddService(new GSP_LCD::Interface);
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index b52e52d4a..ff0af8f12 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -5,6 +5,7 @@
5#include <algorithm> 5#include <algorithm>
6#include <cstring> 6#include <cstring>
7#include <unordered_map> 7#include <unordered_map>
8#include <vector>
8 9
9#include "common/assert.h" 10#include "common/assert.h"
10#include "common/bit_field.h" 11#include "common/bit_field.h"
@@ -593,17 +594,13 @@ static void Poll(Service::Interface* self) {
593 594
594 // The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different sizes) 595 // The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different sizes)
595 // so we have to copy the data 596 // so we have to copy the data
596 pollfd* platform_pollfd = new pollfd[nfds]; 597 std::vector<pollfd> platform_pollfd(nfds);
597 for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) 598 std::transform(input_fds, input_fds + nfds, platform_pollfd.begin(), CTRPollFD::ToPlatform);
598 platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]);
599 599
600 int ret = ::poll(platform_pollfd, nfds, timeout); 600 const int ret = ::poll(platform_pollfd.data(), nfds, timeout);
601 601
602 // Now update the output pollfd structure 602 // Now update the output pollfd structure
603 for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) 603 std::transform(platform_pollfd.begin(), platform_pollfd.end(), output_fds, CTRPollFD::FromPlatform);
604 output_fds[current_fds] = CTRPollFD::FromPlatform(platform_pollfd[current_fds]);
605
606 delete[] platform_pollfd;
607 604
608 int result = 0; 605 int result = 0;
609 if (ret == SOCKET_ERROR_VALUE) 606 if (ret == SOCKET_ERROR_VALUE)
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index a7f2715ba..84a4ce5fc 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -74,7 +74,7 @@ enum class ResultStatus {
74 ErrorEncrypted, 74 ErrorEncrypted,
75}; 75};
76 76
77static inline u32 MakeMagic(char a, char b, char c, char d) { 77constexpr u32 MakeMagic(char a, char b, char c, char d) {
78 return a | b << 8 | c << 16 | d << 24; 78 return a | b << 8 | c << 16 | d << 24;
79} 79}
80 80
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 4b59984ad..028b59348 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -75,12 +75,17 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
75 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); 75 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
76 break; 76 break;
77 77
78 case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E):
79 g_state.primitive_assembler.Reconfigure(regs.triangle_topology);
80 break;
81
82 case PICA_REG_INDEX_WORKAROUND(restart_primitive, 0x25F):
83 g_state.primitive_assembler.Reset();
84 break;
85
78 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232): 86 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232):
79 if (regs.vs_default_attributes_setup.index == 15) { 87 g_state.immediate.current_attribute = 0;
80 // Reset immediate primitive state 88 default_attr_counter = 0;
81 g_state.immediate.primitive_assembler.Reconfigure(regs.triangle_topology);
82 g_state.immediate.attribute_id = 0;
83 }
84 break; 89 break;
85 90
86 // Load default vertex input attributes 91 // Load default vertex input attributes
@@ -105,7 +110,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
105 break; 110 break;
106 } 111 }
107 112
108 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index]; 113 Math::Vec4<float24> attribute;
109 114
110 // NOTE: The destination component order indeed is "backwards" 115 // NOTE: The destination component order indeed is "backwards"
111 attribute.w = float24::FromRaw(default_attr_write_buffer[0] >> 8); 116 attribute.w = float24::FromRaw(default_attr_write_buffer[0] >> 8);
@@ -119,26 +124,29 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
119 124
120 // TODO: Verify that this actually modifies the register! 125 // TODO: Verify that this actually modifies the register!
121 if (setup.index < 15) { 126 if (setup.index < 15) {
127 g_state.vs.default_attributes[setup.index] = attribute;
122 setup.index++; 128 setup.index++;
123 } else { 129 } else {
124 // Put each attribute into an immediate input buffer. 130 // Put each attribute into an immediate input buffer.
125 // When all specified immediate attributes are present, the Vertex Shader is invoked and everything is 131 // When all specified immediate attributes are present, the Vertex Shader is invoked and everything is
126 // sent to the primitive assembler. 132 // sent to the primitive assembler.
127 133
128 auto& immediate_input = g_state.immediate.input; 134 auto& immediate_input = g_state.immediate.input_vertex;
129 auto& immediate_attribute_id = g_state.immediate.attribute_id; 135 auto& immediate_attribute_id = g_state.immediate.current_attribute;
130 const auto& attribute_config = regs.vertex_attributes;
131 136
132 immediate_input.attr[immediate_attribute_id++] = attribute; 137 immediate_input.attr[immediate_attribute_id++] = attribute;
133 138
134 if (immediate_attribute_id >= attribute_config.GetNumTotalAttributes()) { 139 if (immediate_attribute_id >= regs.vs.num_input_attributes+1) {
135 immediate_attribute_id = 0; 140 immediate_attribute_id = 0;
136 141
137 Shader::UnitState<false> shader_unit; 142 Shader::UnitState<false> shader_unit;
138 Shader::Setup(shader_unit); 143 Shader::Setup(shader_unit);
139 144
145 if (g_debug_context)
146 g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, static_cast<void*>(&immediate_input));
147
140 // Send to vertex shader 148 // Send to vertex shader
141 Shader::OutputVertex output = Shader::Run(shader_unit, immediate_input, attribute_config.GetNumTotalAttributes()); 149 Shader::OutputVertex output = Shader::Run(shader_unit, immediate_input, regs.vs.num_input_attributes+1);
142 150
143 // Send to renderer 151 // Send to renderer
144 using Pica::Shader::OutputVertex; 152 using Pica::Shader::OutputVertex;
@@ -146,7 +154,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
146 VideoCore::g_renderer->Rasterizer()->AddTriangle(v0, v1, v2); 154 VideoCore::g_renderer->Rasterizer()->AddTriangle(v0, v1, v2);
147 }; 155 };
148 156
149 g_state.immediate.primitive_assembler.SubmitVertex(output, AddTriangle); 157 g_state.primitive_assembler.SubmitVertex(output, AddTriangle);
150 } 158 }
151 } 159 }
152 } 160 }
@@ -154,9 +162,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
154 } 162 }
155 163
156 case PICA_REG_INDEX(gpu_mode): 164 case PICA_REG_INDEX(gpu_mode):
157 if (regs.gpu_mode == Regs::GPUMode::Configuring && regs.vs_default_attributes_setup.index == 15) { 165 if (regs.gpu_mode == Regs::GPUMode::Configuring) {
158 // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring 166 // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring
159 VideoCore::g_renderer->Rasterizer()->DrawTriangles(); 167 VideoCore::g_renderer->Rasterizer()->DrawTriangles();
168
169 if (g_debug_context) {
170 g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
171 }
160 } 172 }
161 break; 173 break;
162 174
@@ -241,7 +253,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
241 DebugUtils::GeometryDumper geometry_dumper; 253 DebugUtils::GeometryDumper geometry_dumper;
242 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value()); 254 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value());
243#endif 255#endif
244 PrimitiveAssembler<Shader::OutputVertex> primitive_assembler(regs.triangle_topology.Value()); 256 PrimitiveAssembler<Shader::OutputVertex>& primitive_assembler = g_state.primitive_assembler;
245 257
246 if (g_debug_context) { 258 if (g_debug_context) {
247 for (int i = 0; i < 3; ++i) { 259 for (int i = 0; i < 3; ++i) {
@@ -412,16 +424,10 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
412 range.second, range.first); 424 range.second, range.first);
413 } 425 }
414 426
415 VideoCore::g_renderer->Rasterizer()->DrawTriangles();
416
417#if PICA_DUMP_GEOMETRY 427#if PICA_DUMP_GEOMETRY
418 geometry_dumper.Dump(); 428 geometry_dumper.Dump();
419#endif 429#endif
420 430
421 if (g_debug_context) {
422 g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
423 }
424
425 break; 431 break;
426 } 432 }
427 433
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
index 32ad72674..ccbaf071b 100644
--- a/src/video_core/pica.cpp
+++ b/src/video_core/pica.cpp
@@ -493,12 +493,25 @@ std::string Regs::GetCommandName(int index) {
493} 493}
494 494
495void Init() { 495void Init() {
496 g_state.Reset();
496} 497}
497 498
498void Shutdown() { 499void Shutdown() {
499 Shader::Shutdown(); 500 Shader::Shutdown();
501}
502
503template <typename T>
504void Zero(T& o) {
505 memset(&o, 0, sizeof(o));
506}
500 507
501 memset(&g_state, 0, sizeof(State)); 508void State::Reset() {
509 Zero(regs);
510 Zero(vs);
511 Zero(gs);
512 Zero(cmd_list);
513 Zero(immediate);
514 primitive_assembler.Reconfigure(Regs::TriangleTopology::List);
502} 515}
503 516
504} 517}
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 337cff8ce..16f9e4006 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -71,7 +71,7 @@ struct Regs {
71 BitField<0, 24, u32> viewport_depth_range; // float24 71 BitField<0, 24, u32> viewport_depth_range; // float24
72 BitField<0, 24, u32> viewport_depth_far_plane; // float24 72 BitField<0, 24, u32> viewport_depth_far_plane; // float24
73 73
74 INSERT_PADDING_WORDS(0x1); 74 BitField<0, 3, u32> vs_output_total;
75 75
76 union VSOutputAttributes { 76 union VSOutputAttributes {
77 // Maps components of output vertex attributes to semantics 77 // Maps components of output vertex attributes to semantics
@@ -1123,7 +1123,12 @@ struct Regs {
1123 BitField<24, 8, u32> w; 1123 BitField<24, 8, u32> w;
1124 } int_uniforms[4]; 1124 } int_uniforms[4];
1125 1125
1126 INSERT_PADDING_WORDS(0x5); 1126 INSERT_PADDING_WORDS(0x4);
1127
1128 union {
1129 // Number of input attributes to shader unit - 1
1130 BitField<0, 4, u32> num_input_attributes;
1131 };
1127 1132
1128 // Offset to shader program entry point (in words) 1133 // Offset to shader program entry point (in words)
1129 BitField<0, 16, u32> main_offset; 1134 BitField<0, 16, u32> main_offset;
@@ -1157,8 +1162,10 @@ struct Regs {
1157 } 1162 }
1158 } input_register_map; 1163 } input_register_map;
1159 1164
1160 // OUTMAP_MASK, 0x28E, CODETRANSFER_END 1165 BitField<0, 16, u32> output_mask;
1161 INSERT_PADDING_WORDS(0x3); 1166
1167 // 0x28E, CODETRANSFER_END
1168 INSERT_PADDING_WORDS(0x2);
1162 1169
1163 struct { 1170 struct {
1164 enum Format : u32 1171 enum Format : u32
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index c7616bc55..323290054 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -12,6 +12,8 @@ namespace Pica {
12 12
13/// Struct used to describe current Pica state 13/// Struct used to describe current Pica state
14struct State { 14struct State {
15 void Reset();
16
15 /// Pica registers 17 /// Pica registers
16 Regs regs; 18 Regs regs;
17 19
@@ -46,13 +48,14 @@ struct State {
46 48
47 /// Struct used to describe immediate mode rendering state 49 /// Struct used to describe immediate mode rendering state
48 struct ImmediateModeState { 50 struct ImmediateModeState {
49 Shader::InputVertex input; 51 // Used to buffer partial vertices for immediate-mode rendering.
50 // This is constructed with a dummy triangle topology 52 Shader::InputVertex input_vertex;
51 PrimitiveAssembler<Shader::OutputVertex> primitive_assembler; 53 // Index of the next attribute to be loaded into `input_vertex`.
52 int attribute_id = 0; 54 int current_attribute = 0;
53
54 ImmediateModeState() : primitive_assembler(Regs::TriangleTopology::List) {}
55 } immediate; 55 } immediate;
56
57 // This is constructed with a dummy triangle topology
58 PrimitiveAssembler<Shader::OutputVertex> primitive_assembler;
56}; 59};
57 60
58extern State g_state; ///< Current Pica state 61extern State g_state; ///< Current Pica state
diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h
index cc6e5fde5..9396b4c85 100644
--- a/src/video_core/primitive_assembly.h
+++ b/src/video_core/primitive_assembly.h
@@ -20,7 +20,7 @@ struct PrimitiveAssembler {
20 VertexType& v1, 20 VertexType& v1,
21 VertexType& v2)>; 21 VertexType& v2)>;
22 22
23 PrimitiveAssembler(Regs::TriangleTopology topology); 23 PrimitiveAssembler(Regs::TriangleTopology topology = Regs::TriangleTopology::List);
24 24
25 /* 25 /*
26 * Queues a vertex, builds primitives from the vertex queue according to the given 26 * Queues a vertex, builds primitives from the vertex queue according to the given
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 5d91aac00..cc6b3aeab 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -189,6 +189,9 @@ void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0,
189} 189}
190 190
191void RasterizerOpenGL::DrawTriangles() { 191void RasterizerOpenGL::DrawTriangles() {
192 if (vertex_batch.empty())
193 return;
194
192 SyncFramebuffer(); 195 SyncFramebuffer();
193 SyncDrawState(); 196 SyncDrawState();
194 197
@@ -804,6 +807,9 @@ void RasterizerOpenGL::SyncFramebuffer() {
804 807
805 ReloadDepthBuffer(); 808 ReloadDepthBuffer();
806 } 809 }
810
811 ASSERT_MSG(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
812 "OpenGL rasterizer framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER));
807} 813}
808 814
809void RasterizerOpenGL::SyncCullMode() { 815void RasterizerOpenGL::SyncCullMode() {
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index 3d6c4e9e5..fd3617d77 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -22,7 +22,7 @@ inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
22 }; 22 };
23 23
24 // Range check table for input 24 // Range check table for input
25 if (mode >= ARRAY_SIZE(filter_mode_table)) { 25 if (static_cast<size_t>(mode) >= ARRAY_SIZE(filter_mode_table)) {
26 LOG_CRITICAL(Render_OpenGL, "Unknown texture filtering mode %d", mode); 26 LOG_CRITICAL(Render_OpenGL, "Unknown texture filtering mode %d", mode);
27 UNREACHABLE(); 27 UNREACHABLE();
28 28
@@ -51,7 +51,7 @@ inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
51 }; 51 };
52 52
53 // Range check table for input 53 // Range check table for input
54 if (mode >= ARRAY_SIZE(wrap_mode_table)) { 54 if (static_cast<size_t>(mode) >= ARRAY_SIZE(wrap_mode_table)) {
55 LOG_CRITICAL(Render_OpenGL, "Unknown texture wrap mode %d", mode); 55 LOG_CRITICAL(Render_OpenGL, "Unknown texture wrap mode %d", mode);
56 UNREACHABLE(); 56 UNREACHABLE();
57 57
@@ -91,7 +91,7 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
91 }; 91 };
92 92
93 // Range check table for input 93 // Range check table for input
94 if ((unsigned)factor >= ARRAY_SIZE(blend_func_table)) { 94 if (static_cast<size_t>(factor) >= ARRAY_SIZE(blend_func_table)) {
95 LOG_CRITICAL(Render_OpenGL, "Unknown blend factor %d", factor); 95 LOG_CRITICAL(Render_OpenGL, "Unknown blend factor %d", factor);
96 UNREACHABLE(); 96 UNREACHABLE();
97 97
@@ -122,7 +122,7 @@ inline GLenum LogicOp(Pica::Regs::LogicOp op) {
122 }; 122 };
123 123
124 // Range check table for input 124 // Range check table for input
125 if ((unsigned)op >= ARRAY_SIZE(logic_op_table)) { 125 if (static_cast<size_t>(op) >= ARRAY_SIZE(logic_op_table)) {
126 LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", op); 126 LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", op);
127 UNREACHABLE(); 127 UNREACHABLE();
128 128
@@ -145,7 +145,7 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
145 }; 145 };
146 146
147 // Range check table for input 147 // Range check table for input
148 if ((unsigned)func >= ARRAY_SIZE(compare_func_table)) { 148 if (static_cast<size_t>(func) >= ARRAY_SIZE(compare_func_table)) {
149 LOG_CRITICAL(Render_OpenGL, "Unknown compare function %d", func); 149 LOG_CRITICAL(Render_OpenGL, "Unknown compare function %d", func);
150 UNREACHABLE(); 150 UNREACHABLE();
151 151
@@ -168,7 +168,7 @@ inline GLenum StencilOp(Pica::Regs::StencilAction action) {
168 }; 168 };
169 169
170 // Range check table for input 170 // Range check table for input
171 if ((unsigned)action >= ARRAY_SIZE(stencil_op_table)) { 171 if (static_cast<size_t>(action) >= ARRAY_SIZE(stencil_op_table)) {
172 LOG_CRITICAL(Render_OpenGL, "Unknown stencil op %d", action); 172 LOG_CRITICAL(Render_OpenGL, "Unknown stencil op %d", action);
173 UNREACHABLE(); 173 UNREACHABLE();
174 174
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 045e7d5bd..78d295c76 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -120,15 +120,23 @@ OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attr
120 OutputVertex ret; 120 OutputVertex ret;
121 // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to 121 // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
122 // figure out what those circumstances are and enable the remaining outputs then. 122 // figure out what those circumstances are and enable the remaining outputs then.
123 for (int i = 0; i < 7; ++i) { 123 unsigned index = 0;
124 const auto& output_register_map = g_state.regs.vs_output_attributes[i]; // TODO: Don't hardcode VS here 124 for (unsigned i = 0; i < 7; ++i) {
125
126 if (index >= g_state.regs.vs_output_total)
127 break;
128
129 if ((g_state.regs.vs.output_mask & (1 << i)) == 0)
130 continue;
131
132 const auto& output_register_map = g_state.regs.vs_output_attributes[index]; // TODO: Don't hardcode VS here
125 133
126 u32 semantics[4] = { 134 u32 semantics[4] = {
127 output_register_map.map_x, output_register_map.map_y, 135 output_register_map.map_x, output_register_map.map_y,
128 output_register_map.map_z, output_register_map.map_w 136 output_register_map.map_z, output_register_map.map_w
129 }; 137 };
130 138
131 for (int comp = 0; comp < 4; ++comp) { 139 for (unsigned comp = 0; comp < 4; ++comp) {
132 float24* out = ((float24*)&ret) + semantics[comp]; 140 float24* out = ((float24*)&ret) + semantics[comp];
133 if (semantics[comp] != Regs::VSOutputAttributes::INVALID) { 141 if (semantics[comp] != Regs::VSOutputAttributes::INVALID) {
134 *out = state.registers.output[i][comp]; 142 *out = state.registers.output[i][comp];
@@ -138,10 +146,12 @@ OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attr
138 memset(out, 0, sizeof(*out)); 146 memset(out, 0, sizeof(*out));
139 } 147 }
140 } 148 }
149
150 index++;
141 } 151 }
142 152
143 // The hardware takes the absolute and saturates vertex colors like this, *before* doing interpolation 153 // The hardware takes the absolute and saturates vertex colors like this, *before* doing interpolation
144 for (int i = 0; i < 4; ++i) { 154 for (unsigned i = 0; i < 4; ++i) {
145 ret.color[i] = float24::FromFloat32( 155 ret.color[i] = float24::FromFloat32(
146 std::fmin(std::fabs(ret.color[i].ToFloat32()), 1.0f)); 156 std::fmin(std::fabs(ret.color[i].ToFloat32()), 1.0f));
147 } 157 }