summaryrefslogtreecommitdiffstats
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/video_core/engines/maxwell_3d.cpp2
-rw-r--r--src/yuzu/configuration/configure_graphics.ui15
10 files changed, 107 insertions, 99 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,
const u32 target_sample_count, const u32 source_sample_count,
UpsamplerState* state) {
constexpr u32 WindowSize = 10;
- constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow1{
- 51.93359375f, -18.80078125f, 9.73046875f, -5.33203125f, 2.84375f,
- -1.41015625f, 0.62109375f, -0.2265625f, 0.0625f, -0.00390625f,
+ constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc1{
+ 0.95376587f, -0.12872314f, 0.060028076f, -0.032470703f, 0.017669678f,
+ -0.009124756f, 0.004272461f, -0.001739502f, 0.000579834f, -0.000091552734f,
};
- constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow2{
- 105.35546875f, -24.52734375f, 11.9609375f, -6.515625f, 3.52734375f,
- -1.796875f, 0.828125f, -0.32421875f, 0.1015625f, -0.015625f,
+ constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc2{
+ 0.8230896f, -0.19161987f, 0.093444824f, -0.05090332f, 0.027557373f,
+ -0.014038086f, 0.0064697266f, -0.002532959f, 0.00079345703f, -0.00012207031f,
};
- constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow3{
- 122.08203125f, -16.47656250f, 7.68359375f, -4.15625000f, 2.26171875f,
- -1.16796875f, 0.54687500f, -0.22265625f, 0.07421875f, -0.01171875f,
+ constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc3{
+ 0.6298828f, -0.19274902f, 0.09725952f, -0.05319214f, 0.028625488f,
+ -0.014373779f, 0.006500244f, -0.0024719238f, 0.0007324219f, -0.000091552734f,
};
- constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow4{
- 23.73437500f, -9.62109375f, 5.07812500f, -2.78125000f, 1.46875000f,
- -0.71484375f, 0.30859375f, -0.10546875f, 0.02734375f, 0.00000000f,
+ constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc4{
+ 0.4057312f, -0.1468811f, 0.07601929f, -0.041656494f, 0.022216797f,
+ -0.011016846f, 0.004852295f, -0.0017700195f, 0.00048828125f, -0.000030517578f,
};
- constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow5{
- 80.62500000f, -24.67187500f, 12.44921875f, -6.80859375f, 3.66406250f,
- -1.83984375f, 0.83203125f, -0.31640625f, 0.09375000f, -0.01171875f,
+ constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc5{
+ 0.1854248f, -0.075164795f, 0.03967285f, -0.021728516f, 0.011474609f,
+ -0.005584717f, 0.0024108887f, -0.0008239746f, 0.00021362305f, 0.0f,
};
if (!state->initialized) {
@@ -91,52 +91,31 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize);
};
- auto calculate_sample = [&state](std::span<const Common::FixedPoint<24, 8>> coeffs1,
- std::span<const Common::FixedPoint<24, 8>> coeffs2) -> s32 {
+ auto calculate_sample = [&state](std::span<const Common::FixedPoint<17, 15>> coeffs1,
+ std::span<const Common::FixedPoint<17, 15>> coeffs2) -> s32 {
auto output_index{state->history_output_index};
- auto start_pos{output_index - state->history_start_index + 1U};
- auto end_pos{10U};
+ u64 result{0};
- if (start_pos < 10) {
- end_pos = start_pos;
- }
-
- u64 prev_contrib{0};
- u32 coeff_index{0};
- for (; coeff_index < end_pos; coeff_index++, output_index--) {
- prev_contrib += static_cast<u64>(state->history[output_index].to_raw()) *
- coeffs1[coeff_index].to_raw();
- }
+ for (u32 coeff_index = 0; coeff_index < 10; coeff_index++) {
+ result += static_cast<u64>(state->history[output_index].to_raw()) *
+ coeffs1[coeff_index].to_raw();
- auto end_index{state->history_end_index};
- for (; start_pos < 9; start_pos++, coeff_index++, end_index--) {
- prev_contrib += static_cast<u64>(state->history[end_index].to_raw()) *
- coeffs1[coeff_index].to_raw();
+ output_index = output_index == state->history_start_index ? state->history_end_index
+ : output_index - 1;
}
output_index =
static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize);
- start_pos = state->history_end_index - output_index + 1U;
- end_pos = 10U;
- if (start_pos < 10) {
- end_pos = start_pos;
- }
-
- u64 next_contrib{0};
- coeff_index = 0;
- for (; coeff_index < end_pos; coeff_index++, output_index++) {
- next_contrib += static_cast<u64>(state->history[output_index].to_raw()) *
- coeffs2[coeff_index].to_raw();
- }
+ for (u32 coeff_index = 0; coeff_index < 10; coeff_index++) {
+ result += static_cast<u64>(state->history[output_index].to_raw()) *
+ coeffs2[coeff_index].to_raw();
- auto start_index{state->history_start_index};
- for (; start_pos < 9; start_pos++, start_index++, coeff_index++) {
- next_contrib += static_cast<u64>(state->history[start_index].to_raw()) *
- coeffs2[coeff_index].to_raw();
+ output_index = output_index == state->history_end_index ? state->history_start_index
+ : output_index + 1;
}
- return static_cast<s32>(((prev_contrib >> 15) + (next_contrib >> 15)) >> 8);
+ return static_cast<s32>(result >> (8 + 15));
};
switch (state->ratio.to_int_floor()) {
@@ -150,23 +129,23 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
break;
case 1:
- output[write_index] = calculate_sample(SincWindow3, SincWindow4);
+ output[write_index] = calculate_sample(WindowedSinc1, WindowedSinc5);
break;
case 2:
- output[write_index] = calculate_sample(SincWindow2, SincWindow1);
+ output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
break;
case 3:
- output[write_index] = calculate_sample(SincWindow5, SincWindow5);
+ output[write_index] = calculate_sample(WindowedSinc3, WindowedSinc3);
break;
case 4:
- output[write_index] = calculate_sample(SincWindow1, SincWindow2);
+ output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
break;
case 5:
- output[write_index] = calculate_sample(SincWindow4, SincWindow3);
+ output[write_index] = calculate_sample(WindowedSinc5, WindowedSinc1);
break;
}
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,
break;
case 1:
- output[write_index] = calculate_sample(SincWindow2, SincWindow1);
+ output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
break;
case 2:
- output[write_index] = calculate_sample(SincWindow1, SincWindow2);
+ output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
break;
}
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,
break;
case 1:
- output[write_index] = calculate_sample(SincWindow1, SincWindow2);
+ output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
break;
case 2:
increment();
- output[write_index] = calculate_sample(SincWindow2, SincWindow1);
+ output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
break;
}
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() {
info.up_scale = 1;
info.down_shift = 0;
break;
+ case ResolutionSetup::Res3_2X:
+ info.up_scale = 3;
+ info.down_shift = 1;
+ break;
case ResolutionSetup::Res2X:
info.up_scale = 2;
info.down_shift = 0;
@@ -149,6 +153,14 @@ void UpdateRescalingInfo() {
info.up_scale = 6;
info.down_shift = 0;
break;
+ case ResolutionSetup::Res7X:
+ info.up_scale = 7;
+ info.down_shift = 0;
+ break;
+ case ResolutionSetup::Res8X:
+ info.up_scale = 8;
+ info.down_shift = 0;
+ break;
default:
ASSERT(false);
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 {
Res1_2X = 0,
Res3_4X = 1,
Res1X = 2,
- Res2X = 3,
- Res3X = 4,
- Res4X = 5,
- Res5X = 6,
- Res6X = 7,
+ Res3_2X = 3,
+ Res2X = 4,
+ Res3X = 5,
+ Res4X = 6,
+ Res5X = 7,
+ Res6X = 8,
+ Res7X = 9,
+ Res8X = 10,
};
enum 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,
}
void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
- std::uintptr_t user_data) {
- std::scoped_lock scope{basic_lock};
- const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
- return e.type.lock().get() == event_type.get() && e.user_data == user_data;
- });
-
- // Removing random items breaks the invariant so we have to re-establish it.
- if (itr != event_queue.end()) {
- event_queue.erase(itr, event_queue.end());
- std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
+ std::uintptr_t user_data, bool wait) {
+ {
+ std::scoped_lock lk{basic_lock};
+ const auto itr =
+ std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
+ return e.type.lock().get() == event_type.get() && e.user_data == user_data;
+ });
+
+ // Removing random items breaks the invariant so we have to re-establish it.
+ if (itr != event_queue.end()) {
+ event_queue.erase(itr, event_queue.end());
+ std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
+ }
+ }
+
+ // Force any in-progress events to finish
+ if (wait) {
+ std::scoped_lock lk{advance_lock};
}
}
@@ -190,20 +198,6 @@ u64 CoreTiming::GetClockTicks() const {
return CpuCyclesToClockCycles(ticks);
}
-void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
- std::scoped_lock lock{basic_lock};
-
- const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
- return e.type.lock().get() == event_type.get();
- });
-
- // Removing random items breaks the invariant so we have to re-establish it.
- if (itr != event_queue.end()) {
- event_queue.erase(itr, event_queue.end());
- std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
- }
-}
-
std::optional<s64> CoreTiming::Advance() {
std::scoped_lock lock{advance_lock, basic_lock};
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:
const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data = 0, bool absolute_time = false);
- void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data);
+ void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data,
+ bool wait = true);
- /// We only permit one event of each type in the queue at a time.
- void RemoveEvent(const std::shared_ptr<EventType>& event_type);
+ void UnscheduleEventWithoutWait(const std::shared_ptr<EventType>& event_type,
+ std::uintptr_t user_data) {
+ UnscheduleEvent(event_type, user_data, false);
+ }
void AddTicks(u64 ticks_to_add);
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() {
}
void KHardwareTimer::Finalize() {
- this->DisableInterrupt();
+ m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
+ m_wakeup_time = std::numeric_limits<s64>::max();
m_event_type.reset();
}
@@ -59,7 +60,8 @@ void KHardwareTimer::EnableInterrupt(s64 wakeup_time) {
}
void KHardwareTimer::DisableInterrupt() {
- m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
+ m_kernel.System().CoreTiming().UnscheduleEventWithoutWait(m_event_type,
+ reinterpret_cast<uintptr_t>(this));
m_wakeup_time = std::numeric_limits<s64>::max();
}
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() {
}
s64 NVFlinger::GetNextTicks() const {
- static constexpr s64 max_hertz = 120LL;
-
const auto& settings = Settings::values;
auto speed_scale = 1.f;
if (settings.use_multi_core.GetValue()) {
@@ -327,9 +325,11 @@ s64 NVFlinger::GetNextTicks() const {
}
}
- const auto next_ticks = ((1000000000 * (1LL << swap_interval)) / max_hertz);
+ // As an extension, treat nonpositive swap interval as framerate multiplier.
+ const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval)
+ : 60.f / static_cast<f32>(swap_interval);
- return static_cast<s64>(speed_scale * static_cast<float>(next_ticks));
+ return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
}
} // 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:
/// layers.
u32 next_buffer_queue_id = 1;
- u32 swap_interval = 1;
+ s32 swap_interval = 1;
/// Event that handles screen composition.
std::shared_ptr<Core::Timing::EventType> multi_composition_event;
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 97f547789..68ceda519 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -467,7 +467,7 @@ void Maxwell3D::ProcessMacroBind(u32 data) {
}
void Maxwell3D::ProcessFirmwareCall4() {
- LOG_WARNING(HW_GPU, "(STUBBED) called");
+ LOG_DEBUG(HW_GPU, "(STUBBED) called");
// Firmware call 4 is a blob that changes some registers depending on its parameters.
// These registers don't affect emulation and so are stubbed by setting 0xd00 to 1.
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 @@
</item>
<item>
<property name="text">
+ <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
<string>2X (1440p/2160p)</string>
</property>
</item>
@@ -389,6 +394,16 @@
<string>6X (4320p/6480p)</string>
</property>
</item>
+ <item>
+ <property name="text">
+ <string>7X (5040p/7560p)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>8X (5760p/8640p)</string>
+ </property>
+ </item>
</widget>
</item>
</layout>