diff --git a/src/core/hle/kernel/k_capabilities.cpp b/src/core/hle/kernel/k_capabilities.cpp index 64f1d73..2907cc6 100644 --- a/src/core/hle/kernel/k_capabilities.cpp +++ b/src/core/hle/kernel/k_capabilities.cpp @@ -203,23 +203,23 @@ Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) { Result KCapabilities::MapRegion_(const u32 cap, KPageTable* page_table) { // Map each region into the process's page table. - R_RETURN(ProcessMapRegionCapability( + return ProcessMapRegionCapability( cap, [](KMemoryRegionType region_type, KMemoryPermission perm) -> Result { // R_RETURN(page_table->MapRegion(region_type, perm)); UNIMPLEMENTED(); R_SUCCEED(); - })); + }); } Result KCapabilities::CheckMapRegion(KernelCore& kernel, const u32 cap) { // Check that each region has a physical backing store. - R_RETURN(ProcessMapRegionCapability( + return ProcessMapRegionCapability( cap, [&](KMemoryRegionType region_type, KMemoryPermission perm) -> Result { R_UNLESS(kernel.MemoryLayout().GetPhysicalMemoryRegionTree().FindFirstDerived( region_type) != nullptr, ResultOutOfRange); R_SUCCEED(); - })); + }); } Result KCapabilities::SetInterruptPairCapability(const u32 cap) { diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index fb2ba4c..fb8e793 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 513ea48..80eba22 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -758,12 +758,20 @@ Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const { return hid_core.GetSupportedStyleTag(); } -void Controller_NPad::SetSupportedNpadIdTypes(std::span data) { +Result Controller_NPad::SetSupportedNpadIdTypes(std::span data) { + constexpr std::size_t max_number_npad_ids = 0xa; const auto length = data.size(); ASSERT(length > 0 && (length % sizeof(u32)) == 0); + const std::size_t elements = length / sizeof(u32); + + if (elements > max_number_npad_ids) { + return InvalidArraySize; + } + supported_npad_id_types.clear(); - supported_npad_id_types.resize(length / sizeof(u32)); + supported_npad_id_types.resize(elements); std::memcpy(supported_npad_id_types.data(), data.data(), length); + return ResultSuccess; } void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 1f7d334..02cc009 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -96,7 +96,7 @@ public: void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); Core::HID::NpadStyleTag GetSupportedStyleSet() const; - void SetSupportedNpadIdTypes(std::span data); + Result SetSupportedNpadIdTypes(std::span data); void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); std::size_t GetSupportedNpadIdTypesSize() const; diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h index 76208e9..9585bda 100644 --- a/src/core/hle/service/hid/errors.h +++ b/src/core/hle/service/hid/errors.h @@ -18,6 +18,7 @@ constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601}; constexpr Result NpadIsSameType{ErrorModule::HID, 602}; constexpr Result InvalidNpadId{ErrorModule::HID, 709}; constexpr Result NpadNotConnected{ErrorModule::HID, 710}; +constexpr Result InvalidArraySize{ErrorModule::HID, 715}; constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302}; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index f15f1a6..ac2c0c7 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -1025,13 +1025,13 @@ void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop()}; - applet_resource->GetController(HidController::NPad) - .SetSupportedNpadIdTypes(ctx.ReadBuffer()); + const auto result = applet_resource->GetController(HidController::NPad) + .SetSupportedNpadIdTypes(ctx.ReadBuffer()); LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) { diff --git a/src/tests/video_core/buffer_base.cpp b/src/tests/video_core/buffer_base.cpp index 1275cca..734dbf4 100644 --- a/src/tests/video_core/buffer_base.cpp +++ b/src/tests/video_core/buffer_base.cpp @@ -538,7 +538,7 @@ TEST_CASE("BufferBase: Cached write downloads") { int num = 0; buffer.ForEachDownloadRangeAndClear(c, WORD, [&](u64 offset, u64 size) { ++num; }); buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; }); - REQUIRE(num == 1); + REQUIRE(num == 0); REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE)); REQUIRE(!buffer.IsRegionGpuModified(c + PAGE, PAGE)); buffer.FlushCachedWrites(); diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h index c47b7d8..92d77ee 100644 --- a/src/video_core/buffer_cache/buffer_base.h +++ b/src/video_core/buffer_cache/buffer_base.h @@ -430,7 +430,7 @@ private: if (query_begin >= SizeBytes() || size < 0) { return; } - [[maybe_unused]] u64* const untracked_words = Array(); + u64* const untracked_words = Array(); u64* const state_words = Array(); const u64 query_end = query_begin + std::min(static_cast(size), SizeBytes()); u64* const words_begin = state_words + query_begin / BYTES_PER_WORD; @@ -483,7 +483,7 @@ private: NotifyRasterizer(word_index, current_bits, ~u64{0}); } // Exclude CPU modified pages when visiting GPU pages - const u64 word = current_word; + const u64 word = current_word & ~(type == Type::GPU ? untracked_words[word_index] : 0); u64 page = page_begin; page_begin = 0; @@ -531,7 +531,7 @@ private: [[nodiscard]] bool IsRegionModified(u64 offset, u64 size) const noexcept { static_assert(type != Type::Untracked); - [[maybe_unused]] const u64* const untracked_words = Array(); + const u64* const untracked_words = Array(); const u64* const state_words = Array(); const u64 num_query_words = size / BYTES_PER_WORD + 1; const u64 word_begin = offset / BYTES_PER_WORD; @@ -539,7 +539,8 @@ private: const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE); u64 page_index = (offset / BYTES_PER_PAGE) % PAGES_PER_WORD; for (u64 word_index = word_begin; word_index < word_end; ++word_index, page_index = 0) { - const u64 word = state_words[word_index]; + const u64 off_word = type == Type::GPU ? untracked_words[word_index] : 0; + const u64 word = state_words[word_index] & ~off_word; if (word == 0) { continue; } @@ -563,7 +564,7 @@ private: [[nodiscard]] std::pair ModifiedRegion(u64 offset, u64 size) const noexcept { static_assert(type != Type::Untracked); - [[maybe_unused]] const u64* const untracked_words = Array(); + const u64* const untracked_words = Array(); const u64* const state_words = Array(); const u64 num_query_words = size / BYTES_PER_WORD + 1; const u64 word_begin = offset / BYTES_PER_WORD; @@ -573,7 +574,8 @@ private: u64 begin = std::numeric_limits::max(); u64 end = 0; for (u64 word_index = word_begin; word_index < word_end; ++word_index) { - const u64 word = state_words[word_index]; + const u64 off_word = type == Type::GPU ? untracked_words[word_index] : 0; + const u64 word = state_words[word_index] & ~off_word; if (word == 0) { continue; } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 5f63b8b..d35f092 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -961,6 +961,38 @@ void GMainWindow::InitializeWidgets() { tas_label->setFocusPolicy(Qt::NoFocus); statusBar()->insertPermanentWidget(0, tas_label); + volume_popup = new QWidget(this); + volume_popup->setWindowFlags(Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint | Qt::Popup); + volume_popup->setLayout(new QVBoxLayout()); + volume_popup->setMinimumWidth(200); + + volume_slider = new QSlider(Qt::Horizontal); + volume_slider->setObjectName(QStringLiteral("volume_slider")); + volume_slider->setMaximum(200); + volume_slider->setPageStep(5); + connect(volume_slider, &QSlider::valueChanged, this, [this](int percentage) { + Settings::values.audio_muted = false; + const auto volume = static_cast(percentage); + Settings::values.volume.SetValue(volume); + UpdateVolumeUI(); + }); + volume_popup->layout()->addWidget(volume_slider); + + volume_button = new QPushButton(); + volume_button->setObjectName(QStringLiteral("TogglableStatusBarButton")); + volume_button->setFocusPolicy(Qt::NoFocus); + volume_button->setCheckable(true); + UpdateVolumeUI(); + connect(volume_button, &QPushButton::clicked, this, [&] { + UpdateVolumeUI(); + volume_popup->setVisible(!volume_popup->isVisible()); + QRect rect = volume_button->geometry(); + QPoint bottomLeft = statusBar()->mapToGlobal(rect.topLeft()); + bottomLeft.setY(bottomLeft.y() - volume_popup->geometry().height()); + volume_popup->setGeometry(QRect(bottomLeft, QSize(rect.width(), rect.height()))); + }); + statusBar()->insertPermanentWidget(0, volume_button); + // setup AA button aa_status_button = new QPushButton(); aa_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton")); @@ -1123,30 +1155,9 @@ void GMainWindow::InitializeHotkeys() { &GMainWindow::OnToggleAdaptingFilter); connect_shortcut(QStringLiteral("Change Docked Mode"), &GMainWindow::OnToggleDockedMode); connect_shortcut(QStringLiteral("Change GPU Accuracy"), &GMainWindow::OnToggleGpuAccuracy); - connect_shortcut(QStringLiteral("Audio Mute/Unmute"), - [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); - connect_shortcut(QStringLiteral("Audio Volume Down"), [] { - const auto current_volume = static_cast(Settings::values.volume.GetValue()); - int step = 5; - if (current_volume <= 30) { - step = 2; - } - if (current_volume <= 6) { - step = 1; - } - Settings::values.volume.SetValue(std::max(current_volume - step, 0)); - }); - connect_shortcut(QStringLiteral("Audio Volume Up"), [] { - const auto current_volume = static_cast(Settings::values.volume.GetValue()); - int step = 5; - if (current_volume < 30) { - step = 2; - } - if (current_volume < 6) { - step = 1; - } - Settings::values.volume.SetValue(current_volume + step); - }); + connect_shortcut(QStringLiteral("Audio Mute/Unmute"), &GMainWindow::OnMute); + connect_shortcut(QStringLiteral("Audio Volume Down"), &GMainWindow::OnDecreaseVolume); + connect_shortcut(QStringLiteral("Audio Volume Up"), &GMainWindow::OnIncreaseVolume); connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); }); @@ -3460,6 +3471,39 @@ void GMainWindow::OnToggleGpuAccuracy() { UpdateGPUAccuracyButton(); } +void GMainWindow::OnMute() { + Settings::values.audio_muted = !Settings::values.audio_muted; + UpdateVolumeUI(); +} + +void GMainWindow::OnDecreaseVolume() { + Settings::values.audio_muted = false; + const auto current_volume = static_cast(Settings::values.volume.GetValue()); + int step = 5; + if (current_volume <= 30) { + step = 2; + } + if (current_volume <= 6) { + step = 1; + } + Settings::values.volume.SetValue(std::max(current_volume - step, 0)); + UpdateVolumeUI(); +} + +void GMainWindow::OnIncreaseVolume() { + Settings::values.audio_muted = false; + const auto current_volume = static_cast(Settings::values.volume.GetValue()); + int step = 5; + if (current_volume < 30) { + step = 2; + } + if (current_volume < 6) { + step = 1; + } + Settings::values.volume.SetValue(current_volume + step); + UpdateVolumeUI(); +} + void GMainWindow::OnToggleAdaptingFilter() { auto filter = Settings::values.scaling_filter.GetValue(); if (filter == Settings::ScalingFilter::LastFilter) { @@ -3918,6 +3962,18 @@ void GMainWindow::UpdateAAText() { } } +void GMainWindow::UpdateVolumeUI() { + const auto volume_value = static_cast(Settings::values.volume.GetValue()); + volume_slider->setValue(volume_value); + if (Settings::values.audio_muted) { + volume_button->setChecked(false); + volume_button->setText(tr("VOLUME: MUTE")); + } else { + volume_button->setChecked(true); + volume_button->setText(tr("VOLUME: %1%", "Volume percentage (e.g. 50%)").arg(volume_value)); + } +} + void GMainWindow::UpdateStatusButtons() { renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::Vulkan); @@ -3926,6 +3982,7 @@ void GMainWindow::UpdateStatusButtons() { UpdateDockedButton(); UpdateFilterText(); UpdateAAText(); + UpdateVolumeUI(); } void GMainWindow::UpdateUISettings() { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 0f61abc..a23b373 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -37,6 +37,8 @@ class QLabel; class MultiplayerState; class QPushButton; class QProgressDialog; +class QSlider; +class QHBoxLayout; class WaitTreeWidget; enum class GameListOpenTarget; enum class GameListRemoveTarget; @@ -312,6 +314,9 @@ private slots: void OnMenuRecentFile(); void OnConfigure(); void OnConfigureTas(); + void OnDecreaseVolume(); + void OnIncreaseVolume(); + void OnMute(); void OnTasStartStop(); void OnTasRecord(); void OnTasReset(); @@ -364,6 +369,7 @@ private: void UpdateAPIText(); void UpdateFilterText(); void UpdateAAText(); + void UpdateVolumeUI(); void UpdateStatusBar(); void UpdateGPUAccuracyButton(); void UpdateStatusButtons(); @@ -412,6 +418,9 @@ private: QPushButton* dock_status_button = nullptr; QPushButton* filter_status_button = nullptr; QPushButton* aa_status_button = nullptr; + QPushButton* volume_button = nullptr; + QWidget* volume_popup = nullptr; + QSlider* volume_slider = nullptr; QTimer status_bar_update_timer; std::unique_ptr config; diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 3f3651d..cf3cc4c 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -286,11 +286,14 @@ vulkan_device = # 0: 0.5x (360p/540p) [EXPERIMENTAL] # 1: 0.75x (540p/810p) [EXPERIMENTAL] # 2 (default): 1x (720p/1080p) -# 3: 2x (1440p/2160p) -# 4: 3x (2160p/3240p) -# 5: 4x (2880p/4320p) -# 6: 5x (3600p/5400p) -# 7: 6x (4320p/6480p) +# 3: 1.5x (1080p/1620p) [EXPERIMENTAL] +# 4: 2x (1440p/2160p) +# 5: 3x (2160p/3240p) +# 6: 4x (2880p/4320p) +# 7: 5x (3600p/5400p) +# 8: 6x (4320p/6480p) +# 9: 7x (5040p/7560p) +# 10: 8x (5760/8640p) resolution_setup = # Pixel filter to use when up- or down-sampling rendered frames. @@ -299,11 +302,11 @@ resolution_setup = # 2: Bicubic # 3: Gaussian # 4: ScaleForce -# 5: AMD FidelityFX™️ Super Resolution [Vulkan Only] +# 5: AMD FidelityFX™️ Super Resolution scaling_filter = # Anti-Aliasing (AA) -# 0 (default): None, 1: FXAA +# 0 (default): None, 1: FXAA, 2: SMAA anti_aliasing = # Whether to use fullscreen or borderless window mode