summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/sink/cubeb_sink.cpp3
-rw-r--r--src/audio_core/sink/sdl2_sink.cpp3
-rw-r--r--src/audio_core/sink/sink.h12
-rw-r--r--src/audio_core/sink/sink_stream.cpp41
-rw-r--r--src/common/fs/path_util.cpp6
-rw-r--r--src/common/fs/path_util.h2
-rw-r--r--src/core/hle/service/audio/audren_u.cpp2
-rw-r--r--src/core/hle/service/filesystem/filesystem.h7
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp18
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp35
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_core.cpp4
-rw-r--r--src/core/hle/service/nvnflinger/buffer_slot.h1
-rw-r--r--src/tests/video_core/memory_tracker.cpp6
-rw-r--r--src/video_core/buffer_cache/word_manager.h2
-rw-r--r--src/video_core/rasterizer_accelerated.cpp99
-rw-r--r--src/video_core/rasterizer_accelerated.h29
-rw-r--r--src/video_core/rasterizer_interface.h2
-rw-r--r--src/video_core/shader_cache.cpp4
-rw-r--r--src/video_core/texture_cache/texture_cache.h10
-rw-r--r--src/yuzu/configuration/configure_ui.cpp4
-rw-r--r--src/yuzu/configuration/qt_config.cpp5
-rw-r--r--src/yuzu/main.cpp6
-rw-r--r--src/yuzu/uisettings.h3
23 files changed, 184 insertions, 120 deletions
diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp
index 51a23fe15..d97ca2a40 100644
--- a/src/audio_core/sink/cubeb_sink.cpp
+++ b/src/audio_core/sink/cubeb_sink.cpp
@@ -253,8 +253,9 @@ CubebSink::~CubebSink() {
253#endif 253#endif
254} 254}
255 255
256SinkStream* CubebSink::AcquireSinkStream(Core::System& system, u32 system_channels, 256SinkStream* CubebSink::AcquireSinkStream(Core::System& system, u32 system_channels_,
257 const std::string& name, StreamType type) { 257 const std::string& name, StreamType type) {
258 system_channels = system_channels_;
258 SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<CubebSinkStream>( 259 SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<CubebSinkStream>(
259 ctx, device_channels, system_channels, output_device, input_device, name, type, system)); 260 ctx, device_channels, system_channels, output_device, input_device, name, type, system));
260 261
diff --git a/src/audio_core/sink/sdl2_sink.cpp b/src/audio_core/sink/sdl2_sink.cpp
index 96e0efce2..7dd155ff0 100644
--- a/src/audio_core/sink/sdl2_sink.cpp
+++ b/src/audio_core/sink/sdl2_sink.cpp
@@ -168,8 +168,9 @@ SDLSink::SDLSink(std::string_view target_device_name) {
168 168
169SDLSink::~SDLSink() = default; 169SDLSink::~SDLSink() = default;
170 170
171SinkStream* SDLSink::AcquireSinkStream(Core::System& system, u32 system_channels, 171SinkStream* SDLSink::AcquireSinkStream(Core::System& system, u32 system_channels_,
172 const std::string&, StreamType type) { 172 const std::string&, StreamType type) {
173 system_channels = system_channels_;
173 SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<SDLSinkStream>( 174 SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<SDLSinkStream>(
174 device_channels, system_channels, output_device, input_device, type, system)); 175 device_channels, system_channels, output_device, input_device, type, system));
175 return stream.get(); 176 return stream.get();
diff --git a/src/audio_core/sink/sink.h b/src/audio_core/sink/sink.h
index f28c6d126..e22e8c3e5 100644
--- a/src/audio_core/sink/sink.h
+++ b/src/audio_core/sink/sink.h
@@ -85,9 +85,21 @@ public:
85 */ 85 */
86 virtual void SetSystemVolume(f32 volume) = 0; 86 virtual void SetSystemVolume(f32 volume) = 0;
87 87
88 /**
89 * Get the number of channels the game has set, can be different to the host hardware's support.
90 * Either 2 or 6.
91 *
92 * @return Number of device channels.
93 */
94 u32 GetSystemChannels() const {
95 return system_channels;
96 }
97
88protected: 98protected:
89 /// Number of device channels supported by the hardware 99 /// Number of device channels supported by the hardware
90 u32 device_channels{2}; 100 u32 device_channels{2};
101 /// Number of channels the game is sending
102 u32 system_channels{2};
91}; 103};
92 104
93using SinkPtr = std::unique_ptr<Sink>; 105using SinkPtr = std::unique_ptr<Sink>;
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp
index 2a09db599..c047b0668 100644
--- a/src/audio_core/sink/sink_stream.cpp
+++ b/src/audio_core/sink/sink_stream.cpp
@@ -40,29 +40,36 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
40 40
41 if (system_channels == 6 && device_channels == 2) { 41 if (system_channels == 6 && device_channels == 2) {
42 // We're given 6 channels, but our device only outputs 2, so downmix. 42 // We're given 6 channels, but our device only outputs 2, so downmix.
43 static constexpr std::array<f32, 4> down_mix_coeff{1.0f, 0.707f, 0.251f, 0.707f}; 43 // Front = 1.0
44 // Center = 0.596
45 // LFE = 0.354
46 // Back = 0.707
47 static constexpr std::array<f32, 4> down_mix_coeff{1.0, 0.596f, 0.354f, 0.707f};
44 48
45 for (u32 read_index = 0, write_index = 0; read_index < samples.size(); 49 for (u32 read_index = 0, write_index = 0; read_index < samples.size();
46 read_index += system_channels, write_index += device_channels) { 50 read_index += system_channels, write_index += device_channels) {
51 const auto fl =
52 static_cast<f32>(samples[read_index + static_cast<u32>(Channels::FrontLeft)]);
53 const auto fr =
54 static_cast<f32>(samples[read_index + static_cast<u32>(Channels::FrontRight)]);
55 const auto c =
56 static_cast<f32>(samples[read_index + static_cast<u32>(Channels::Center)]);
57 const auto lfe =
58 static_cast<f32>(samples[read_index + static_cast<u32>(Channels::LFE)]);
59 const auto bl =
60 static_cast<f32>(samples[read_index + static_cast<u32>(Channels::BackLeft)]);
61 const auto br =
62 static_cast<f32>(samples[read_index + static_cast<u32>(Channels::BackRight)]);
63
47 const auto left_sample{ 64 const auto left_sample{
48 ((Common::FixedPoint<49, 15>( 65 static_cast<s32>((fl * down_mix_coeff[0] + c * down_mix_coeff[1] +
49 samples[read_index + static_cast<u32>(Channels::FrontLeft)]) * 66 lfe * down_mix_coeff[2] + bl * down_mix_coeff[3]) *
50 down_mix_coeff[0] + 67 volume)};
51 samples[read_index + static_cast<u32>(Channels::Center)] * down_mix_coeff[1] +
52 samples[read_index + static_cast<u32>(Channels::LFE)] * down_mix_coeff[2] +
53 samples[read_index + static_cast<u32>(Channels::BackLeft)] * down_mix_coeff[3]) *
54 volume)
55 .to_int()};
56 68
57 const auto right_sample{ 69 const auto right_sample{
58 ((Common::FixedPoint<49, 15>( 70 static_cast<s32>((fr * down_mix_coeff[0] + c * down_mix_coeff[1] +
59 samples[read_index + static_cast<u32>(Channels::FrontRight)]) * 71 lfe * down_mix_coeff[2] + br * down_mix_coeff[3]) *
60 down_mix_coeff[0] + 72 volume)};
61 samples[read_index + static_cast<u32>(Channels::Center)] * down_mix_coeff[1] +
62 samples[read_index + static_cast<u32>(Channels::LFE)] * down_mix_coeff[2] +
63 samples[read_index + static_cast<u32>(Channels::BackRight)] * down_mix_coeff[3]) *
64 volume)
65 .to_int()};
66 73
67 samples[write_index + static_cast<u32>(Channels::FrontLeft)] = 74 samples[write_index + static_cast<u32>(Channels::FrontLeft)] =
68 static_cast<s16>(std::clamp(left_sample, min, max)); 75 static_cast<s16>(std::clamp(left_sample, min, max));
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index d2f50432a..4f69db6f5 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -418,9 +418,9 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
418 return std::string(RemoveTrailingSlash(path)); 418 return std::string(RemoveTrailingSlash(path));
419} 419}
420 420
421std::string_view GetParentPath(std::string_view path) { 421std::string GetParentPath(std::string_view path) {
422 if (path.empty()) { 422 if (path.empty()) {
423 return path; 423 return std::string(path);
424 } 424 }
425 425
426#ifdef ANDROID 426#ifdef ANDROID
@@ -439,7 +439,7 @@ std::string_view GetParentPath(std::string_view path) {
439 name_index = std::max(name_bck_index, name_fwd_index); 439 name_index = std::max(name_bck_index, name_fwd_index);
440 } 440 }
441 441
442 return path.substr(0, name_index); 442 return std::string(path.substr(0, name_index));
443} 443}
444 444
445std::string_view GetPathWithoutTop(std::string_view path) { 445std::string_view GetPathWithoutTop(std::string_view path) {
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h
index 23c8b1359..59301e7ed 100644
--- a/src/common/fs/path_util.h
+++ b/src/common/fs/path_util.h
@@ -302,7 +302,7 @@ enum class DirectorySeparator {
302 DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash); 302 DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
303 303
304// Gets all of the text up to the last '/' or '\' in the path. 304// Gets all of the text up to the last '/' or '\' in the path.
305[[nodiscard]] std::string_view GetParentPath(std::string_view path); 305[[nodiscard]] std::string GetParentPath(std::string_view path);
306 306
307// Gets all of the text after the first '/' or '\' in the path. 307// Gets all of the text after the first '/' or '\' in the path.
308[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path); 308[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 2f09cade5..23e56c77a 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -359,7 +359,7 @@ private:
359 359
360 void GetActiveChannelCount(HLERequestContext& ctx) { 360 void GetActiveChannelCount(HLERequestContext& ctx) {
361 const auto& sink{system.AudioCore().GetOutputSink()}; 361 const auto& sink{system.AudioCore().GetOutputSink()};
362 u32 channel_count{sink.GetDeviceChannels()}; 362 u32 channel_count{sink.GetSystemChannels()};
363 363
364 LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count); 364 LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);
365 365
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index e7e7c4c28..276d264e1 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -54,6 +54,13 @@ enum class ImageDirectoryId : u32 {
54 SdCard, 54 SdCard,
55}; 55};
56 56
57enum class OpenDirectoryMode : u64 {
58 Directory = (1 << 0),
59 File = (1 << 1),
60 All = Directory | File
61};
62DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode);
63
57class FileSystemController { 64class FileSystemController {
58public: 65public:
59 explicit FileSystemController(Core::System& system_); 66 explicit FileSystemController(Core::System& system_);
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index b1310d6e4..82ecc1b90 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -259,7 +259,7 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
259 259
260class IDirectory final : public ServiceFramework<IDirectory> { 260class IDirectory final : public ServiceFramework<IDirectory> {
261public: 261public:
262 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_) 262 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, OpenDirectoryMode mode)
263 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { 263 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
264 static const FunctionInfo functions[] = { 264 static const FunctionInfo functions[] = {
265 {0, &IDirectory::Read, "Read"}, 265 {0, &IDirectory::Read, "Read"},
@@ -269,8 +269,12 @@ public:
269 269
270 // TODO(DarkLordZach): Verify that this is the correct behavior. 270 // TODO(DarkLordZach): Verify that this is the correct behavior.
271 // Build entry index now to save time later. 271 // Build entry index now to save time later.
272 BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File); 272 if (True(mode & OpenDirectoryMode::Directory)) {
273 BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory); 273 BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
274 }
275 if (True(mode & OpenDirectoryMode::File)) {
276 BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File);
277 }
274 } 278 }
275 279
276private: 280private:
@@ -446,11 +450,9 @@ public:
446 450
447 const auto file_buffer = ctx.ReadBuffer(); 451 const auto file_buffer = ctx.ReadBuffer();
448 const std::string name = Common::StringFromBuffer(file_buffer); 452 const std::string name = Common::StringFromBuffer(file_buffer);
453 const auto mode = rp.PopRaw<OpenDirectoryMode>();
449 454
450 // TODO(Subv): Implement this filter. 455 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode);
451 const u32 filter_flags = rp.Pop<u32>();
452
453 LOG_DEBUG(Service_FS, "called. directory={}, filter={}", name, filter_flags);
454 456
455 FileSys::VirtualDir vfs_dir{}; 457 FileSys::VirtualDir vfs_dir{};
456 auto result = backend.OpenDirectory(&vfs_dir, name); 458 auto result = backend.OpenDirectory(&vfs_dir, name);
@@ -460,7 +462,7 @@ public:
460 return; 462 return;
461 } 463 }
462 464
463 auto directory = std::make_shared<IDirectory>(system, vfs_dir); 465 auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
464 466
465 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 467 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
466 rb.Push(ResultSuccess); 468 rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
index d91886bed..bbe8e06d4 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
@@ -90,6 +90,18 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
90 90
91 LOG_DEBUG(Service_Nvnflinger, "acquiring slot={}", slot); 91 LOG_DEBUG(Service_Nvnflinger, "acquiring slot={}", slot);
92 92
93 // If the front buffer is still being tracked, update its slot state
94 if (core->StillTracking(*front)) {
95 slots[slot].acquire_called = true;
96 slots[slot].needs_cleanup_on_release = false;
97 slots[slot].buffer_state = BufferState::Acquired;
98
99 // TODO: for now, avoid resetting the fence, so that when we next return this
100 // slot to the producer, it will wait for the fence to pass. We should fix this
101 // by properly waiting for the fence in the BufferItemConsumer.
102 // slots[slot].fence = Fence::NoFence();
103 }
104
93 // If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to 105 // If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to
94 // avoid unnecessarily remapping this buffer on the consumer side. 106 // avoid unnecessarily remapping this buffer on the consumer side.
95 if (out_buffer->acquire_called) { 107 if (out_buffer->acquire_called) {
@@ -132,11 +144,28 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
132 ++current; 144 ++current;
133 } 145 }
134 146
135 slots[slot].buffer_state = BufferState::Free; 147 if (slots[slot].buffer_state == BufferState::Acquired) {
148 // TODO: for now, avoid resetting the fence, so that when we next return this
149 // slot to the producer, it can wait for its own fence to pass. We should fix this
150 // by properly waiting for the fence in the BufferItemConsumer.
151 // slots[slot].fence = release_fence;
152 slots[slot].buffer_state = BufferState::Free;
136 153
137 listener = core->connected_producer_listener; 154 listener = core->connected_producer_listener;
138 155
139 LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot); 156 LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot);
157 } else if (slots[slot].needs_cleanup_on_release) {
158 LOG_DEBUG(Service_Nvnflinger, "releasing a stale buffer slot {} (state = {})", slot,
159 slots[slot].buffer_state);
160 slots[slot].needs_cleanup_on_release = false;
161 return Status::StaleBufferSlot;
162 } else {
163 LOG_ERROR(Service_Nvnflinger,
164 "attempted to release buffer slot {} but its state was {}", slot,
165 slots[slot].buffer_state);
166
167 return Status::BadValue;
168 }
140 169
141 core->SignalDequeueCondition(); 170 core->SignalDequeueCondition();
142 } 171 }
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_core.cpp b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp
index 4ed5e5978..5d8c861fa 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_core.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp
@@ -74,6 +74,10 @@ void BufferQueueCore::FreeBufferLocked(s32 slot) {
74 74
75 slots[slot].graphic_buffer.reset(); 75 slots[slot].graphic_buffer.reset();
76 76
77 if (slots[slot].buffer_state == BufferState::Acquired) {
78 slots[slot].needs_cleanup_on_release = true;
79 }
80
77 slots[slot].buffer_state = BufferState::Free; 81 slots[slot].buffer_state = BufferState::Free;
78 slots[slot].frame_number = UINT32_MAX; 82 slots[slot].frame_number = UINT32_MAX;
79 slots[slot].acquire_called = false; 83 slots[slot].acquire_called = false;
diff --git a/src/core/hle/service/nvnflinger/buffer_slot.h b/src/core/hle/service/nvnflinger/buffer_slot.h
index d25bca049..37daca78b 100644
--- a/src/core/hle/service/nvnflinger/buffer_slot.h
+++ b/src/core/hle/service/nvnflinger/buffer_slot.h
@@ -31,6 +31,7 @@ struct BufferSlot final {
31 u64 frame_number{}; 31 u64 frame_number{};
32 Fence fence; 32 Fence fence;
33 bool acquire_called{}; 33 bool acquire_called{};
34 bool needs_cleanup_on_release{};
34 bool attached_by_consumer{}; 35 bool attached_by_consumer{};
35 bool is_preallocated{}; 36 bool is_preallocated{};
36}; 37};
diff --git a/src/tests/video_core/memory_tracker.cpp b/src/tests/video_core/memory_tracker.cpp
index 2dbff21af..618793668 100644
--- a/src/tests/video_core/memory_tracker.cpp
+++ b/src/tests/video_core/memory_tracker.cpp
@@ -23,13 +23,13 @@ constexpr VAddr c = 16 * HIGH_PAGE_SIZE;
23 23
24class RasterizerInterface { 24class RasterizerInterface {
25public: 25public:
26 void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) { 26 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
27 const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS}; 27 const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS};
28 const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >> 28 const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >>
29 Core::Memory::YUZU_PAGEBITS}; 29 Core::Memory::YUZU_PAGEBITS};
30 for (u64 page = page_start; page < page_end; ++page) { 30 for (u64 page = page_start; page < page_end; ++page) {
31 int& value = page_table[page]; 31 int& value = page_table[page];
32 value += (cache ? 1 : -1); 32 value += delta;
33 if (value < 0) { 33 if (value < 0) {
34 throw std::logic_error{"negative page"}; 34 throw std::logic_error{"negative page"};
35 } 35 }
@@ -546,4 +546,4 @@ TEST_CASE("MemoryTracker: Cached write downloads") {
546 REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE)); 546 REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE));
547 memory_track->MarkRegionAsCpuModified(c, WORD); 547 memory_track->MarkRegionAsCpuModified(c, WORD);
548 REQUIRE(rasterizer.Count() == 0); 548 REQUIRE(rasterizer.Count() == 0);
549} 549} \ No newline at end of file
diff --git a/src/video_core/buffer_cache/word_manager.h b/src/video_core/buffer_cache/word_manager.h
index 95b752055..a336bde41 100644
--- a/src/video_core/buffer_cache/word_manager.h
+++ b/src/video_core/buffer_cache/word_manager.h
@@ -473,7 +473,7 @@ private:
473 VAddr addr = cpu_addr + word_index * BYTES_PER_WORD; 473 VAddr addr = cpu_addr + word_index * BYTES_PER_WORD;
474 IteratePages(changed_bits, [&](size_t offset, size_t size) { 474 IteratePages(changed_bits, [&](size_t offset, size_t size) {
475 rasterizer->UpdatePagesCachedCount(addr + offset * BYTES_PER_PAGE, 475 rasterizer->UpdatePagesCachedCount(addr + offset * BYTES_PER_PAGE,
476 size * BYTES_PER_PAGE, add_to_rasterizer); 476 size * BYTES_PER_PAGE, add_to_rasterizer ? 1 : -1);
477 }); 477 });
478 } 478 }
479 479
diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp
index 3c9477f6e..f200a650f 100644
--- a/src/video_core/rasterizer_accelerated.cpp
+++ b/src/video_core/rasterizer_accelerated.cpp
@@ -3,7 +3,6 @@
3 3
4#include <atomic> 4#include <atomic>
5 5
6#include "common/alignment.h"
7#include "common/assert.h" 6#include "common/assert.h"
8#include "common/common_types.h" 7#include "common/common_types.h"
9#include "common/div_ceil.h" 8#include "common/div_ceil.h"
@@ -12,65 +11,61 @@
12 11
13namespace VideoCore { 12namespace VideoCore {
14 13
15static constexpr u16 IdentityValue = 1;
16
17using namespace Core::Memory; 14using namespace Core::Memory;
18 15
19RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) : map{}, cpu_memory{cpu_memory_} { 16RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_)
20 // We are tracking CPU memory, which cannot map more than 39 bits. 17 : cached_pages(std::make_unique<CachedPages>()), cpu_memory{cpu_memory_} {}
21 const VAddr start_address = 0;
22 const VAddr end_address = (1ULL << 39);
23 const IntervalType address_space_interval(start_address, end_address);
24 const auto value = std::make_pair(address_space_interval, IdentityValue);
25
26 map.add(value);
27}
28 18
29RasterizerAccelerated::~RasterizerAccelerated() = default; 19RasterizerAccelerated::~RasterizerAccelerated() = default;
30 20
31void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) { 21void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
32 std::scoped_lock lk{map_lock}; 22 u64 uncache_begin = 0;
33 23 u64 cache_begin = 0;
34 // Align sizes. 24 u64 uncache_bytes = 0;
35 addr = Common::AlignDown(addr, YUZU_PAGESIZE); 25 u64 cache_bytes = 0;
36 size = Common::AlignUp(size, YUZU_PAGESIZE); 26
37 27 std::atomic_thread_fence(std::memory_order_acquire);
38 // Declare the overall interval we are going to operate on. 28 const u64 page_end = Common::DivCeil(addr + size, YUZU_PAGESIZE);
39 const VAddr start_address = addr; 29 for (u64 page = addr >> YUZU_PAGEBITS; page != page_end; ++page) {
40 const VAddr end_address = addr + size; 30 std::atomic_uint16_t& count = cached_pages->at(page >> 2).Count(page);
41 const IntervalType modification_range(start_address, end_address); 31
42 32 if (delta > 0) {
43 // Find the boundaries of where to iterate. 33 ASSERT_MSG(count.load(std::memory_order::relaxed) < UINT16_MAX, "Count may overflow!");
44 const auto lower = map.lower_bound(modification_range); 34 } else if (delta < 0) {
45 const auto upper = map.upper_bound(modification_range); 35 ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!");
46 36 } else {
47 // Iterate over the contained intervals. 37 ASSERT_MSG(false, "Delta must be non-zero!");
48 for (auto it = lower; it != upper; it++) { 38 }
49 // Intersect interval range with modification range.
50 const auto current_range = modification_range & it->first;
51
52 // Calculate the address and size to operate over.
53 const auto current_addr = current_range.lower();
54 const auto current_size = current_range.upper() - current_addr;
55
56 // Get the current value of the range.
57 const auto value = it->second;
58 39
59 if (cache && value == IdentityValue) { 40 // Adds or subtracts 1, as count is a unsigned 8-bit value
60 // If we are going to cache, and the value is not yet referenced, then cache this range. 41 count.fetch_add(static_cast<u16>(delta), std::memory_order_release);
61 cpu_memory.RasterizerMarkRegionCached(current_addr, current_size, true); 42
62 } else if (!cache && value == IdentityValue + 1) { 43 // Assume delta is either -1 or 1
63 // If we are going to uncache, and this is the last reference, then uncache this range. 44 if (count.load(std::memory_order::relaxed) == 0) {
64 cpu_memory.RasterizerMarkRegionCached(current_addr, current_size, false); 45 if (uncache_bytes == 0) {
46 uncache_begin = page;
47 }
48 uncache_bytes += YUZU_PAGESIZE;
49 } else if (uncache_bytes > 0) {
50 cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes,
51 false);
52 uncache_bytes = 0;
53 }
54 if (count.load(std::memory_order::relaxed) == 1 && delta > 0) {
55 if (cache_bytes == 0) {
56 cache_begin = page;
57 }
58 cache_bytes += YUZU_PAGESIZE;
59 } else if (cache_bytes > 0) {
60 cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true);
61 cache_bytes = 0;
65 } 62 }
66 } 63 }
67 64 if (uncache_bytes > 0) {
68 // Update the set. 65 cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes, false);
69 const auto value = std::make_pair(modification_range, IdentityValue); 66 }
70 if (cache) { 67 if (cache_bytes > 0) {
71 map.add(value); 68 cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true);
72 } else {
73 map.subtract(value);
74 } 69 }
75} 70}
76 71
diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h
index f1968f186..e6c0ea87a 100644
--- a/src/video_core/rasterizer_accelerated.h
+++ b/src/video_core/rasterizer_accelerated.h
@@ -3,8 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <mutex> 6#include <array>
7#include <boost/icl/interval_map.hpp> 7#include <atomic>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/rasterizer_interface.h" 10#include "video_core/rasterizer_interface.h"
@@ -21,17 +21,28 @@ public:
21 explicit RasterizerAccelerated(Core::Memory::Memory& cpu_memory_); 21 explicit RasterizerAccelerated(Core::Memory::Memory& cpu_memory_);
22 ~RasterizerAccelerated() override; 22 ~RasterizerAccelerated() override;
23 23
24 void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) override; 24 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
25 25
26private: 26private:
27 using PageIndex = VAddr; 27 class CacheEntry final {
28 using PageReferenceCount = u16; 28 public:
29 CacheEntry() = default;
29 30
30 using IntervalMap = boost::icl::interval_map<PageIndex, PageReferenceCount>; 31 std::atomic_uint16_t& Count(std::size_t page) {
31 using IntervalType = IntervalMap::interval_type; 32 return values[page & 3];
33 }
32 34
33 IntervalMap map; 35 const std::atomic_uint16_t& Count(std::size_t page) const {
34 std::mutex map_lock; 36 return values[page & 3];
37 }
38
39 private:
40 std::array<std::atomic_uint16_t, 4> values{};
41 };
42 static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!");
43
44 using CachedPages = std::array<CacheEntry, 0x2000000>;
45 std::unique_ptr<CachedPages> cached_pages;
35 Core::Memory::Memory& cpu_memory; 46 Core::Memory::Memory& cpu_memory;
36}; 47};
37 48
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index fd42d26b5..af1469147 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -162,7 +162,7 @@ public:
162 } 162 }
163 163
164 /// Increase/decrease the number of object in pages touching the specified region 164 /// Increase/decrease the number of object in pages touching the specified region
165 virtual void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {} 165 virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
166 166
167 /// Initialize disk cached resources for the game being emulated 167 /// Initialize disk cached resources for the game being emulated
168 virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading, 168 virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp
index a109f9cbe..e81cd031b 100644
--- a/src/video_core/shader_cache.cpp
+++ b/src/video_core/shader_cache.cpp
@@ -132,7 +132,7 @@ void ShaderCache::Register(std::unique_ptr<ShaderInfo> data, VAddr addr, size_t
132 132
133 storage.push_back(std::move(data)); 133 storage.push_back(std::move(data));
134 134
135 rasterizer.UpdatePagesCachedCount(addr, size, true); 135 rasterizer.UpdatePagesCachedCount(addr, size, 1);
136} 136}
137 137
138void ShaderCache::InvalidatePagesInRegion(VAddr addr, size_t size) { 138void ShaderCache::InvalidatePagesInRegion(VAddr addr, size_t size) {
@@ -209,7 +209,7 @@ void ShaderCache::UnmarkMemory(Entry* entry) {
209 209
210 const VAddr addr = entry->addr_start; 210 const VAddr addr = entry->addr_start;
211 const size_t size = entry->addr_end - addr; 211 const size_t size = entry->addr_end - addr;
212 rasterizer.UpdatePagesCachedCount(addr, size, false); 212 rasterizer.UpdatePagesCachedCount(addr, size, -1);
213} 213}
214 214
215void ShaderCache::RemoveShadersFromStorage(std::span<ShaderInfo*> removed_shaders) { 215void ShaderCache::RemoveShadersFromStorage(std::span<ShaderInfo*> removed_shaders) {
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index d7941f6a4..0d5a1709f 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -2080,7 +2080,7 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
2080 ASSERT(False(image.flags & ImageFlagBits::Tracked)); 2080 ASSERT(False(image.flags & ImageFlagBits::Tracked));
2081 image.flags |= ImageFlagBits::Tracked; 2081 image.flags |= ImageFlagBits::Tracked;
2082 if (False(image.flags & ImageFlagBits::Sparse)) { 2082 if (False(image.flags & ImageFlagBits::Sparse)) {
2083 rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, true); 2083 rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1);
2084 return; 2084 return;
2085 } 2085 }
2086 if (True(image.flags & ImageFlagBits::Registered)) { 2086 if (True(image.flags & ImageFlagBits::Registered)) {
@@ -2091,13 +2091,13 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
2091 const auto& map = slot_map_views[map_view_id]; 2091 const auto& map = slot_map_views[map_view_id];
2092 const VAddr cpu_addr = map.cpu_addr; 2092 const VAddr cpu_addr = map.cpu_addr;
2093 const std::size_t size = map.size; 2093 const std::size_t size = map.size;
2094 rasterizer.UpdatePagesCachedCount(cpu_addr, size, true); 2094 rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1);
2095 } 2095 }
2096 return; 2096 return;
2097 } 2097 }
2098 ForEachSparseSegment(image, 2098 ForEachSparseSegment(image,
2099 [this]([[maybe_unused]] GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) { 2099 [this]([[maybe_unused]] GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) {
2100 rasterizer.UpdatePagesCachedCount(cpu_addr, size, true); 2100 rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1);
2101 }); 2101 });
2102} 2102}
2103 2103
@@ -2106,7 +2106,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
2106 ASSERT(True(image.flags & ImageFlagBits::Tracked)); 2106 ASSERT(True(image.flags & ImageFlagBits::Tracked));
2107 image.flags &= ~ImageFlagBits::Tracked; 2107 image.flags &= ~ImageFlagBits::Tracked;
2108 if (False(image.flags & ImageFlagBits::Sparse)) { 2108 if (False(image.flags & ImageFlagBits::Sparse)) {
2109 rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, false); 2109 rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, -1);
2110 return; 2110 return;
2111 } 2111 }
2112 ASSERT(True(image.flags & ImageFlagBits::Registered)); 2112 ASSERT(True(image.flags & ImageFlagBits::Registered));
@@ -2117,7 +2117,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
2117 const auto& map = slot_map_views[map_view_id]; 2117 const auto& map = slot_map_views[map_view_id];
2118 const VAddr cpu_addr = map.cpu_addr; 2118 const VAddr cpu_addr = map.cpu_addr;
2119 const std::size_t size = map.size; 2119 const std::size_t size = map.size;
2120 rasterizer.UpdatePagesCachedCount(cpu_addr, size, false); 2120 rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1);
2121 } 2121 }
2122} 2122}
2123 2123
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index dd43f0a0e..c8e871151 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -193,8 +193,8 @@ void ConfigureUi::RequestGameListUpdate() {
193void ConfigureUi::SetConfiguration() { 193void ConfigureUi::SetConfiguration() {
194 ui->theme_combobox->setCurrentIndex( 194 ui->theme_combobox->setCurrentIndex(
195 ui->theme_combobox->findData(QString::fromStdString(UISettings::values.theme))); 195 ui->theme_combobox->findData(QString::fromStdString(UISettings::values.theme)));
196 ui->language_combobox->setCurrentIndex( 196 ui->language_combobox->setCurrentIndex(ui->language_combobox->findData(
197 ui->language_combobox->findData(QString::fromStdString(UISettings::values.language))); 197 QString::fromStdString(UISettings::values.language.GetValue())));
198 ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); 198 ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue());
199 ui->show_compat->setChecked(UISettings::values.show_compat.GetValue()); 199 ui->show_compat->setChecked(UISettings::values.show_compat.GetValue());
200 ui->show_size->setChecked(UISettings::values.show_size.GetValue()); 200 ui->show_size->setChecked(UISettings::values.show_size.GetValue());
diff --git a/src/yuzu/configuration/qt_config.cpp b/src/yuzu/configuration/qt_config.cpp
index 636c5e640..417a43ec5 100644
--- a/src/yuzu/configuration/qt_config.cpp
+++ b/src/yuzu/configuration/qt_config.cpp
@@ -187,7 +187,6 @@ void QtConfig::ReadPathValues() {
187 BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); 187 BeginGroup(Settings::TranslateCategory(Settings::Category::Paths));
188 188
189 UISettings::values.roms_path = ReadStringSetting(std::string("romsPath")); 189 UISettings::values.roms_path = ReadStringSetting(std::string("romsPath"));
190 UISettings::values.symbols_path = ReadStringSetting(std::string("symbolsPath"));
191 UISettings::values.game_dir_deprecated = 190 UISettings::values.game_dir_deprecated =
192 ReadStringSetting(std::string("gameListRootDir"), std::string(".")); 191 ReadStringSetting(std::string("gameListRootDir"), std::string("."));
193 UISettings::values.game_dir_deprecated_deepscan = 192 UISettings::values.game_dir_deprecated_deepscan =
@@ -225,8 +224,6 @@ void QtConfig::ReadPathValues() {
225 UISettings::values.recent_files = 224 UISettings::values.recent_files =
226 QString::fromStdString(ReadStringSetting(std::string("recentFiles"))) 225 QString::fromStdString(ReadStringSetting(std::string("recentFiles")))
227 .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive); 226 .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive);
228 UISettings::values.language =
229 ReadStringSetting(std::string("language"), std::make_optional(std::string("")));
230 227
231 EndGroup(); 228 EndGroup();
232} 229}
@@ -409,7 +406,6 @@ void QtConfig::SavePathValues() {
409 BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); 406 BeginGroup(Settings::TranslateCategory(Settings::Category::Paths));
410 407
411 WriteSetting(std::string("romsPath"), UISettings::values.roms_path); 408 WriteSetting(std::string("romsPath"), UISettings::values.roms_path);
412 WriteSetting(std::string("symbolsPath"), UISettings::values.symbols_path);
413 BeginArray(std::string("gamedirs")); 409 BeginArray(std::string("gamedirs"));
414 for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { 410 for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) {
415 SetArrayIndex(i); 411 SetArrayIndex(i);
@@ -422,7 +418,6 @@ void QtConfig::SavePathValues() {
422 418
423 WriteSetting(std::string("recentFiles"), 419 WriteSetting(std::string("recentFiles"),
424 UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); 420 UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString());
425 WriteSetting(std::string("language"), UISettings::values.language);
426 421
427 EndGroup(); 422 EndGroup();
428} 423}
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index f31ed7ebb..059fcf041 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -5147,12 +5147,12 @@ void GMainWindow::UpdateUITheme() {
5147void GMainWindow::LoadTranslation() { 5147void GMainWindow::LoadTranslation() {
5148 bool loaded; 5148 bool loaded;
5149 5149
5150 if (UISettings::values.language.empty()) { 5150 if (UISettings::values.language.GetValue().empty()) {
5151 // If the selected language is empty, use system locale 5151 // If the selected language is empty, use system locale
5152 loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/")); 5152 loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/"));
5153 } else { 5153 } else {
5154 // Otherwise load from the specified file 5154 // Otherwise load from the specified file
5155 loaded = translator.load(QString::fromStdString(UISettings::values.language), 5155 loaded = translator.load(QString::fromStdString(UISettings::values.language.GetValue()),
5156 QStringLiteral(":/languages/")); 5156 QStringLiteral(":/languages/"));
5157 } 5157 }
5158 5158
@@ -5164,7 +5164,7 @@ void GMainWindow::LoadTranslation() {
5164} 5164}
5165 5165
5166void GMainWindow::OnLanguageChanged(const QString& locale) { 5166void GMainWindow::OnLanguageChanged(const QString& locale) {
5167 if (UISettings::values.language != std::string("en")) { 5167 if (UISettings::values.language.GetValue() != std::string("en")) {
5168 qApp->removeTranslator(&translator); 5168 qApp->removeTranslator(&translator);
5169 } 5169 }
5170 5170
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 549a39e1b..f9906be33 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -154,12 +154,11 @@ struct Values {
154 Setting<u32> screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots}; 154 Setting<u32> screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots};
155 155
156 std::string roms_path; 156 std::string roms_path;
157 std::string symbols_path;
158 std::string game_dir_deprecated; 157 std::string game_dir_deprecated;
159 bool game_dir_deprecated_deepscan; 158 bool game_dir_deprecated_deepscan;
160 QVector<GameDir> game_dirs; 159 QVector<GameDir> game_dirs;
161 QStringList recent_files; 160 QStringList recent_files;
162 std::string language; 161 Setting<std::string> language{linkage, {}, "language", Category::Paths};
163 162
164 std::string theme; 163 std::string theme;
165 164