summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/CMakeLists.txt3
-rw-r--r--src/audio_core/cubeb_sink.cpp25
-rw-r--r--src/audio_core/sdl2_sink.cpp4
-rw-r--r--src/audio_core/time_stretch.cpp68
-rw-r--r--src/audio_core/time_stretch.h34
-rw-r--r--src/core/hle/kernel/k_code_memory.cpp3
-rw-r--r--src/core/hle/kernel/k_page_linked_list.h4
-rw-r--r--src/core/hle/kernel/k_page_table.cpp242
-rw-r--r--src/core/hle/kernel/k_page_table.h33
-rw-r--r--src/core/hle/kernel/svc.cpp13
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp2
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp12
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp2
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp2
-rw-r--r--src/video_core/command_classes/codecs/codec.cpp35
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp2
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp3
-rw-r--r--src/video_core/texture_cache/texture_cache.h2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp7
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu/configuration/configure_debug.ui4
-rw-r--r--src/yuzu/configuration/configure_hotkeys.cpp7
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.cpp6
-rw-r--r--src/yuzu/main.cpp13
-rw-r--r--src/yuzu_cmd/CMakeLists.txt2
-rw-r--r--src/yuzu_cmd/default_ini.h6
-rw-r--r--src/yuzu_cmd/yuzu.cpp1
30 files changed, 313 insertions, 237 deletions
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index 090dd19b1..e553b8203 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -36,8 +36,6 @@ add_library(audio_core STATIC
36 splitter_context.h 36 splitter_context.h
37 stream.cpp 37 stream.cpp
38 stream.h 38 stream.h
39 time_stretch.cpp
40 time_stretch.h
41 voice_context.cpp 39 voice_context.cpp
42 voice_context.h 40 voice_context.h
43 41
@@ -63,7 +61,6 @@ if (NOT MSVC)
63endif() 61endif()
64 62
65target_link_libraries(audio_core PUBLIC common core) 63target_link_libraries(audio_core PUBLIC common core)
66target_link_libraries(audio_core PRIVATE SoundTouch)
67 64
68if(ENABLE_CUBEB) 65if(ENABLE_CUBEB)
69 target_link_libraries(audio_core PRIVATE cubeb) 66 target_link_libraries(audio_core PRIVATE cubeb)
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 93c35e785..13de3087c 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -7,7 +7,6 @@
7#include <cstring> 7#include <cstring>
8#include "audio_core/cubeb_sink.h" 8#include "audio_core/cubeb_sink.h"
9#include "audio_core/stream.h" 9#include "audio_core/stream.h"
10#include "audio_core/time_stretch.h"
11#include "common/assert.h" 10#include "common/assert.h"
12#include "common/logging/log.h" 11#include "common/logging/log.h"
13#include "common/ring_buffer.h" 12#include "common/ring_buffer.h"
@@ -23,8 +22,7 @@ class CubebSinkStream final : public SinkStream {
23public: 22public:
24 CubebSinkStream(cubeb* ctx_, u32 sample_rate, u32 num_channels_, cubeb_devid output_device, 23 CubebSinkStream(cubeb* ctx_, u32 sample_rate, u32 num_channels_, cubeb_devid output_device,
25 const std::string& name) 24 const std::string& name)
26 : ctx{ctx_}, num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate, 25 : ctx{ctx_}, num_channels{std::min(num_channels_, 6u)} {
27 num_channels} {
28 26
29 cubeb_stream_params params{}; 27 cubeb_stream_params params{};
30 params.rate = sample_rate; 28 params.rate = sample_rate;
@@ -131,7 +129,6 @@ private:
131 Common::RingBuffer<s16, 0x10000> queue; 129 Common::RingBuffer<s16, 0x10000> queue;
132 std::array<s16, 2> last_frame{}; 130 std::array<s16, 2> last_frame{};
133 std::atomic<bool> should_flush{}; 131 std::atomic<bool> should_flush{};
134 TimeStretcher time_stretch;
135 132
136 static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, 133 static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
137 void* output_buffer, long num_frames); 134 void* output_buffer, long num_frames);
@@ -205,25 +202,7 @@ long CubebSinkStream::DataCallback([[maybe_unused]] cubeb_stream* stream, void*
205 202
206 const std::size_t num_channels = impl->GetNumChannels(); 203 const std::size_t num_channels = impl->GetNumChannels();
207 const std::size_t samples_to_write = num_channels * num_frames; 204 const std::size_t samples_to_write = num_channels * num_frames;
208 std::size_t samples_written; 205 const std::size_t samples_written = impl->queue.Pop(buffer, samples_to_write);
209
210 /*
211 if (Settings::values.enable_audio_stretching.GetValue()) {
212 const std::vector<s16> in{impl->queue.Pop()};
213 const std::size_t num_in{in.size() / num_channels};
214 s16* const out{reinterpret_cast<s16*>(buffer)};
215 const std::size_t out_frames =
216 impl->time_stretch.Process(in.data(), num_in, out, num_frames);
217 samples_written = out_frames * num_channels;
218
219 if (impl->should_flush) {
220 impl->time_stretch.Flush();
221 impl->should_flush = false;
222 }
223 } else {
224 samples_written = impl->queue.Pop(buffer, samples_to_write);
225 }*/
226 samples_written = impl->queue.Pop(buffer, samples_to_write);
227 206
228 if (samples_written >= num_channels) { 207 if (samples_written >= num_channels) {
229 std::memcpy(&impl->last_frame[0], buffer + (samples_written - num_channels) * sizeof(s16), 208 std::memcpy(&impl->last_frame[0], buffer + (samples_written - num_channels) * sizeof(s16),
diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp
index 62d3716a6..2d14ce2cb 100644
--- a/src/audio_core/sdl2_sink.cpp
+++ b/src/audio_core/sdl2_sink.cpp
@@ -7,7 +7,6 @@
7#include <cstring> 7#include <cstring>
8#include "audio_core/sdl2_sink.h" 8#include "audio_core/sdl2_sink.h"
9#include "audio_core/stream.h" 9#include "audio_core/stream.h"
10#include "audio_core/time_stretch.h"
11#include "common/assert.h" 10#include "common/assert.h"
12#include "common/logging/log.h" 11#include "common/logging/log.h"
13//#include "common/settings.h" 12//#include "common/settings.h"
@@ -27,7 +26,7 @@ namespace AudioCore {
27class SDLSinkStream final : public SinkStream { 26class SDLSinkStream final : public SinkStream {
28public: 27public:
29 SDLSinkStream(u32 sample_rate, u32 num_channels_, const std::string& output_device) 28 SDLSinkStream(u32 sample_rate, u32 num_channels_, const std::string& output_device)
30 : num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate, num_channels} { 29 : num_channels{std::min(num_channels_, 6u)} {
31 30
32 SDL_AudioSpec spec; 31 SDL_AudioSpec spec;
33 spec.freq = sample_rate; 32 spec.freq = sample_rate;
@@ -116,7 +115,6 @@ private:
116 SDL_AudioDeviceID dev = 0; 115 SDL_AudioDeviceID dev = 0;
117 u32 num_channels{}; 116 u32 num_channels{};
118 std::atomic<bool> should_flush{}; 117 std::atomic<bool> should_flush{};
119 TimeStretcher time_stretch;
120}; 118};
121 119
122SDLSink::SDLSink(std::string_view target_device_name) { 120SDLSink::SDLSink(std::string_view target_device_name) {
diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp
deleted file mode 100644
index 726591fce..000000000
--- a/src/audio_core/time_stretch.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <cmath>
7#include <cstddef>
8#include "audio_core/time_stretch.h"
9#include "common/logging/log.h"
10
11namespace AudioCore {
12
13TimeStretcher::TimeStretcher(u32 sample_rate, u32 channel_count) : m_sample_rate{sample_rate} {
14 m_sound_touch.setChannels(channel_count);
15 m_sound_touch.setSampleRate(sample_rate);
16 m_sound_touch.setPitch(1.0);
17 m_sound_touch.setTempo(1.0);
18}
19
20void TimeStretcher::Clear() {
21 m_sound_touch.clear();
22}
23
24void TimeStretcher::Flush() {
25 m_sound_touch.flush();
26}
27
28std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
29 std::size_t num_out) {
30 const double time_delta = static_cast<double>(num_out) / m_sample_rate; // seconds
31
32 // We were given actual_samples number of samples, and num_samples were requested from us.
33 double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out);
34
35 const double max_latency = 0.25; // seconds
36 const double max_backlog = m_sample_rate * max_latency;
37 const double backlog_fullness = m_sound_touch.numSamples() / max_backlog;
38 if (backlog_fullness > 4.0) {
39 // Too many samples in backlog: Don't push anymore on
40 num_in = 0;
41 }
42
43 // We ideally want the backlog to be about 50% full.
44 // This gives some headroom both ways to prevent underflow and overflow.
45 // We tweak current_ratio to encourage this.
46 constexpr double tweak_time_scale = 0.05; // seconds
47 const double tweak_correction = (backlog_fullness - 0.5) * (time_delta / tweak_time_scale);
48 current_ratio *= std::pow(1.0 + 2.0 * tweak_correction, tweak_correction < 0 ? 3.0 : 1.0);
49
50 // This low-pass filter smoothes out variance in the calculated stretch ratio.
51 // The time-scale determines how responsive this filter is.
52 constexpr double lpf_time_scale = 0.712; // seconds
53 const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale);
54 m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio);
55
56 // Place a lower limit of 5% speed. When a game boots up, there will be
57 // many silence samples. These do not need to be timestretched.
58 m_stretch_ratio = std::max(m_stretch_ratio, 0.05);
59 m_sound_touch.setTempo(m_stretch_ratio);
60
61 LOG_TRACE(Audio, "{:5}/{:5} ratio:{:0.6f} backlog:{:0.6f}", num_in, num_out, m_stretch_ratio,
62 backlog_fullness);
63
64 m_sound_touch.putSamples(in, static_cast<u32>(num_in));
65 return m_sound_touch.receiveSamples(out, static_cast<u32>(num_out));
66}
67
68} // namespace AudioCore
diff --git a/src/audio_core/time_stretch.h b/src/audio_core/time_stretch.h
deleted file mode 100644
index bb2270b96..000000000
--- a/src/audio_core/time_stretch.h
+++ /dev/null
@@ -1,34 +0,0 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <SoundTouch.h>
9#include "common/common_types.h"
10
11namespace AudioCore {
12
13class TimeStretcher {
14public:
15 TimeStretcher(u32 sample_rate, u32 channel_count);
16
17 /// @param in Input sample buffer
18 /// @param num_in Number of input frames in `in`
19 /// @param out Output sample buffer
20 /// @param num_out Desired number of output frames in `out`
21 /// @returns Actual number of frames written to `out`
22 std::size_t Process(const s16* in, std::size_t num_in, s16* out, std::size_t num_out);
23
24 void Clear();
25
26 void Flush();
27
28private:
29 u32 m_sample_rate;
30 soundtouch::SoundTouch m_sound_touch;
31 double m_stretch_ratio = 1.0;
32};
33
34} // namespace AudioCore
diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp
index b365ce7b7..63bbe02e9 100644
--- a/src/core/hle/kernel/k_code_memory.cpp
+++ b/src/core/hle/kernel/k_code_memory.cpp
@@ -28,7 +28,8 @@ ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr
28 auto& page_table = m_owner->PageTable(); 28 auto& page_table = m_owner->PageTable();
29 29
30 // Construct the page group. 30 // Construct the page group.
31 m_page_group = KPageLinkedList(addr, Common::DivideUp(size, PageSize)); 31 m_page_group =
32 KPageLinkedList(page_table.GetPhysicalAddr(addr), Common::DivideUp(size, PageSize));
32 33
33 // Lock the memory. 34 // Lock the memory.
34 R_TRY(page_table.LockForCodeMemory(addr, size)) 35 R_TRY(page_table.LockForCodeMemory(addr, size))
diff --git a/src/core/hle/kernel/k_page_linked_list.h b/src/core/hle/kernel/k_page_linked_list.h
index 0e2ae582a..869228322 100644
--- a/src/core/hle/kernel/k_page_linked_list.h
+++ b/src/core/hle/kernel/k_page_linked_list.h
@@ -89,6 +89,10 @@ public:
89 return ResultSuccess; 89 return ResultSuccess;
90 } 90 }
91 91
92 bool Empty() const {
93 return nodes.empty();
94 }
95
92private: 96private:
93 std::list<Node> nodes; 97 std::list<Node> nodes;
94}; 98};
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 02d93b12e..599013cf6 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -486,6 +486,58 @@ VAddr KPageTable::FindFreeArea(VAddr region_start, std::size_t region_num_pages,
486 return address; 486 return address;
487} 487}
488 488
489ResultCode KPageTable::MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages) {
490 ASSERT(this->IsLockedByCurrentThread());
491
492 const size_t size = num_pages * PageSize;
493
494 // We're making a new group, not adding to an existing one.
495 R_UNLESS(pg.Empty(), ResultInvalidCurrentMemory);
496
497 // Begin traversal.
498 Common::PageTable::TraversalContext context;
499 Common::PageTable::TraversalEntry next_entry;
500 R_UNLESS(page_table_impl.BeginTraversal(next_entry, context, addr), ResultInvalidCurrentMemory);
501
502 // Prepare tracking variables.
503 PAddr cur_addr = next_entry.phys_addr;
504 size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1));
505 size_t tot_size = cur_size;
506
507 // Iterate, adding to group as we go.
508 const auto& memory_layout = system.Kernel().MemoryLayout();
509 while (tot_size < size) {
510 R_UNLESS(page_table_impl.ContinueTraversal(next_entry, context),
511 ResultInvalidCurrentMemory);
512
513 if (next_entry.phys_addr != (cur_addr + cur_size)) {
514 const size_t cur_pages = cur_size / PageSize;
515
516 R_UNLESS(IsHeapPhysicalAddress(memory_layout, cur_addr), ResultInvalidCurrentMemory);
517 R_TRY(pg.AddBlock(cur_addr, cur_pages));
518
519 cur_addr = next_entry.phys_addr;
520 cur_size = next_entry.block_size;
521 } else {
522 cur_size += next_entry.block_size;
523 }
524
525 tot_size += next_entry.block_size;
526 }
527
528 // Ensure we add the right amount for the last block.
529 if (tot_size > size) {
530 cur_size -= (tot_size - size);
531 }
532
533 // Add the last block.
534 const size_t cur_pages = cur_size / PageSize;
535 R_UNLESS(IsHeapPhysicalAddress(memory_layout, cur_addr), ResultInvalidCurrentMemory);
536 R_TRY(pg.AddBlock(cur_addr, cur_pages));
537
538 return ResultSuccess;
539}
540
489ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, 541ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
490 KPageTable& src_page_table, VAddr src_addr) { 542 KPageTable& src_page_table, VAddr src_addr) {
491 KScopedLightLock lk(general_lock); 543 KScopedLightLock lk(general_lock);
@@ -1223,6 +1275,31 @@ ResultCode KPageTable::UnmapPages(VAddr address, std::size_t num_pages, KMemoryS
1223 return ResultSuccess; 1275 return ResultSuccess;
1224} 1276}
1225 1277
1278ResultCode KPageTable::MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages,
1279 KMemoryState state_mask, KMemoryState state,
1280 KMemoryPermission perm_mask, KMemoryPermission perm,
1281 KMemoryAttribute attr_mask, KMemoryAttribute attr) {
1282 // Ensure that the page group isn't null.
1283 ASSERT(out != nullptr);
1284
1285 // Make sure that the region we're mapping is valid for the table.
1286 const size_t size = num_pages * PageSize;
1287 R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
1288
1289 // Lock the table.
1290 KScopedLightLock lk(general_lock);
1291
1292 // Check if state allows us to create the group.
1293 R_TRY(this->CheckMemoryState(address, size, state_mask | KMemoryState::FlagReferenceCounted,
1294 state | KMemoryState::FlagReferenceCounted, perm_mask, perm,
1295 attr_mask, attr));
1296
1297 // Create a new page group for the region.
1298 R_TRY(this->MakePageGroup(*out, address, num_pages));
1299
1300 return ResultSuccess;
1301}
1302
1226ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, 1303ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
1227 Svc::MemoryPermission svc_perm) { 1304 Svc::MemoryPermission svc_perm) {
1228 const size_t num_pages = size / PageSize; 1305 const size_t num_pages = size / PageSize;
@@ -1605,57 +1682,21 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
1605} 1682}
1606 1683
1607ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { 1684ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
1608 KScopedLightLock lk(general_lock); 1685 return this->LockMemoryAndOpen(
1609 1686 nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
1610 KMemoryPermission new_perm = KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite; 1687 KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, KMemoryPermission::UserReadWrite,
1611 1688 KMemoryAttribute::All, KMemoryAttribute::None,
1612 KMemoryPermission old_perm{}; 1689 static_cast<KMemoryPermission>(KMemoryPermission::NotMapped |
1613 1690 KMemoryPermission::KernelReadWrite),
1614 if (const ResultCode result{CheckMemoryState( 1691 KMemoryAttribute::Locked);
1615 nullptr, &old_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
1616 KMemoryState::FlagCanCodeMemory, KMemoryPermission::All,
1617 KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)};
1618 result.IsError()) {
1619 return result;
1620 }
1621
1622 new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
1623
1624 block_manager->UpdateLock(
1625 addr, size / PageSize,
1626 [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
1627 block->ShareToDevice(permission);
1628 },
1629 new_perm);
1630
1631 return ResultSuccess;
1632} 1692}
1633 1693
1634ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) { 1694ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) {
1635 KScopedLightLock lk(general_lock); 1695 return this->UnlockMemory(addr, size, KMemoryState::FlagCanCodeMemory,
1636 1696 KMemoryState::FlagCanCodeMemory, KMemoryPermission::None,
1637 KMemoryPermission new_perm = KMemoryPermission::UserReadWrite; 1697 KMemoryPermission::None, KMemoryAttribute::All,
1638 1698 KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite,
1639 KMemoryPermission old_perm{}; 1699 KMemoryAttribute::Locked, nullptr);
1640
1641 if (const ResultCode result{CheckMemoryState(
1642 nullptr, &old_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
1643 KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None,
1644 KMemoryAttribute::All, KMemoryAttribute::Locked)};
1645 result.IsError()) {
1646 return result;
1647 }
1648
1649 new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
1650
1651 block_manager->UpdateLock(
1652 addr, size / PageSize,
1653 [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
1654 block->UnshareToDevice(permission);
1655 },
1656 new_perm);
1657
1658 return ResultSuccess;
1659} 1700}
1660 1701
1661ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { 1702ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
@@ -1991,4 +2032,109 @@ ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermissi
1991 return ResultSuccess; 2032 return ResultSuccess;
1992} 2033}
1993 2034
2035ResultCode KPageTable::LockMemoryAndOpen(KPageLinkedList* out_pg, PAddr* out_paddr, VAddr addr,
2036 size_t size, KMemoryState state_mask, KMemoryState state,
2037 KMemoryPermission perm_mask, KMemoryPermission perm,
2038 KMemoryAttribute attr_mask, KMemoryAttribute attr,
2039 KMemoryPermission new_perm, KMemoryAttribute lock_attr) {
2040 // Validate basic preconditions.
2041 ASSERT((lock_attr & attr) == KMemoryAttribute::None);
2042 ASSERT((lock_attr & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)) ==
2043 KMemoryAttribute::None);
2044
2045 // Validate the lock request.
2046 const size_t num_pages = size / PageSize;
2047 R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory);
2048
2049 // Lock the table.
2050 KScopedLightLock lk(general_lock);
2051
2052 // Check that the output page group is empty, if it exists.
2053 if (out_pg) {
2054 ASSERT(out_pg->GetNumPages() == 0);
2055 }
2056
2057 // Check the state.
2058 KMemoryState old_state{};
2059 KMemoryPermission old_perm{};
2060 KMemoryAttribute old_attr{};
2061 size_t num_allocator_blocks{};
2062 R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm),
2063 std::addressof(old_attr), std::addressof(num_allocator_blocks),
2064 addr, size, state_mask | KMemoryState::FlagReferenceCounted,
2065 state | KMemoryState::FlagReferenceCounted, perm_mask, perm,
2066 attr_mask, attr));
2067
2068 // Get the physical address, if we're supposed to.
2069 if (out_paddr != nullptr) {
2070 ASSERT(this->GetPhysicalAddressLocked(out_paddr, addr));
2071 }
2072
2073 // Make the page group, if we're supposed to.
2074 if (out_pg != nullptr) {
2075 R_TRY(this->MakePageGroup(*out_pg, addr, num_pages));
2076 }
2077
2078 // Decide on new perm and attr.
2079 new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
2080 KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr | lock_attr);
2081
2082 // Update permission, if we need to.
2083 if (new_perm != old_perm) {
2084 R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions));
2085 }
2086
2087 // Apply the memory block updates.
2088 block_manager->Update(addr, num_pages, old_state, new_perm, new_attr);
2089
2090 return ResultSuccess;
2091}
2092
2093ResultCode KPageTable::UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask,
2094 KMemoryState state, KMemoryPermission perm_mask,
2095 KMemoryPermission perm, KMemoryAttribute attr_mask,
2096 KMemoryAttribute attr, KMemoryPermission new_perm,
2097 KMemoryAttribute lock_attr, const KPageLinkedList* pg) {
2098 // Validate basic preconditions.
2099 ASSERT((attr_mask & lock_attr) == lock_attr);
2100 ASSERT((attr & lock_attr) == lock_attr);
2101
2102 // Validate the unlock request.
2103 const size_t num_pages = size / PageSize;
2104 R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory);
2105
2106 // Lock the table.
2107 KScopedLightLock lk(general_lock);
2108
2109 // Check the state.
2110 KMemoryState old_state{};
2111 KMemoryPermission old_perm{};
2112 KMemoryAttribute old_attr{};
2113 size_t num_allocator_blocks{};
2114 R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm),
2115 std::addressof(old_attr), std::addressof(num_allocator_blocks),
2116 addr, size, state_mask | KMemoryState::FlagReferenceCounted,
2117 state | KMemoryState::FlagReferenceCounted, perm_mask, perm,
2118 attr_mask, attr));
2119
2120 // Check the page group.
2121 if (pg != nullptr) {
2122 UNIMPLEMENTED_MSG("PageGroup support is unimplemented!");
2123 }
2124
2125 // Decide on new perm and attr.
2126 new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
2127 KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr & ~lock_attr);
2128
2129 // Update permission, if we need to.
2130 if (new_perm != old_perm) {
2131 R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions));
2132 }
2133
2134 // Apply the memory block updates.
2135 block_manager->Update(addr, num_pages, old_state, new_perm, new_attr);
2136
2137 return ResultSuccess;
2138}
2139
1994} // namespace Kernel 2140} // namespace Kernel
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 54c6adf8d..bfabdf38c 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -12,6 +12,7 @@
12#include "core/file_sys/program_metadata.h" 12#include "core/file_sys/program_metadata.h"
13#include "core/hle/kernel/k_light_lock.h" 13#include "core/hle/kernel/k_light_lock.h"
14#include "core/hle/kernel/k_memory_block.h" 14#include "core/hle/kernel/k_memory_block.h"
15#include "core/hle/kernel/k_memory_layout.h"
15#include "core/hle/kernel/k_memory_manager.h" 16#include "core/hle/kernel/k_memory_manager.h"
16#include "core/hle/result.h" 17#include "core/hle/result.h"
17 18
@@ -71,6 +72,10 @@ public:
71 ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); 72 ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size);
72 ResultCode LockForCodeMemory(VAddr addr, std::size_t size); 73 ResultCode LockForCodeMemory(VAddr addr, std::size_t size);
73 ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size); 74 ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size);
75 ResultCode MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages,
76 KMemoryState state_mask, KMemoryState state,
77 KMemoryPermission perm_mask, KMemoryPermission perm,
78 KMemoryAttribute attr_mask, KMemoryAttribute attr);
74 79
75 Common::PageTable& PageTableImpl() { 80 Common::PageTable& PageTableImpl() {
76 return page_table_impl; 81 return page_table_impl;
@@ -159,10 +164,37 @@ private:
159 attr_mask, attr, ignore_attr); 164 attr_mask, attr, ignore_attr);
160 } 165 }
161 166
167 ResultCode LockMemoryAndOpen(KPageLinkedList* out_pg, PAddr* out_paddr, VAddr addr, size_t size,
168 KMemoryState state_mask, KMemoryState state,
169 KMemoryPermission perm_mask, KMemoryPermission perm,
170 KMemoryAttribute attr_mask, KMemoryAttribute attr,
171 KMemoryPermission new_perm, KMemoryAttribute lock_attr);
172 ResultCode UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask, KMemoryState state,
173 KMemoryPermission perm_mask, KMemoryPermission perm,
174 KMemoryAttribute attr_mask, KMemoryAttribute attr,
175 KMemoryPermission new_perm, KMemoryAttribute lock_attr,
176 const KPageLinkedList* pg);
177
178 ResultCode MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages);
179
162 bool IsLockedByCurrentThread() const { 180 bool IsLockedByCurrentThread() const {
163 return general_lock.IsLockedByCurrentThread(); 181 return general_lock.IsLockedByCurrentThread();
164 } 182 }
165 183
184 bool IsHeapPhysicalAddress(const KMemoryLayout& layout, PAddr phys_addr) {
185 ASSERT(this->IsLockedByCurrentThread());
186
187 return layout.IsHeapPhysicalAddress(cached_physical_heap_region, phys_addr);
188 }
189
190 bool GetPhysicalAddressLocked(PAddr* out, VAddr virt_addr) const {
191 ASSERT(this->IsLockedByCurrentThread());
192
193 *out = GetPhysicalAddr(virt_addr);
194
195 return *out != 0;
196 }
197
166 mutable KLightLock general_lock; 198 mutable KLightLock general_lock;
167 mutable KLightLock map_physical_memory_lock; 199 mutable KLightLock map_physical_memory_lock;
168 200
@@ -322,6 +354,7 @@ private:
322 bool is_aslr_enabled{}; 354 bool is_aslr_enabled{};
323 355
324 u32 heap_fill_value{}; 356 u32 heap_fill_value{};
357 const KMemoryRegion* cached_physical_heap_region{};
325 358
326 KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application}; 359 KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application};
327 KMemoryManager::Direction allocation_option{KMemoryManager::Direction::FromFront}; 360 KMemoryManager::Direction allocation_option{KMemoryManager::Direction::FromFront};
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 839171e85..976d63234 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1362,8 +1362,11 @@ static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Hand
1362 ResultInvalidMemoryRegion); 1362 ResultInvalidMemoryRegion);
1363 1363
1364 // Create a new page group. 1364 // Create a new page group.
1365 KMemoryInfo kBlockInfo = dst_pt.QueryInfo(dst_address); 1365 KPageLinkedList pg;
1366 KPageLinkedList pg(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages()); 1366 R_TRY(src_pt.MakeAndOpenPageGroup(
1367 std::addressof(pg), src_address, size / PageSize, KMemoryState::FlagCanMapProcess,
1368 KMemoryState::FlagCanMapProcess, KMemoryPermission::None, KMemoryPermission::None,
1369 KMemoryAttribute::All, KMemoryAttribute::None));
1367 1370
1368 // Map the group. 1371 // Map the group.
1369 R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode, 1372 R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode,
@@ -1408,8 +1411,8 @@ static ResultCode UnmapProcessMemory(Core::System& system, VAddr dst_address, Ha
1408} 1411}
1409 1412
1410static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) { 1413static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) {
1411 LOG_TRACE(Kernel_SVC, "called, handle_out={}, address=0x{:X}, size=0x{:X}", 1414 LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, size=0x{:X}", address, size);
1412 static_cast<void*>(out), address, size); 1415
1413 // Get kernel instance. 1416 // Get kernel instance.
1414 auto& kernel = system.Kernel(); 1417 auto& kernel = system.Kernel();
1415 1418
@@ -1664,7 +1667,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
1664 return ResultInvalidAddress; 1667 return ResultInvalidAddress;
1665 } 1668 }
1666 1669
1667 if (size == 0 || Common::Is4KBAligned(size)) { 1670 if (size == 0 || !Common::Is4KBAligned(size)) {
1668 LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size); 1671 LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size);
1669 return ResultInvalidSize; 1672 return ResultInvalidSize;
1670 } 1673 }
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 3703ca4c6..4208337db 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -174,7 +174,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
174 ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found."); 174 ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found.");
175 175
176 ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(), 176 ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(),
177 "Could not write all of the bytes but everything else has succeded."); 177 "Could not write all of the bytes but everything else has succeeded.");
178 178
179 if (!src->GetContainingDirectory()->DeleteFile(Common::FS::GetFilename(src_path))) { 179 if (!src->GetContainingDirectory()->DeleteFile(Common::FS::GetFilename(src_path))) {
180 // TODO(DarkLordZach): Find a better error code for this 180 // TODO(DarkLordZach): Find a better error code for this
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index ec9fda248..92e6bf889 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -874,6 +874,10 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
874 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", 874 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
875 parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown); 875 parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown);
876 876
877 // Games expect this event to be signaled after calling this function
878 applet_resource->GetController<Controller_NPad>(HidController::NPad)
879 .SignalStyleSetChangedEvent(parameters.npad_id);
880
877 IPC::ResponseBuilder rb{ctx, 2, 1}; 881 IPC::ResponseBuilder rb{ctx, 2, 1};
878 rb.Push(ResultSuccess); 882 rb.Push(ResultSuccess);
879 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) 883 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index f9b82b504..44c54c665 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -134,7 +134,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
134 } 134 }
135 135
136 EventState status = events_interface.status[event_id]; 136 EventState status = events_interface.status[event_id];
137 const bool bad_parameter = status != EventState::Free && status != EventState::Registered; 137 const bool bad_parameter = status == EventState::Busy;
138 if (bad_parameter) { 138 if (bad_parameter) {
139 std::memcpy(output.data(), &params, sizeof(params)); 139 std::memcpy(output.data(), &params, sizeof(params));
140 return NvResult::BadParameter; 140 return NvResult::BadParameter;
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
index c16babe14..1ce2a856b 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -26,7 +26,7 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) {
26 rb.Push<DeviceFD>(0); 26 rb.Push<DeviceFD>(0);
27 rb.PushEnum(NvResult::NotInitialized); 27 rb.PushEnum(NvResult::NotInitialized);
28 28
29 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); 29 LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
30 return; 30 return;
31 } 31 }
32 32
@@ -61,7 +61,7 @@ void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
61 61
62 if (!is_initialized) { 62 if (!is_initialized) {
63 ServiceError(ctx, NvResult::NotInitialized); 63 ServiceError(ctx, NvResult::NotInitialized);
64 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); 64 LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
65 return; 65 return;
66 } 66 }
67 67
@@ -87,7 +87,7 @@ void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
87 87
88 if (!is_initialized) { 88 if (!is_initialized) {
89 ServiceError(ctx, NvResult::NotInitialized); 89 ServiceError(ctx, NvResult::NotInitialized);
90 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); 90 LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
91 return; 91 return;
92 } 92 }
93 93
@@ -114,7 +114,7 @@ void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
114 114
115 if (!is_initialized) { 115 if (!is_initialized) {
116 ServiceError(ctx, NvResult::NotInitialized); 116 ServiceError(ctx, NvResult::NotInitialized);
117 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); 117 LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
118 return; 118 return;
119 } 119 }
120 120
@@ -139,7 +139,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) {
139 139
140 if (!is_initialized) { 140 if (!is_initialized) {
141 ServiceError(ctx, NvResult::NotInitialized); 141 ServiceError(ctx, NvResult::NotInitialized);
142 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); 142 LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
143 return; 143 return;
144 } 144 }
145 145
@@ -170,7 +170,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
170 170
171 if (!is_initialized) { 171 if (!is_initialized) {
172 ServiceError(ctx, NvResult::NotInitialized); 172 ServiceError(ctx, NvResult::NotInitialized);
173 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); 173 LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
174 return; 174 return;
175 } 175 }
176 176
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp
index 57b4f0eee..60732215b 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp
@@ -132,7 +132,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
132 multisample = v.X(meta_reg++); 132 multisample = v.X(meta_reg++);
133 } 133 }
134 if (tld.clamp != 0) { 134 if (tld.clamp != 0) {
135 throw NotImplementedException("TLD.CL - CLAMP is not implmented"); 135 throw NotImplementedException("TLD.CL - CLAMP is not implemented");
136 } 136 }
137 IR::TextureInstInfo info{}; 137 IR::TextureInstInfo info{};
138 info.type.Assign(GetType(tld.type)); 138 info.type.Assign(GetType(tld.type));
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp
index 311a9e763..f89ce1b68 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp
@@ -81,7 +81,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
81 } const tmml{insn}; 81 } const tmml{insn};
82 82
83 if ((tmml.mask & 0b1100) != 0) { 83 if ((tmml.mask & 0b1100) != 0) {
84 throw NotImplementedException("TMML BA results are not implmented"); 84 throw NotImplementedException("TMML BA results are not implemented");
85 } 85 }
86 const IR::Value coords{MakeCoords(v, tmml.coord_reg, tmml.type)}; 86 const IR::Value coords{MakeCoords(v, tmml.coord_reg, tmml.type)};
87 87
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp
index 81fac94bf..40f7755e8 100644
--- a/src/video_core/command_classes/codecs/codec.cpp
+++ b/src/video_core/command_classes/codecs/codec.cpp
@@ -56,6 +56,18 @@ AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pi
56 av_codec_ctx->pix_fmt = PREFERRED_CPU_FMT; 56 av_codec_ctx->pix_fmt = PREFERRED_CPU_FMT;
57 return PREFERRED_CPU_FMT; 57 return PREFERRED_CPU_FMT;
58} 58}
59
60// List all the currently available hwcontext in ffmpeg
61std::vector<AVHWDeviceType> ListSupportedContexts() {
62 std::vector<AVHWDeviceType> contexts{};
63 AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE;
64 do {
65 current_device_type = av_hwdevice_iterate_types(current_device_type);
66 contexts.push_back(current_device_type);
67 } while (current_device_type != AV_HWDEVICE_TYPE_NONE);
68 return contexts;
69}
70
59} // namespace 71} // namespace
60 72
61void AVFrameDeleter(AVFrame* ptr) { 73void AVFrameDeleter(AVFrame* ptr) {
@@ -76,17 +88,6 @@ Codec::~Codec() {
76 av_buffer_unref(&av_gpu_decoder); 88 av_buffer_unref(&av_gpu_decoder);
77} 89}
78 90
79// List all the currently available hwcontext in ffmpeg
80static std::vector<AVHWDeviceType> ListSupportedContexts() {
81 std::vector<AVHWDeviceType> contexts{};
82 AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE;
83 do {
84 current_device_type = av_hwdevice_iterate_types(current_device_type);
85 contexts.push_back(current_device_type);
86 } while (current_device_type != AV_HWDEVICE_TYPE_NONE);
87 return contexts;
88}
89
90bool Codec::CreateGpuAvDevice() { 91bool Codec::CreateGpuAvDevice() {
91 static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX; 92 static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX;
92 static const auto supported_contexts = ListSupportedContexts(); 93 static const auto supported_contexts = ListSupportedContexts();
@@ -96,6 +97,8 @@ bool Codec::CreateGpuAvDevice() {
96 LOG_DEBUG(Service_NVDRV, "{} explicitly unsupported", av_hwdevice_get_type_name(type)); 97 LOG_DEBUG(Service_NVDRV, "{} explicitly unsupported", av_hwdevice_get_type_name(type));
97 continue; 98 continue;
98 } 99 }
100 // Avoid memory leak from not cleaning up after av_hwdevice_ctx_create
101 av_buffer_unref(&av_gpu_decoder);
99 const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0); 102 const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0);
100 if (hwdevice_res < 0) { 103 if (hwdevice_res < 0) {
101 LOG_DEBUG(Service_NVDRV, "{} av_hwdevice_ctx_create failed {}", 104 LOG_DEBUG(Service_NVDRV, "{} av_hwdevice_ctx_create failed {}",
@@ -127,15 +130,19 @@ bool Codec::CreateGpuAvDevice() {
127 av_codec->name, av_hwdevice_get_type_name(type)); 130 av_codec->name, av_hwdevice_get_type_name(type));
128 break; 131 break;
129 } 132 }
130 if (config->methods & HW_CONFIG_METHOD && config->device_type == type) { 133 if ((config->methods & HW_CONFIG_METHOD) != 0 && config->device_type == type) {
131 av_codec_ctx->pix_fmt = config->pix_fmt; 134#if defined(__unix__)
132 if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) { 135 // Some linux decoding backends are reported to crash with this config method
136 // TODO(ameerj): Properly support this method
137 if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) != 0) {
133 // skip zero-copy decoders, we don't currently support them 138 // skip zero-copy decoders, we don't currently support them
134 LOG_DEBUG(Service_NVDRV, "Skipping decoder {} with unsupported capability {}.", 139 LOG_DEBUG(Service_NVDRV, "Skipping decoder {} with unsupported capability {}.",
135 av_hwdevice_get_type_name(type), config->methods); 140 av_hwdevice_get_type_name(type), config->methods);
136 continue; 141 continue;
137 } 142 }
143#endif
138 LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type)); 144 LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
145 av_codec_ctx->pix_fmt = config->pix_fmt;
139 return true; 146 return true;
140 } 147 }
141 } 148 }
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 656dd7eb0..597301eeb 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -282,7 +282,7 @@ void main() {
282 282
283u64 Device::GetCurrentDedicatedVideoMemory() const { 283u64 Device::GetCurrentDedicatedVideoMemory() const {
284 GLint cur_avail_mem_kb = 0; 284 GLint cur_avail_mem_kb = 0;
285 glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &cur_avail_mem_kb); 285 glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &cur_avail_mem_kb);
286 return static_cast<u64>(cur_avail_mem_kb) * 1_KiB; 286 return static_cast<u64>(cur_avail_mem_kb) * 1_KiB;
287} 287}
288 288
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index ec03cca38..abda1c490 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -367,17 +367,14 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
367 PipelineLayoutCreateInfo(two_textures_set_layout.address()))), 367 PipelineLayoutCreateInfo(two_textures_set_layout.address()))),
368 full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)), 368 full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
369 blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)), 369 blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)),
370 blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)),
370 convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), 371 convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
371 convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), 372 convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
372 convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)), 373 convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
373 convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)), 374 convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
374 convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)), 375 convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
375 linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)), 376 linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
376 nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) { 377 nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {}
377 if (device.IsExtShaderStencilExportSupported()) {
378 blit_depth_stencil_frag = BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV);
379 }
380}
381 378
382BlitImageHelper::~BlitImageHelper() = default; 379BlitImageHelper::~BlitImageHelper() = default;
383 380
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index f2890d263..2c2ccc7c6 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -1451,8 +1451,7 @@ bool Image::BlitScaleHelper(bool scale_up) {
1451 1451
1452 runtime->blit_image_helper.BlitColor(blit_framebuffer.get(), color_view, dst_region, 1452 runtime->blit_image_helper.BlitColor(blit_framebuffer.get(), color_view, dst_region,
1453 src_region, operation, BLIT_OPERATION); 1453 src_region, operation, BLIT_OPERATION);
1454 } else if (!runtime->device.IsBlitDepthStencilSupported() && 1454 } else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
1455 aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
1456 if (!blit_framebuffer) { 1455 if (!blit_framebuffer) {
1457 blit_framebuffer = std::make_unique<Framebuffer>(*runtime, nullptr, view_ptr, extent); 1456 blit_framebuffer = std::make_unique<Framebuffer>(*runtime, nullptr, view_ptr, extent);
1458 } 1457 }
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index efc1c4525..8fef74117 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1080,8 +1080,6 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
1080 Image& overlap = slot_images[overlap_id]; 1080 Image& overlap = slot_images[overlap_id];
1081 if (True(overlap.flags & ImageFlagBits::GpuModified)) { 1081 if (True(overlap.flags & ImageFlagBits::GpuModified)) {
1082 new_image.flags |= ImageFlagBits::GpuModified; 1082 new_image.flags |= ImageFlagBits::GpuModified;
1083 new_image.modification_tick =
1084 std::max(overlap.modification_tick, new_image.modification_tick);
1085 } 1083 }
1086 if (overlap.info.num_samples != new_image.info.num_samples) { 1084 if (overlap.info.num_samples != new_image.info.num_samples) {
1087 LOG_WARNING(HW_GPU, "Copying between images with different samples is not implemented"); 1085 LOG_WARNING(HW_GPU, "Copying between images with different samples is not implemented");
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index e142bee35..f3a05ada9 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -621,6 +621,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
621 khr_push_descriptor = false; 621 khr_push_descriptor = false;
622 break; 622 break;
623 } 623 }
624 const u32 nv_major_version = (properties.driverVersion >> 22) & 0x3ff;
625 if (nv_major_version >= 510) {
626 LOG_WARNING(Render_Vulkan, "NVIDIA Drivers >= 510 do not support MSAA image blits");
627 cant_blit_msaa = true;
628 }
624 } 629 }
625 const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV; 630 const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV;
626 if (ext_extended_dynamic_state && is_radv) { 631 if (ext_extended_dynamic_state && is_radv) {
@@ -731,7 +736,7 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags
731} 736}
732 737
733void Device::ReportLoss() const { 738void Device::ReportLoss() const {
734 LOG_CRITICAL(Render_Vulkan, "Device loss occured!"); 739 LOG_CRITICAL(Render_Vulkan, "Device loss occurred!");
735 740
736 // Wait for the log to flush and for Nsight Aftermath to dump the results 741 // Wait for the log to flush and for Nsight Aftermath to dump the results
737 std::this_thread::sleep_for(std::chrono::seconds{15}); 742 std::this_thread::sleep_for(std::chrono::seconds{15});
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 30902101d..b1467d016 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -293,7 +293,7 @@ if (YUZU_USE_QT_WEB_ENGINE)
293endif () 293endif ()
294 294
295if(UNIX AND NOT APPLE) 295if(UNIX AND NOT APPLE)
296 install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") 296 install(TARGETS yuzu)
297endif() 297endif()
298 298
299if (YUZU_USE_BUNDLED_QT) 299if (YUZU_USE_BUNDLED_QT)
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index edb525e82..c1d90d588 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -214,14 +214,14 @@
214 <item row="1" column="1"> 214 <item row="1" column="1">
215 <widget class="QCheckBox" name="enable_all_controllers"> 215 <widget class="QCheckBox" name="enable_all_controllers">
216 <property name="text"> 216 <property name="text">
217 <string>Enable all Controller Types</string> 217 <string>Enable All Controller Types</string>
218 </property> 218 </property>
219 </widget> 219 </widget>
220 </item> 220 </item>
221 <item row="2" column="1"> 221 <item row="2" column="1">
222 <widget class="QCheckBox" name="disable_web_applet"> 222 <widget class="QCheckBox" name="disable_web_applet">
223 <property name="text"> 223 <property name="text">
224 <string>Disable Web Applet**</string> 224 <string>Disable Web Applet</string>
225 </property> 225 </property>
226 </widget> 226 </widget>
227 </item> 227 </item>
diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp
index 53e629a5e..6679e9c53 100644
--- a/src/yuzu/configuration/configure_hotkeys.cpp
+++ b/src/yuzu/configuration/configure_hotkeys.cpp
@@ -35,8 +35,9 @@ ConfigureHotkeys::ConfigureHotkeys(Core::HID::HIDCore& hid_core, QWidget* parent
35 ui->hotkey_list->setContextMenuPolicy(Qt::CustomContextMenu); 35 ui->hotkey_list->setContextMenuPolicy(Qt::CustomContextMenu);
36 ui->hotkey_list->setModel(model); 36 ui->hotkey_list->setModel(model);
37 37
38 ui->hotkey_list->setColumnWidth(name_column, 200); 38 ui->hotkey_list->header()->setStretchLastSection(false);
39 ui->hotkey_list->resizeColumnToContents(hotkey_column); 39 ui->hotkey_list->header()->setSectionResizeMode(name_column, QHeaderView::ResizeMode::Stretch);
40 ui->hotkey_list->header()->setMinimumSectionSize(150);
40 41
41 connect(ui->button_restore_defaults, &QPushButton::clicked, this, 42 connect(ui->button_restore_defaults, &QPushButton::clicked, this,
42 &ConfigureHotkeys::RestoreDefaults); 43 &ConfigureHotkeys::RestoreDefaults);
@@ -76,8 +77,8 @@ void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) {
76 } 77 }
77 78
78 ui->hotkey_list->expandAll(); 79 ui->hotkey_list->expandAll();
79 ui->hotkey_list->resizeColumnToContents(name_column);
80 ui->hotkey_list->resizeColumnToContents(hotkey_column); 80 ui->hotkey_list->resizeColumnToContents(hotkey_column);
81 ui->hotkey_list->resizeColumnToContents(controller_column);
81} 82}
82 83
83void ConfigureHotkeys::changeEvent(QEvent* event) { 84void ConfigureHotkeys::changeEvent(QEvent* event) {
diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp
index 21e51d749..7893a85bb 100644
--- a/src/yuzu/configuration/configure_per_game_addons.cpp
+++ b/src/yuzu/configuration/configure_per_game_addons.cpp
@@ -47,6 +47,10 @@ ConfigurePerGameAddons::ConfigurePerGameAddons(Core::System& system_, QWidget* p
47 item_model->setHeaderData(0, Qt::Horizontal, tr("Patch Name")); 47 item_model->setHeaderData(0, Qt::Horizontal, tr("Patch Name"));
48 item_model->setHeaderData(1, Qt::Horizontal, tr("Version")); 48 item_model->setHeaderData(1, Qt::Horizontal, tr("Version"));
49 49
50 tree_view->header()->setStretchLastSection(false);
51 tree_view->header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
52 tree_view->header()->setMinimumSectionSize(150);
53
50 // We must register all custom types with the Qt Automoc system so that we are able to use it 54 // We must register all custom types with the Qt Automoc system so that we are able to use it
51 // with signals/slots. In this case, QList falls under the umbrella of custom types. 55 // with signals/slots. In this case, QList falls under the umbrella of custom types.
52 qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>"); 56 qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
@@ -138,5 +142,5 @@ void ConfigurePerGameAddons::LoadConfiguration() {
138 item_model->appendRow(list_items.back()); 142 item_model->appendRow(list_items.back());
139 } 143 }
140 144
141 tree_view->setColumnWidth(0, 5 * tree_view->width() / 16); 145 tree_view->resizeColumnToContents(1);
142} 146}
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 3b7058a2b..62d15f8cd 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -293,8 +293,6 @@ GMainWindow::GMainWindow()
293 293
294 MigrateConfigFiles(); 294 MigrateConfigFiles();
295 295
296 ui->action_Fullscreen->setChecked(false);
297
298#if defined(HAVE_SDL2) && !defined(_WIN32) 296#if defined(HAVE_SDL2) && !defined(_WIN32)
299 SDL_InitSubSystem(SDL_INIT_VIDEO); 297 SDL_InitSubSystem(SDL_INIT_VIDEO);
300 // SDL disables the screen saver by default, and setting the hint 298 // SDL disables the screen saver by default, and setting the hint
@@ -312,17 +310,20 @@ GMainWindow::GMainWindow()
312 } 310 }
313 311
314 QString game_path; 312 QString game_path;
313 bool has_gamepath = false;
314 bool is_fullscreen = false;
315 315
316 for (int i = 1; i < args.size(); ++i) { 316 for (int i = 1; i < args.size(); ++i) {
317 // Preserves drag/drop functionality 317 // Preserves drag/drop functionality
318 if (args.size() == 2 && !args[1].startsWith(QChar::fromLatin1('-'))) { 318 if (args.size() == 2 && !args[1].startsWith(QChar::fromLatin1('-'))) {
319 game_path = args[1]; 319 game_path = args[1];
320 has_gamepath = true;
320 break; 321 break;
321 } 322 }
322 323
323 // Launch game in fullscreen mode 324 // Launch game in fullscreen mode
324 if (args[i] == QStringLiteral("-f")) { 325 if (args[i] == QStringLiteral("-f")) {
325 ui->action_Fullscreen->setChecked(true); 326 is_fullscreen = true;
326 continue; 327 continue;
327 } 328 }
328 329
@@ -365,9 +366,15 @@ GMainWindow::GMainWindow()
365 } 366 }
366 367
367 game_path = args[++i]; 368 game_path = args[++i];
369 has_gamepath = true;
368 } 370 }
369 } 371 }
370 372
373 // Override fullscreen setting if gamepath or argument is provided
374 if (has_gamepath || is_fullscreen) {
375 ui->action_Fullscreen->setChecked(is_fullscreen);
376 }
377
371 if (!game_path.isEmpty()) { 378 if (!game_path.isEmpty()) {
372 BootGame(game_path); 379 BootGame(game_path);
373 } 380 }
diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt
index 74fc24972..c8901f2df 100644
--- a/src/yuzu_cmd/CMakeLists.txt
+++ b/src/yuzu_cmd/CMakeLists.txt
@@ -45,7 +45,7 @@ if (YUZU_USE_EXTERNAL_SDL2)
45endif() 45endif()
46 46
47if(UNIX AND NOT APPLE) 47if(UNIX AND NOT APPLE)
48 install(TARGETS yuzu-cmd RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") 48 install(TARGETS yuzu-cmd)
49endif() 49endif()
50 50
51if (MSVC) 51if (MSVC)
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 34782c378..f34d6b728 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -342,12 +342,6 @@ fps_cap =
342# null: No audio output 342# null: No audio output
343output_engine = 343output_engine =
344 344
345# Whether or not to enable the audio-stretching post-processing effect.
346# This effect adjusts audio speed to match emulation speed and helps prevent audio stutter,
347# at the cost of increasing audio latency.
348# 0: No, 1 (default): Yes
349enable_audio_stretching =
350
351# Which audio device to use. 345# Which audio device to use.
352# auto (default): Auto-select 346# auto (default): Auto-select
353output_device = 347output_device =
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 14bf82f39..ab12dd15d 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -74,6 +74,7 @@ static void PrintVersion() {
74int main(int argc, char** argv) { 74int main(int argc, char** argv) {
75 Common::Log::Initialize(); 75 Common::Log::Initialize();
76 Common::Log::SetColorConsoleBackendEnabled(true); 76 Common::Log::SetColorConsoleBackendEnabled(true);
77 Common::Log::Start();
77 Common::DetachedTasks detached_tasks; 78 Common::DetachedTasks detached_tasks;
78 79
79 int option_index = 0; 80 int option_index = 0;