summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/renderer/command/resample/upsample.cpp97
-rw-r--r--src/common/settings.cpp12
-rw-r--r--src/common/settings.h13
-rw-r--r--src/core/core_timing.cpp42
-rw-r--r--src/core/core_timing.h9
-rw-r--r--src/core/hle/kernel/k_hardware_timer.cpp6
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp8
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.ui15
9 files changed, 106 insertions, 98 deletions
diff --git a/src/audio_core/renderer/command/resample/upsample.cpp b/src/audio_core/renderer/command/resample/upsample.cpp
index 6c3ff31f7..5f7db12ca 100644
--- a/src/audio_core/renderer/command/resample/upsample.cpp
+++ b/src/audio_core/renderer/command/resample/upsample.cpp
@@ -20,25 +20,25 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
20 const u32 target_sample_count, const u32 source_sample_count, 20 const u32 target_sample_count, const u32 source_sample_count,
21 UpsamplerState* state) { 21 UpsamplerState* state) {
22 constexpr u32 WindowSize = 10; 22 constexpr u32 WindowSize = 10;
23 constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow1{ 23 constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc1{
24 51.93359375f, -18.80078125f, 9.73046875f, -5.33203125f, 2.84375f, 24 0.95376587f, -0.12872314f, 0.060028076f, -0.032470703f, 0.017669678f,
25 -1.41015625f, 0.62109375f, -0.2265625f, 0.0625f, -0.00390625f, 25 -0.009124756f, 0.004272461f, -0.001739502f, 0.000579834f, -0.000091552734f,
26 }; 26 };
27 constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow2{ 27 constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc2{
28 105.35546875f, -24.52734375f, 11.9609375f, -6.515625f, 3.52734375f, 28 0.8230896f, -0.19161987f, 0.093444824f, -0.05090332f, 0.027557373f,
29 -1.796875f, 0.828125f, -0.32421875f, 0.1015625f, -0.015625f, 29 -0.014038086f, 0.0064697266f, -0.002532959f, 0.00079345703f, -0.00012207031f,
30 }; 30 };
31 constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow3{ 31 constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc3{
32 122.08203125f, -16.47656250f, 7.68359375f, -4.15625000f, 2.26171875f, 32 0.6298828f, -0.19274902f, 0.09725952f, -0.05319214f, 0.028625488f,
33 -1.16796875f, 0.54687500f, -0.22265625f, 0.07421875f, -0.01171875f, 33 -0.014373779f, 0.006500244f, -0.0024719238f, 0.0007324219f, -0.000091552734f,
34 }; 34 };
35 constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow4{ 35 constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc4{
36 23.73437500f, -9.62109375f, 5.07812500f, -2.78125000f, 1.46875000f, 36 0.4057312f, -0.1468811f, 0.07601929f, -0.041656494f, 0.022216797f,
37 -0.71484375f, 0.30859375f, -0.10546875f, 0.02734375f, 0.00000000f, 37 -0.011016846f, 0.004852295f, -0.0017700195f, 0.00048828125f, -0.000030517578f,
38 }; 38 };
39 constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow5{ 39 constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc5{
40 80.62500000f, -24.67187500f, 12.44921875f, -6.80859375f, 3.66406250f, 40 0.1854248f, -0.075164795f, 0.03967285f, -0.021728516f, 0.011474609f,
41 -1.83984375f, 0.83203125f, -0.31640625f, 0.09375000f, -0.01171875f, 41 -0.005584717f, 0.0024108887f, -0.0008239746f, 0.00021362305f, 0.0f,
42 }; 42 };
43 43
44 if (!state->initialized) { 44 if (!state->initialized) {
@@ -91,52 +91,31 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
91 static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize); 91 static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize);
92 }; 92 };
93 93
94 auto calculate_sample = [&state](std::span<const Common::FixedPoint<24, 8>> coeffs1, 94 auto calculate_sample = [&state](std::span<const Common::FixedPoint<17, 15>> coeffs1,
95 std::span<const Common::FixedPoint<24, 8>> coeffs2) -> s32 { 95 std::span<const Common::FixedPoint<17, 15>> coeffs2) -> s32 {
96 auto output_index{state->history_output_index}; 96 auto output_index{state->history_output_index};
97 auto start_pos{output_index - state->history_start_index + 1U}; 97 u64 result{0};
98 auto end_pos{10U};
99 98
100 if (start_pos < 10) { 99 for (u32 coeff_index = 0; coeff_index < 10; coeff_index++) {
101 end_pos = start_pos; 100 result += static_cast<u64>(state->history[output_index].to_raw()) *
102 } 101 coeffs1[coeff_index].to_raw();
103
104 u64 prev_contrib{0};
105 u32 coeff_index{0};
106 for (; coeff_index < end_pos; coeff_index++, output_index--) {
107 prev_contrib += static_cast<u64>(state->history[output_index].to_raw()) *
108 coeffs1[coeff_index].to_raw();
109 }
110 102
111 auto end_index{state->history_end_index}; 103 output_index = output_index == state->history_start_index ? state->history_end_index
112 for (; start_pos < 9; start_pos++, coeff_index++, end_index--) { 104 : output_index - 1;
113 prev_contrib += static_cast<u64>(state->history[end_index].to_raw()) *
114 coeffs1[coeff_index].to_raw();
115 } 105 }
116 106
117 output_index = 107 output_index =
118 static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize); 108 static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize);
119 start_pos = state->history_end_index - output_index + 1U;
120 end_pos = 10U;
121 109
122 if (start_pos < 10) { 110 for (u32 coeff_index = 0; coeff_index < 10; coeff_index++) {
123 end_pos = start_pos; 111 result += static_cast<u64>(state->history[output_index].to_raw()) *
124 } 112 coeffs2[coeff_index].to_raw();
125
126 u64 next_contrib{0};
127 coeff_index = 0;
128 for (; coeff_index < end_pos; coeff_index++, output_index++) {
129 next_contrib += static_cast<u64>(state->history[output_index].to_raw()) *
130 coeffs2[coeff_index].to_raw();
131 }
132 113
133 auto start_index{state->history_start_index}; 114 output_index = output_index == state->history_end_index ? state->history_start_index
134 for (; start_pos < 9; start_pos++, start_index++, coeff_index++) { 115 : output_index + 1;
135 next_contrib += static_cast<u64>(state->history[start_index].to_raw()) *
136 coeffs2[coeff_index].to_raw();
137 } 116 }
138 117
139 return static_cast<s32>(((prev_contrib >> 15) + (next_contrib >> 15)) >> 8); 118 return static_cast<s32>(result >> (8 + 15));
140 }; 119 };
141 120
142 switch (state->ratio.to_int_floor()) { 121 switch (state->ratio.to_int_floor()) {
@@ -150,23 +129,23 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
150 break; 129 break;
151 130
152 case 1: 131 case 1:
153 output[write_index] = calculate_sample(SincWindow3, SincWindow4); 132 output[write_index] = calculate_sample(WindowedSinc1, WindowedSinc5);
154 break; 133 break;
155 134
156 case 2: 135 case 2:
157 output[write_index] = calculate_sample(SincWindow2, SincWindow1); 136 output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
158 break; 137 break;
159 138
160 case 3: 139 case 3:
161 output[write_index] = calculate_sample(SincWindow5, SincWindow5); 140 output[write_index] = calculate_sample(WindowedSinc3, WindowedSinc3);
162 break; 141 break;
163 142
164 case 4: 143 case 4:
165 output[write_index] = calculate_sample(SincWindow1, SincWindow2); 144 output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
166 break; 145 break;
167 146
168 case 5: 147 case 5:
169 output[write_index] = calculate_sample(SincWindow4, SincWindow3); 148 output[write_index] = calculate_sample(WindowedSinc5, WindowedSinc1);
170 break; 149 break;
171 } 150 }
172 state->sample_index = static_cast<u8>((state->sample_index + 1) % 6); 151 state->sample_index = static_cast<u8>((state->sample_index + 1) % 6);
@@ -183,11 +162,11 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
183 break; 162 break;
184 163
185 case 1: 164 case 1:
186 output[write_index] = calculate_sample(SincWindow2, SincWindow1); 165 output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
187 break; 166 break;
188 167
189 case 2: 168 case 2:
190 output[write_index] = calculate_sample(SincWindow1, SincWindow2); 169 output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
191 break; 170 break;
192 } 171 }
193 state->sample_index = static_cast<u8>((state->sample_index + 1) % 3); 172 state->sample_index = static_cast<u8>((state->sample_index + 1) % 3);
@@ -204,12 +183,12 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
204 break; 183 break;
205 184
206 case 1: 185 case 1:
207 output[write_index] = calculate_sample(SincWindow1, SincWindow2); 186 output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
208 break; 187 break;
209 188
210 case 2: 189 case 2:
211 increment(); 190 increment();
212 output[write_index] = calculate_sample(SincWindow2, SincWindow1); 191 output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
213 break; 192 break;
214 } 193 }
215 state->sample_index = static_cast<u8>((state->sample_index + 1) % 3); 194 state->sample_index = static_cast<u8>((state->sample_index + 1) % 3);
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 1638b79f5..b1a2aa8b2 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -129,6 +129,10 @@ void UpdateRescalingInfo() {
129 info.up_scale = 1; 129 info.up_scale = 1;
130 info.down_shift = 0; 130 info.down_shift = 0;
131 break; 131 break;
132 case ResolutionSetup::Res3_2X:
133 info.up_scale = 3;
134 info.down_shift = 1;
135 break;
132 case ResolutionSetup::Res2X: 136 case ResolutionSetup::Res2X:
133 info.up_scale = 2; 137 info.up_scale = 2;
134 info.down_shift = 0; 138 info.down_shift = 0;
@@ -149,6 +153,14 @@ void UpdateRescalingInfo() {
149 info.up_scale = 6; 153 info.up_scale = 6;
150 info.down_shift = 0; 154 info.down_shift = 0;
151 break; 155 break;
156 case ResolutionSetup::Res7X:
157 info.up_scale = 7;
158 info.down_shift = 0;
159 break;
160 case ResolutionSetup::Res8X:
161 info.up_scale = 8;
162 info.down_shift = 0;
163 break;
152 default: 164 default:
153 ASSERT(false); 165 ASSERT(false);
154 info.up_scale = 1; 166 info.up_scale = 1;
diff --git a/src/common/settings.h b/src/common/settings.h
index a457e3f23..80b2eeabc 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -56,11 +56,14 @@ enum class ResolutionSetup : u32 {
56 Res1_2X = 0, 56 Res1_2X = 0,
57 Res3_4X = 1, 57 Res3_4X = 1,
58 Res1X = 2, 58 Res1X = 2,
59 Res2X = 3, 59 Res3_2X = 3,
60 Res3X = 4, 60 Res2X = 4,
61 Res4X = 5, 61 Res3X = 5,
62 Res5X = 6, 62 Res4X = 6,
63 Res6X = 7, 63 Res5X = 7,
64 Res6X = 8,
65 Res7X = 9,
66 Res8X = 10,
64}; 67};
65 68
66enum class ScalingFilter : u32 { 69enum class ScalingFilter : u32 {
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 0e7b5f943..6bac6722f 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -142,16 +142,24 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
142} 142}
143 143
144void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, 144void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
145 std::uintptr_t user_data) { 145 std::uintptr_t user_data, bool wait) {
146 std::scoped_lock scope{basic_lock}; 146 {
147 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { 147 std::scoped_lock lk{basic_lock};
148 return e.type.lock().get() == event_type.get() && e.user_data == user_data; 148 const auto itr =
149 }); 149 std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
150 150 return e.type.lock().get() == event_type.get() && e.user_data == user_data;
151 // Removing random items breaks the invariant so we have to re-establish it. 151 });
152 if (itr != event_queue.end()) { 152
153 event_queue.erase(itr, event_queue.end()); 153 // Removing random items breaks the invariant so we have to re-establish it.
154 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 154 if (itr != event_queue.end()) {
155 event_queue.erase(itr, event_queue.end());
156 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
157 }
158 }
159
160 // Force any in-progress events to finish
161 if (wait) {
162 std::scoped_lock lk{advance_lock};
155 } 163 }
156} 164}
157 165
@@ -190,20 +198,6 @@ u64 CoreTiming::GetClockTicks() const {
190 return CpuCyclesToClockCycles(ticks); 198 return CpuCyclesToClockCycles(ticks);
191} 199}
192 200
193void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
194 std::scoped_lock lock{basic_lock};
195
196 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
197 return e.type.lock().get() == event_type.get();
198 });
199
200 // Removing random items breaks the invariant so we have to re-establish it.
201 if (itr != event_queue.end()) {
202 event_queue.erase(itr, event_queue.end());
203 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
204 }
205}
206
207std::optional<s64> CoreTiming::Advance() { 201std::optional<s64> CoreTiming::Advance() {
208 std::scoped_lock lock{advance_lock, basic_lock}; 202 std::scoped_lock lock{advance_lock, basic_lock};
209 global_timer = GetGlobalTimeNs().count(); 203 global_timer = GetGlobalTimeNs().count();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index b5925193c..da366637b 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -98,10 +98,13 @@ public:
98 const std::shared_ptr<EventType>& event_type, 98 const std::shared_ptr<EventType>& event_type,
99 std::uintptr_t user_data = 0, bool absolute_time = false); 99 std::uintptr_t user_data = 0, bool absolute_time = false);
100 100
101 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data); 101 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data,
102 bool wait = true);
102 103
103 /// We only permit one event of each type in the queue at a time. 104 void UnscheduleEventWithoutWait(const std::shared_ptr<EventType>& event_type,
104 void RemoveEvent(const std::shared_ptr<EventType>& event_type); 105 std::uintptr_t user_data) {
106 UnscheduleEvent(event_type, user_data, false);
107 }
105 108
106 void AddTicks(u64 ticks_to_add); 109 void AddTicks(u64 ticks_to_add);
107 110
diff --git a/src/core/hle/kernel/k_hardware_timer.cpp b/src/core/hle/kernel/k_hardware_timer.cpp
index 6bba79ea0..4dcd53821 100644
--- a/src/core/hle/kernel/k_hardware_timer.cpp
+++ b/src/core/hle/kernel/k_hardware_timer.cpp
@@ -18,7 +18,8 @@ void KHardwareTimer::Initialize() {
18} 18}
19 19
20void KHardwareTimer::Finalize() { 20void KHardwareTimer::Finalize() {
21 this->DisableInterrupt(); 21 m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
22 m_wakeup_time = std::numeric_limits<s64>::max();
22 m_event_type.reset(); 23 m_event_type.reset();
23} 24}
24 25
@@ -59,7 +60,8 @@ void KHardwareTimer::EnableInterrupt(s64 wakeup_time) {
59} 60}
60 61
61void KHardwareTimer::DisableInterrupt() { 62void KHardwareTimer::DisableInterrupt() {
62 m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this)); 63 m_kernel.System().CoreTiming().UnscheduleEventWithoutWait(m_event_type,
64 reinterpret_cast<uintptr_t>(this));
63 m_wakeup_time = std::numeric_limits<s64>::max(); 65 m_wakeup_time = std::numeric_limits<s64>::max();
64} 66}
65 67
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index d1cbadde4..f4416f5b2 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -312,8 +312,6 @@ void NVFlinger::Compose() {
312} 312}
313 313
314s64 NVFlinger::GetNextTicks() const { 314s64 NVFlinger::GetNextTicks() const {
315 static constexpr s64 max_hertz = 120LL;
316
317 const auto& settings = Settings::values; 315 const auto& settings = Settings::values;
318 auto speed_scale = 1.f; 316 auto speed_scale = 1.f;
319 if (settings.use_multi_core.GetValue()) { 317 if (settings.use_multi_core.GetValue()) {
@@ -327,9 +325,11 @@ s64 NVFlinger::GetNextTicks() const {
327 } 325 }
328 } 326 }
329 327
330 const auto next_ticks = ((1000000000 * (1LL << swap_interval)) / max_hertz); 328 // As an extension, treat nonpositive swap interval as framerate multiplier.
329 const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval)
330 : 60.f / static_cast<f32>(swap_interval);
331 331
332 return static_cast<s64>(speed_scale * static_cast<float>(next_ticks)); 332 return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
333} 333}
334 334
335} // namespace Service::NVFlinger 335} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 9b22397db..3828cf272 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -133,7 +133,7 @@ private:
133 /// layers. 133 /// layers.
134 u32 next_buffer_queue_id = 1; 134 u32 next_buffer_queue_id = 1;
135 135
136 u32 swap_interval = 1; 136 s32 swap_interval = 1;
137 137
138 /// Event that handles screen composition. 138 /// Event that handles screen composition.
139 std::shared_ptr<Core::Timing::EventType> multi_composition_event; 139 std::shared_ptr<Core::Timing::EventType> multi_composition_event;
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index aa02cc63c..bb9910a53 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -366,6 +366,11 @@
366 </item> 366 </item>
367 <item> 367 <item>
368 <property name="text"> 368 <property name="text">
369 <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string>
370 </property>
371 </item>
372 <item>
373 <property name="text">
369 <string>2X (1440p/2160p)</string> 374 <string>2X (1440p/2160p)</string>
370 </property> 375 </property>
371 </item> 376 </item>
@@ -389,6 +394,16 @@
389 <string>6X (4320p/6480p)</string> 394 <string>6X (4320p/6480p)</string>
390 </property> 395 </property>
391 </item> 396 </item>
397 <item>
398 <property name="text">
399 <string>7X (5040p/7560p)</string>
400 </property>
401 </item>
402 <item>
403 <property name="text">
404 <string>8X (5760p/8640p)</string>
405 </property>
406 </item>
392 </widget> 407 </widget>
393 </item> 408 </item>
394 </layout> 409 </layout>