summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp12
-rw-r--r--src/audio_core/audio_renderer.h2
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/errors.h8
-rw-r--r--src/core/hle/kernel/svc.cpp14
-rw-r--r--src/core/hle/kernel/svc_wrap.h4
-rw-r--r--src/core/hle/kernel/thread.cpp4
-rw-r--r--src/core/hle/service/acc/acc_aa.cpp2
-rw-r--r--src/core/hle/service/acc/acc_aa.h1
-rw-r--r--src/core/hle/service/acc/acc_su.cpp2
-rw-r--r--src/core/hle/service/acc/acc_su.h1
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u0.h1
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u1.h1
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp2
-rw-r--r--src/core/hle/service/acc/profile_manager.h2
-rw-r--r--src/core/hle/service/am/am.cpp23
-rw-r--r--src/core/hle/service/am/am.h12
-rw-r--r--src/core/hle/service/am/applet_ae.cpp2
-rw-r--r--src/core/hle/service/am/applet_ae.h2
-rw-r--r--src/core/hle/service/am/applet_oe.cpp2
-rw-r--r--src/core/hle/service/am/applet_oe.h2
-rw-r--r--src/core/hle/service/am/idle.cpp2
-rw-r--r--src/core/hle/service/am/idle.h1
-rw-r--r--src/core/hle/service/am/omm.cpp2
-rw-r--r--src/core/hle/service/am/omm.h1
-rw-r--r--src/core/hle/service/am/spsm.cpp2
-rw-r--r--src/core/hle/service/am/spsm.h1
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp2
-rw-r--r--src/core/hle/service/aoc/aoc_u.h2
-rw-r--r--src/core/hle/service/apm/apm.cpp3
-rw-r--r--src/core/hle/service/apm/apm.h4
-rw-r--r--src/core/hle/service/apm/interface.cpp4
-rw-r--r--src/core/hle/service/apm/interface.h3
-rw-r--r--src/core/hle/service/audio/audctl.cpp2
-rw-r--r--src/core/hle/service/audio/audctl.h1
-rw-r--r--src/core/hle/service/audio/auddbg.cpp2
-rw-r--r--src/core/hle/service/audio/auddbg.h1
-rw-r--r--src/core/hle/service/audio/audin_a.cpp2
-rw-r--r--src/core/hle/service/audio/audin_a.h1
-rw-r--r--src/core/hle/service/audio/audin_u.cpp2
-rw-r--r--src/core/hle/service/audio/audin_u.h2
-rw-r--r--src/core/hle/service/audio/audio.cpp1
-rw-r--r--src/core/hle/service/audio/audio.h4
-rw-r--r--src/core/hle/service/audio/audout_a.cpp2
-rw-r--r--src/core/hle/service/audio/audout_a.h1
-rw-r--r--src/core/hle/service/audio/audout_u.cpp19
-rw-r--r--src/core/hle/service/audio/audout_u.h19
-rw-r--r--src/core/hle/service/audio/audrec_a.cpp2
-rw-r--r--src/core/hle/service/audio/audrec_a.h1
-rw-r--r--src/core/hle/service/audio/audrec_u.cpp2
-rw-r--r--src/core/hle/service/audio/audrec_u.h2
-rw-r--r--src/core/hle/service/audio/audren_a.cpp2
-rw-r--r--src/core/hle/service/audio/audren_a.h1
-rw-r--r--src/core/hle/service/audio/audren_u.cpp8
-rw-r--r--src/core/hle/service/audio/audren_u.h3
-rw-r--r--src/core/hle/service/audio/codecctl.cpp2
-rw-r--r--src/core/hle/service/audio/codecctl.h2
-rw-r--r--src/core/hle/service/audio/hwopus.cpp7
-rw-r--r--src/core/hle/service/audio/hwopus.h2
-rw-r--r--src/core/hle/service/bcat/bcat.cpp2
-rw-r--r--src/core/hle/service/bcat/bcat.h1
-rw-r--r--src/core/hle/service/bcat/module.cpp2
-rw-r--r--src/core/hle/service/bcat/module.h1
-rw-r--r--src/core/hle/service/fatal/fatal.cpp2
-rw-r--r--src/core/hle/service/fatal/fatal.h1
-rw-r--r--src/core/hle/service/fatal/fatal_p.cpp2
-rw-r--r--src/core/hle/service/fatal/fatal_p.h1
-rw-r--r--src/core/hle/service/fatal/fatal_u.cpp2
-rw-r--r--src/core/hle/service/fatal/fatal_u.h1
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp2
-rw-r--r--src/core/hle/service/filesystem/filesystem.h1
-rw-r--r--src/core/hle/service/filesystem/fsp_ldr.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_ldr.h1
-rw-r--r--src/core/hle/service/filesystem/fsp_pr.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_pr.h1
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h2
-rw-r--r--src/core/hle/service/friend/friend.cpp2
-rw-r--r--src/core/hle/service/friend/friend.h1
-rw-r--r--src/core/hle/service/friend/interface.cpp2
-rw-r--r--src/core/hle/service/friend/interface.h1
-rw-r--r--src/core/hle/service/hid/hid.cpp8
-rw-r--r--src/core/hle/service/hid/irs.cpp4
-rw-r--r--src/core/hle/service/hid/irs.h2
-rw-r--r--src/core/hle/service/hid/xcd.cpp2
-rw-r--r--src/core/hle/service/hid/xcd.h1
-rw-r--r--src/core/hle/service/nfp/nfp.cpp2
-rw-r--r--src/core/hle/service/nfp/nfp.h1
-rw-r--r--src/core/hle/service/nfp/nfp_user.cpp2
-rw-r--r--src/core/hle/service/nfp/nfp_user.h1
-rw-r--r--src/core/hle/service/ns/pl_u.cpp170
-rw-r--r--src/core/hle/service/ns/pl_u.h10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp29
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h21
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h4
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp2
-rw-r--r--src/core/hle/service/nvdrv/interface.h2
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp2
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h2
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.cpp2
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.h2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h2
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp3
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h4
-rw-r--r--src/core/hle/service/pctl/module.cpp2
-rw-r--r--src/core/hle/service/pctl/module.h1
-rw-r--r--src/core/hle/service/pctl/pctl.cpp2
-rw-r--r--src/core/hle/service/pctl/pctl.h1
-rw-r--r--src/core/hle/service/prepo/prepo.cpp63
-rw-r--r--src/core/hle/service/prepo/prepo.h16
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/set/set.cpp2
-rw-r--r--src/core/hle/service/set/set.h2
-rw-r--r--src/core/hle/service/set/set_cal.cpp2
-rw-r--r--src/core/hle/service/set/set_cal.h2
-rw-r--r--src/core/hle/service/set/set_fd.cpp2
-rw-r--r--src/core/hle/service/set/set_fd.h2
-rw-r--r--src/core/hle/service/sockets/bsd.cpp4
-rw-r--r--src/core/hle/service/sockets/bsd.h3
-rw-r--r--src/core/hle/service/sockets/ethc.cpp4
-rw-r--r--src/core/hle/service/sockets/ethc.h2
-rw-r--r--src/core/hle/service/sockets/nsd.cpp2
-rw-r--r--src/core/hle/service/sockets/nsd.h2
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp2
-rw-r--r--src/core/hle/service/sockets/sfdnsres.h2
-rw-r--r--src/core/hle/service/spl/csrng.cpp2
-rw-r--r--src/core/hle/service/spl/csrng.h1
-rw-r--r--src/core/hle/service/spl/module.cpp2
-rw-r--r--src/core/hle/service/spl/module.h1
-rw-r--r--src/core/hle/service/spl/spl.cpp2
-rw-r--r--src/core/hle/service/spl/spl.h1
-rw-r--r--src/core/hle/service/time/interface.cpp2
-rw-r--r--src/core/hle/service/time/interface.h1
-rw-r--r--src/core/hle/service/time/time.cpp2
-rw-r--r--src/core/hle/service/time/time.h1
-rw-r--r--src/core/hle/service/vi/vi.cpp2
-rw-r--r--src/core/hle/service/vi/vi.h1
-rw-r--r--src/core/hle/service/vi/vi_m.cpp2
-rw-r--r--src/core/hle/service/vi/vi_m.h1
-rw-r--r--src/core/hle/service/vi/vi_s.cpp2
-rw-r--r--src/core/hle/service/vi/vi_s.h1
-rw-r--r--src/core/hle/service/vi/vi_u.cpp2
-rw-r--r--src/core/hle/service/vi/vi_u.h1
-rw-r--r--src/core/settings.h2
-rw-r--r--src/input_common/main.cpp12
-rw-r--r--src/input_common/main.h2
-rw-r--r--src/input_common/sdl/sdl.cpp387
-rw-r--r--src/input_common/sdl/sdl.h9
-rw-r--r--src/video_core/command_processor.cpp170
-rw-r--r--src/video_core/command_processor.h17
-rw-r--r--src/video_core/engines/maxwell_3d.cpp6
-rw-r--r--src/video_core/engines/maxwell_3d.h22
-rw-r--r--src/video_core/engines/maxwell_dma.cpp12
-rw-r--r--src/video_core/engines/shader_bytecode.h115
-rw-r--r--src/video_core/gpu.cpp1
-rw-r--r--src/video_core/gpu.h8
-rw-r--r--src/video_core/rasterizer_interface.h3
-rw-r--r--src/video_core/renderer_base.cpp1
-rw-r--r--src/video_core/renderer_base.h1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp207
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h23
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp472
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h64
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp445
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h50
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_state.h8
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.cpp2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp26
-rw-r--r--src/video_core/textures/texture.h12
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu/bootmanager.cpp1
-rw-r--r--src/yuzu/compatibility_list.cpp18
-rw-r--r--src/yuzu/compatibility_list.h17
-rw-r--r--src/yuzu/configuration/configure_general.cpp3
-rw-r--r--src/yuzu/configuration/configure_general.ui7
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp16
-rw-r--r--src/yuzu/configuration/configure_graphics.h1
-rw-r--r--src/yuzu/configuration/configure_graphics.ui21
-rw-r--r--src/yuzu/configuration/configure_input.cpp22
-rw-r--r--src/yuzu/game_list.cpp9
-rw-r--r--src/yuzu/game_list.h10
-rw-r--r--src/yuzu/game_list_p.h11
-rw-r--r--src/yuzu/game_list_worker.cpp6
-rw-r--r--src/yuzu/game_list_worker.h8
-rw-r--r--src/yuzu/main.cpp16
-rw-r--r--src/yuzu/main.h6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp9
-rw-r--r--src/yuzu_cmd/yuzu.cpp5
210 files changed, 2076 insertions, 957 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 397b107f5..a75cd3be5 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -17,10 +17,10 @@ AudioRenderer::AudioRenderer(AudioRendererParameter params,
17 Kernel::SharedPtr<Kernel::Event> buffer_event) 17 Kernel::SharedPtr<Kernel::Event> buffer_event)
18 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) { 18 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) {
19 19
20 audio_core = std::make_unique<AudioCore::AudioOut>(); 20 audio_out = std::make_unique<AudioCore::AudioOut>();
21 stream = audio_core->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer", 21 stream = audio_out->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer",
22 [=]() { buffer_event->Signal(); }); 22 [=]() { buffer_event->Signal(); });
23 audio_core->StartStream(stream); 23 audio_out->StartStream(stream);
24 24
25 QueueMixedBuffer(0); 25 QueueMixedBuffer(0);
26 QueueMixedBuffer(1); 26 QueueMixedBuffer(1);
@@ -236,11 +236,11 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
236 } 236 }
237 } 237 }
238 } 238 }
239 audio_core->QueueBuffer(stream, tag, std::move(buffer)); 239 audio_out->QueueBuffer(stream, tag, std::move(buffer));
240} 240}
241 241
242void AudioRenderer::ReleaseAndQueueBuffers() { 242void AudioRenderer::ReleaseAndQueueBuffers() {
243 const auto released_buffers{audio_core->GetTagsAndReleaseBuffers(stream, 2)}; 243 const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream, 2)};
244 for (const auto& tag : released_buffers) { 244 for (const auto& tag : released_buffers) {
245 QueueMixedBuffer(tag); 245 QueueMixedBuffer(tag);
246 } 246 }
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index eba67f28e..6d069d693 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -204,7 +204,7 @@ private:
204 AudioRendererParameter worker_params; 204 AudioRendererParameter worker_params;
205 Kernel::SharedPtr<Kernel::Event> buffer_event; 205 Kernel::SharedPtr<Kernel::Event> buffer_event;
206 std::vector<VoiceState> voices; 206 std::vector<VoiceState> voices;
207 std::unique_ptr<AudioCore::AudioOut> audio_core; 207 std::unique_ptr<AudioCore::AudioOut> audio_out;
208 AudioCore::StreamPtr stream; 208 AudioCore::StreamPtr stream;
209}; 209};
210 210
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 7ddc87539..26f727d96 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -388,7 +388,7 @@ add_library(core STATIC
388create_target_directory_groups(core) 388create_target_directory_groups(core)
389 389
390target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 390target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
391target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn) 391target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn open_source_archives)
392 392
393if (ARCHITECTURE_x86_64) 393if (ARCHITECTURE_x86_64)
394 target_sources(core PRIVATE 394 target_sources(core PRIVATE
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index 4054d5db6..ad39c8271 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -21,6 +21,7 @@ enum {
21 HandleTableFull = 105, 21 HandleTableFull = 105,
22 InvalidMemoryState = 106, 22 InvalidMemoryState = 106,
23 InvalidMemoryPermissions = 108, 23 InvalidMemoryPermissions = 108,
24 InvalidThreadPriority = 112,
24 InvalidProcessorId = 113, 25 InvalidProcessorId = 113,
25 InvalidHandle = 114, 26 InvalidHandle = 114,
26 InvalidCombination = 116, 27 InvalidCombination = 116,
@@ -36,7 +37,7 @@ enum {
36// WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always 37// WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always
37// double check that the code matches before re-using the constant. 38// double check that the code matches before re-using the constant.
38 39
39// TODO(bunnei): Replace these with correct errors for Switch OS 40// TODO(bunnei): Replace -1 with correct errors for Switch OS
40constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull); 41constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull);
41constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1); 42constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1);
42constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge); 43constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge);
@@ -53,15 +54,16 @@ constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::In
53constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, 54constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
54 ErrCodes::InvalidMemoryPermissions); 55 ErrCodes::InvalidMemoryPermissions);
55constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); 56constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
57constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
56constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); 58constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
59constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
60 ErrCodes::InvalidThreadPriority);
57constexpr ResultCode ERR_INVALID_POINTER(-1); 61constexpr ResultCode ERR_INVALID_POINTER(-1);
58constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); 62constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1);
59constexpr ResultCode ERR_NOT_AUTHORIZED(-1); 63constexpr ResultCode ERR_NOT_AUTHORIZED(-1);
60/// Alternate code returned instead of ERR_INVALID_HANDLE in some code paths. 64/// Alternate code returned instead of ERR_INVALID_HANDLE in some code paths.
61constexpr ResultCode ERR_INVALID_HANDLE_OS(-1); 65constexpr ResultCode ERR_INVALID_HANDLE_OS(-1);
62constexpr ResultCode ERR_NOT_FOUND(-1); 66constexpr ResultCode ERR_NOT_FOUND(-1);
63constexpr ResultCode ERR_OUT_OF_RANGE(-1);
64constexpr ResultCode ERR_OUT_OF_RANGE_KERNEL(-1);
65constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout); 67constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout);
66/// Returned when Accept() is called on a port with no sessions to be accepted. 68/// Returned when Accept() is called on a port with no sessions to be accepted.
67constexpr ResultCode ERR_NO_PENDING_SESSIONS(-1); 69constexpr ResultCode ERR_NO_PENDING_SESSIONS(-1);
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 1c9373ed8..f500fd2e7 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -273,7 +273,11 @@ static void Break(u64 reason, u64 info1, u64 info2) {
273} 273}
274 274
275/// Used to output a message on a debug hardware unit - does nothing on a retail unit 275/// Used to output a message on a debug hardware unit - does nothing on a retail unit
276static void OutputDebugString(VAddr address, s32 len) { 276static void OutputDebugString(VAddr address, u64 len) {
277 if (len == 0) {
278 return;
279 }
280
277 std::string str(len, '\0'); 281 std::string str(len, '\0');
278 Memory::ReadBlock(address, str.data(), str.size()); 282 Memory::ReadBlock(address, str.data(), str.size());
279 LOG_DEBUG(Debug_Emulated, "{}", str); 283 LOG_DEBUG(Debug_Emulated, "{}", str);
@@ -378,7 +382,7 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) {
378/// Sets the priority for the specified thread 382/// Sets the priority for the specified thread
379static ResultCode SetThreadPriority(Handle handle, u32 priority) { 383static ResultCode SetThreadPriority(Handle handle, u32 priority) {
380 if (priority > THREADPRIO_LOWEST) { 384 if (priority > THREADPRIO_LOWEST) {
381 return ERR_OUT_OF_RANGE; 385 return ERR_INVALID_THREAD_PRIORITY;
382 } 386 }
383 387
384 auto& kernel = Core::System::GetInstance().Kernel(); 388 auto& kernel = Core::System::GetInstance().Kernel();
@@ -523,7 +527,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
523 std::string name = fmt::format("unknown-{:X}", entry_point); 527 std::string name = fmt::format("unknown-{:X}", entry_point);
524 528
525 if (priority > THREADPRIO_LOWEST) { 529 if (priority > THREADPRIO_LOWEST) {
526 return ERR_OUT_OF_RANGE; 530 return ERR_INVALID_THREAD_PRIORITY;
527 } 531 }
528 532
529 SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; 533 SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
@@ -544,8 +548,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
544 case THREADPROCESSORID_3: 548 case THREADPROCESSORID_3:
545 break; 549 break;
546 default: 550 default:
547 ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id); 551 LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id);
548 break; 552 return ERR_INVALID_PROCESSOR_ID;
549 } 553 }
550 554
551 auto& kernel = Core::System::GetInstance().Kernel(); 555 auto& kernel = Core::System::GetInstance().Kernel();
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 79c3fe31b..1eda5f879 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -222,9 +222,9 @@ void SvcWrap() {
222 func((s64)PARAM(0)); 222 func((s64)PARAM(0));
223} 223}
224 224
225template <void func(u64, s32 len)> 225template <void func(u64, u64 len)>
226void SvcWrap() { 226void SvcWrap() {
227 func(PARAM(0), (s32)(PARAM(1) & 0xFFFFFFFF)); 227 func(PARAM(0), PARAM(1));
228} 228}
229 229
230template <void func(u64, u64, u64)> 230template <void func(u64, u64, u64)>
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 3d10d9af2..3f12a84dc 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -227,12 +227,12 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
227 // Check if priority is in ranged. Lowest priority -> highest priority id. 227 // Check if priority is in ranged. Lowest priority -> highest priority id.
228 if (priority > THREADPRIO_LOWEST) { 228 if (priority > THREADPRIO_LOWEST) {
229 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); 229 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
230 return ERR_OUT_OF_RANGE; 230 return ERR_INVALID_THREAD_PRIORITY;
231 } 231 }
232 232
233 if (processor_id > THREADPROCESSORID_MAX) { 233 if (processor_id > THREADPROCESSORID_MAX) {
234 LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); 234 LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id);
235 return ERR_OUT_OF_RANGE_KERNEL; 235 return ERR_INVALID_PROCESSOR_ID;
236 } 236 }
237 237
238 // TODO(yuriks): Other checks, returning 0xD9001BEA 238 // TODO(yuriks): Other checks, returning 0xD9001BEA
diff --git a/src/core/hle/service/acc/acc_aa.cpp b/src/core/hle/service/acc/acc_aa.cpp
index 9bd595a37..e84d9f7cf 100644
--- a/src/core/hle/service/acc/acc_aa.cpp
+++ b/src/core/hle/service/acc/acc_aa.cpp
@@ -18,4 +18,6 @@ ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
18 RegisterHandlers(functions); 18 RegisterHandlers(functions);
19} 19}
20 20
21ACC_AA::~ACC_AA() = default;
22
21} // namespace Service::Account 23} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_aa.h b/src/core/hle/service/acc/acc_aa.h
index 2e08c781a..9edb0421b 100644
--- a/src/core/hle/service/acc/acc_aa.h
+++ b/src/core/hle/service/acc/acc_aa.h
@@ -12,6 +12,7 @@ class ACC_AA final : public Module::Interface {
12public: 12public:
13 explicit ACC_AA(std::shared_ptr<Module> module, 13 explicit ACC_AA(std::shared_ptr<Module> module,
14 std::shared_ptr<ProfileManager> profile_manager); 14 std::shared_ptr<ProfileManager> profile_manager);
15 ~ACC_AA() override;
15}; 16};
16 17
17} // namespace Service::Account 18} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index 0218ee859..ad455c3a7 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -51,4 +51,6 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
51 RegisterHandlers(functions); 51 RegisterHandlers(functions);
52} 52}
53 53
54ACC_SU::~ACC_SU() = default;
55
54} // namespace Service::Account 56} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_su.h b/src/core/hle/service/acc/acc_su.h
index 79a47d88d..a3eb885bf 100644
--- a/src/core/hle/service/acc/acc_su.h
+++ b/src/core/hle/service/acc/acc_su.h
@@ -13,6 +13,7 @@ class ACC_SU final : public Module::Interface {
13public: 13public:
14 explicit ACC_SU(std::shared_ptr<Module> module, 14 explicit ACC_SU(std::shared_ptr<Module> module,
15 std::shared_ptr<ProfileManager> profile_manager); 15 std::shared_ptr<ProfileManager> profile_manager);
16 ~ACC_SU() override;
16}; 17};
17 18
18} // namespace Account 19} // namespace Account
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index 84a4d05b8..72d4adf35 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -31,4 +31,6 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
31 RegisterHandlers(functions); 31 RegisterHandlers(functions);
32} 32}
33 33
34ACC_U0::~ACC_U0() = default;
35
34} // namespace Service::Account 36} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_u0.h b/src/core/hle/service/acc/acc_u0.h
index e8a114f99..a1290e0bd 100644
--- a/src/core/hle/service/acc/acc_u0.h
+++ b/src/core/hle/service/acc/acc_u0.h
@@ -12,6 +12,7 @@ class ACC_U0 final : public Module::Interface {
12public: 12public:
13 explicit ACC_U0(std::shared_ptr<Module> module, 13 explicit ACC_U0(std::shared_ptr<Module> module,
14 std::shared_ptr<ProfileManager> profile_manager); 14 std::shared_ptr<ProfileManager> profile_manager);
15 ~ACC_U0() override;
15}; 16};
16 17
17} // namespace Service::Account 18} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index 495693949..d480f08e5 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -38,4 +38,6 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
38 RegisterHandlers(functions); 38 RegisterHandlers(functions);
39} 39}
40 40
41ACC_U1::~ACC_U1() = default;
42
41} // namespace Service::Account 43} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_u1.h b/src/core/hle/service/acc/acc_u1.h
index a77520e6f..9e79daee3 100644
--- a/src/core/hle/service/acc/acc_u1.h
+++ b/src/core/hle/service/acc/acc_u1.h
@@ -12,6 +12,7 @@ class ACC_U1 final : public Module::Interface {
12public: 12public:
13 explicit ACC_U1(std::shared_ptr<Module> module, 13 explicit ACC_U1(std::shared_ptr<Module> module,
14 std::shared_ptr<ProfileManager> profile_manager); 14 std::shared_ptr<ProfileManager> profile_manager);
15 ~ACC_U1() override;
15}; 16};
16 17
17} // namespace Service::Account 18} // namespace Service::Account
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index e0b03d763..4ccebef23 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -29,6 +29,8 @@ ProfileManager::ProfileManager() {
29 OpenUser(user_uuid); 29 OpenUser(user_uuid);
30} 30}
31 31
32ProfileManager::~ProfileManager() = default;
33
32/// After a users creation it needs to be "registered" to the system. AddToProfiles handles the 34/// After a users creation it needs to be "registered" to the system. AddToProfiles handles the
33/// internal management of the users profiles 35/// internal management of the users profiles
34boost::optional<size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) { 36boost::optional<size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) {
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 52967844d..cd8df93a5 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -82,6 +82,8 @@ static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase is an invalid size");
82class ProfileManager { 82class ProfileManager {
83public: 83public:
84 ProfileManager(); // TODO(ogniK): Load from system save 84 ProfileManager(); // TODO(ogniK): Load from system save
85 ~ProfileManager();
86
85 ResultCode AddUser(const ProfileInfo& user); 87 ResultCode AddUser(const ProfileInfo& user);
86 ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username); 88 ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username);
87 ResultCode CreateNewUser(UUID uuid, const std::string& username); 89 ResultCode CreateNewUser(UUID uuid, const std::string& username);
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 818c03e0f..a57ed3042 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -35,6 +35,8 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") {
35 RegisterHandlers(functions); 35 RegisterHandlers(functions);
36} 36}
37 37
38IWindowController::~IWindowController() = default;
39
38void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) { 40void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {
39 LOG_WARNING(Service_AM, "(STUBBED) called"); 41 LOG_WARNING(Service_AM, "(STUBBED) called");
40 IPC::ResponseBuilder rb{ctx, 4}; 42 IPC::ResponseBuilder rb{ctx, 4};
@@ -61,6 +63,8 @@ IAudioController::IAudioController() : ServiceFramework("IAudioController") {
61 RegisterHandlers(functions); 63 RegisterHandlers(functions);
62} 64}
63 65
66IAudioController::~IAudioController() = default;
67
64void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) { 68void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
65 LOG_WARNING(Service_AM, "(STUBBED) called"); 69 LOG_WARNING(Service_AM, "(STUBBED) called");
66 IPC::ResponseBuilder rb{ctx, 2}; 70 IPC::ResponseBuilder rb{ctx, 2};
@@ -116,7 +120,10 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController"
116 RegisterHandlers(functions); 120 RegisterHandlers(functions);
117} 121}
118 122
123IDisplayController::~IDisplayController() = default;
124
119IDebugFunctions::IDebugFunctions() : ServiceFramework("IDebugFunctions") {} 125IDebugFunctions::IDebugFunctions() : ServiceFramework("IDebugFunctions") {}
126IDebugFunctions::~IDebugFunctions() = default;
120 127
121ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 128ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
122 : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) { 129 : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) {
@@ -165,6 +172,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
165 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); 172 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent");
166} 173}
167 174
175ISelfController::~ISelfController() = default;
176
168void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { 177void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
169 // Takes 3 input u8s with each field located immediately after the previous u8, these are 178 // Takes 3 input u8s with each field located immediately after the previous u8, these are
170 // bool flags. No output. 179 // bool flags. No output.
@@ -337,6 +346,8 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
337 event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event"); 346 event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
338} 347}
339 348
349ICommonStateGetter::~ICommonStateGetter() = default;
350
340void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { 351void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
341 IPC::ResponseBuilder rb{ctx, 3}; 352 IPC::ResponseBuilder rb{ctx, 3};
342 rb.Push(RESULT_SUCCESS); 353 rb.Push(RESULT_SUCCESS);
@@ -573,6 +584,8 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple
573 RegisterHandlers(functions); 584 RegisterHandlers(functions);
574} 585}
575 586
587ILibraryAppletCreator::~ILibraryAppletCreator() = default;
588
576void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { 589void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
577 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 590 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
578 591
@@ -638,6 +651,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
638 RegisterHandlers(functions); 651 RegisterHandlers(functions);
639} 652}
640 653
654IApplicationFunctions::~IApplicationFunctions() = default;
655
641void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { 656void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
642 constexpr std::array<u8, 0x88> data{{ 657 constexpr std::array<u8, 0x88> data{{
643 0xca, 0x97, 0x94, 0xc7, // Magic 658 0xca, 0x97, 0x94, 0xc7, // Magic
@@ -760,6 +775,8 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
760 RegisterHandlers(functions); 775 RegisterHandlers(functions);
761} 776}
762 777
778IHomeMenuFunctions::~IHomeMenuFunctions() = default;
779
763void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { 780void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) {
764 IPC::ResponseBuilder rb{ctx, 2}; 781 IPC::ResponseBuilder rb{ctx, 2};
765 rb.Push(RESULT_SUCCESS); 782 rb.Push(RESULT_SUCCESS);
@@ -783,6 +800,8 @@ IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStat
783 RegisterHandlers(functions); 800 RegisterHandlers(functions);
784} 801}
785 802
803IGlobalStateController::~IGlobalStateController() = default;
804
786IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") { 805IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") {
787 static const FunctionInfo functions[] = { 806 static const FunctionInfo functions[] = {
788 {0, nullptr, "CreateApplication"}, 807 {0, nullptr, "CreateApplication"},
@@ -793,6 +812,8 @@ IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreat
793 RegisterHandlers(functions); 812 RegisterHandlers(functions);
794} 813}
795 814
815IApplicationCreator::~IApplicationCreator() = default;
816
796IProcessWindingController::IProcessWindingController() 817IProcessWindingController::IProcessWindingController()
797 : ServiceFramework("IProcessWindingController") { 818 : ServiceFramework("IProcessWindingController") {
798 static const FunctionInfo functions[] = { 819 static const FunctionInfo functions[] = {
@@ -807,4 +828,6 @@ IProcessWindingController::IProcessWindingController()
807 }; 828 };
808 RegisterHandlers(functions); 829 RegisterHandlers(functions);
809} 830}
831
832IProcessWindingController::~IProcessWindingController() = default;
810} // namespace Service::AM 833} // namespace Service::AM
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 9e8bb4e43..fd9ae296b 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -42,6 +42,7 @@ enum SystemLanguage {
42class IWindowController final : public ServiceFramework<IWindowController> { 42class IWindowController final : public ServiceFramework<IWindowController> {
43public: 43public:
44 IWindowController(); 44 IWindowController();
45 ~IWindowController() override;
45 46
46private: 47private:
47 void GetAppletResourceUserId(Kernel::HLERequestContext& ctx); 48 void GetAppletResourceUserId(Kernel::HLERequestContext& ctx);
@@ -51,6 +52,7 @@ private:
51class IAudioController final : public ServiceFramework<IAudioController> { 52class IAudioController final : public ServiceFramework<IAudioController> {
52public: 53public:
53 IAudioController(); 54 IAudioController();
55 ~IAudioController() override;
54 56
55private: 57private:
56 void SetExpectedMasterVolume(Kernel::HLERequestContext& ctx); 58 void SetExpectedMasterVolume(Kernel::HLERequestContext& ctx);
@@ -63,16 +65,19 @@ private:
63class IDisplayController final : public ServiceFramework<IDisplayController> { 65class IDisplayController final : public ServiceFramework<IDisplayController> {
64public: 66public:
65 IDisplayController(); 67 IDisplayController();
68 ~IDisplayController() override;
66}; 69};
67 70
68class IDebugFunctions final : public ServiceFramework<IDebugFunctions> { 71class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
69public: 72public:
70 IDebugFunctions(); 73 IDebugFunctions();
74 ~IDebugFunctions() override;
71}; 75};
72 76
73class ISelfController final : public ServiceFramework<ISelfController> { 77class ISelfController final : public ServiceFramework<ISelfController> {
74public: 78public:
75 explicit ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); 79 explicit ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
80 ~ISelfController() override;
76 81
77private: 82private:
78 void SetFocusHandlingMode(Kernel::HLERequestContext& ctx); 83 void SetFocusHandlingMode(Kernel::HLERequestContext& ctx);
@@ -98,6 +103,7 @@ private:
98class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { 103class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
99public: 104public:
100 ICommonStateGetter(); 105 ICommonStateGetter();
106 ~ICommonStateGetter() override;
101 107
102private: 108private:
103 enum class FocusState : u8 { 109 enum class FocusState : u8 {
@@ -124,6 +130,7 @@ private:
124class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { 130class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
125public: 131public:
126 ILibraryAppletCreator(); 132 ILibraryAppletCreator();
133 ~ILibraryAppletCreator() override;
127 134
128private: 135private:
129 void CreateLibraryApplet(Kernel::HLERequestContext& ctx); 136 void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
@@ -133,6 +140,7 @@ private:
133class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { 140class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
134public: 141public:
135 IApplicationFunctions(); 142 IApplicationFunctions();
143 ~IApplicationFunctions() override;
136 144
137private: 145private:
138 void PopLaunchParameter(Kernel::HLERequestContext& ctx); 146 void PopLaunchParameter(Kernel::HLERequestContext& ctx);
@@ -150,6 +158,7 @@ private:
150class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { 158class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
151public: 159public:
152 IHomeMenuFunctions(); 160 IHomeMenuFunctions();
161 ~IHomeMenuFunctions() override;
153 162
154private: 163private:
155 void RequestToGetForeground(Kernel::HLERequestContext& ctx); 164 void RequestToGetForeground(Kernel::HLERequestContext& ctx);
@@ -158,16 +167,19 @@ private:
158class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { 167class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
159public: 168public:
160 IGlobalStateController(); 169 IGlobalStateController();
170 ~IGlobalStateController() override;
161}; 171};
162 172
163class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { 173class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
164public: 174public:
165 IApplicationCreator(); 175 IApplicationCreator();
176 ~IApplicationCreator() override;
166}; 177};
167 178
168class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { 179class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
169public: 180public:
170 IProcessWindingController(); 181 IProcessWindingController();
182 ~IProcessWindingController() override;
171}; 183};
172 184
173/// Registers all AM services with the specified service manager. 185/// Registers all AM services with the specified service manager.
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index 7cebc918a..4296c255e 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -222,4 +222,6 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
222 RegisterHandlers(functions); 222 RegisterHandlers(functions);
223} 223}
224 224
225AppletAE::~AppletAE() = default;
226
225} // namespace Service::AM 227} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index bdc57b9bc..1ed77baa4 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -18,7 +18,7 @@ namespace AM {
18class AppletAE final : public ServiceFramework<AppletAE> { 18class AppletAE final : public ServiceFramework<AppletAE> {
19public: 19public:
20 explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); 20 explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
21 ~AppletAE() = default; 21 ~AppletAE() override;
22 22
23private: 23private:
24 void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx); 24 void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index beea7d19b..e45cf6e20 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -103,4 +103,6 @@ AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
103 RegisterHandlers(functions); 103 RegisterHandlers(functions);
104} 104}
105 105
106AppletOE::~AppletOE() = default;
107
106} // namespace Service::AM 108} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index c52e2a322..60cfdfd9d 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -18,7 +18,7 @@ namespace AM {
18class AppletOE final : public ServiceFramework<AppletOE> { 18class AppletOE final : public ServiceFramework<AppletOE> {
19public: 19public:
20 explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); 20 explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
21 ~AppletOE() = default; 21 ~AppletOE() override;
22 22
23private: 23private:
24 void OpenApplicationProxy(Kernel::HLERequestContext& ctx); 24 void OpenApplicationProxy(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp
index af46e9494..0e3088bc8 100644
--- a/src/core/hle/service/am/idle.cpp
+++ b/src/core/hle/service/am/idle.cpp
@@ -21,4 +21,6 @@ IdleSys::IdleSys() : ServiceFramework{"idle:sys"} {
21 RegisterHandlers(functions); 21 RegisterHandlers(functions);
22} 22}
23 23
24IdleSys::~IdleSys() = default;
25
24} // namespace Service::AM 26} // namespace Service::AM
diff --git a/src/core/hle/service/am/idle.h b/src/core/hle/service/am/idle.h
index 1eb68d2c9..c44e856b1 100644
--- a/src/core/hle/service/am/idle.h
+++ b/src/core/hle/service/am/idle.h
@@ -11,6 +11,7 @@ namespace Service::AM {
11class IdleSys final : public ServiceFramework<IdleSys> { 11class IdleSys final : public ServiceFramework<IdleSys> {
12public: 12public:
13 explicit IdleSys(); 13 explicit IdleSys();
14 ~IdleSys() override;
14}; 15};
15 16
16} // namespace Service::AM 17} // namespace Service::AM
diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp
index 447fe8669..1c37f849f 100644
--- a/src/core/hle/service/am/omm.cpp
+++ b/src/core/hle/service/am/omm.cpp
@@ -39,4 +39,6 @@ OMM::OMM() : ServiceFramework{"omm"} {
39 RegisterHandlers(functions); 39 RegisterHandlers(functions);
40} 40}
41 41
42OMM::~OMM() = default;
43
42} // namespace Service::AM 44} // namespace Service::AM
diff --git a/src/core/hle/service/am/omm.h b/src/core/hle/service/am/omm.h
index 49e5d331c..59dc91b72 100644
--- a/src/core/hle/service/am/omm.h
+++ b/src/core/hle/service/am/omm.h
@@ -11,6 +11,7 @@ namespace Service::AM {
11class OMM final : public ServiceFramework<OMM> { 11class OMM final : public ServiceFramework<OMM> {
12public: 12public:
13 explicit OMM(); 13 explicit OMM();
14 ~OMM() override;
14}; 15};
15 16
16} // namespace Service::AM 17} // namespace Service::AM
diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp
index a05d433d0..003ee8667 100644
--- a/src/core/hle/service/am/spsm.cpp
+++ b/src/core/hle/service/am/spsm.cpp
@@ -27,4 +27,6 @@ SPSM::SPSM() : ServiceFramework{"spsm"} {
27 RegisterHandlers(functions); 27 RegisterHandlers(functions);
28} 28}
29 29
30SPSM::~SPSM() = default;
31
30} // namespace Service::AM 32} // namespace Service::AM
diff --git a/src/core/hle/service/am/spsm.h b/src/core/hle/service/am/spsm.h
index 57dde62e1..3a0b979fa 100644
--- a/src/core/hle/service/am/spsm.h
+++ b/src/core/hle/service/am/spsm.h
@@ -11,6 +11,7 @@ namespace Service::AM {
11class SPSM final : public ServiceFramework<SPSM> { 11class SPSM final : public ServiceFramework<SPSM> {
12public: 12public:
13 explicit SPSM(); 13 explicit SPSM();
14 ~SPSM() override;
14}; 15};
15 16
16} // namespace Service::AM 17} // namespace Service::AM
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 6e7438580..d9eeac9ec 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -23,6 +23,8 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u") {
23 RegisterHandlers(functions); 23 RegisterHandlers(functions);
24} 24}
25 25
26AOC_U::~AOC_U() = default;
27
26void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { 28void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
27 IPC::ResponseBuilder rb{ctx, 4}; 29 IPC::ResponseBuilder rb{ctx, 4};
28 rb.Push(RESULT_SUCCESS); 30 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index 17d48ef30..29ce8f488 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -11,7 +11,7 @@ namespace Service::AOC {
11class AOC_U final : public ServiceFramework<AOC_U> { 11class AOC_U final : public ServiceFramework<AOC_U> {
12public: 12public:
13 AOC_U(); 13 AOC_U();
14 ~AOC_U() = default; 14 ~AOC_U() override;
15 15
16private: 16private:
17 void CountAddOnContent(Kernel::HLERequestContext& ctx); 17 void CountAddOnContent(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp
index 4109cb7f7..f3c09bbb1 100644
--- a/src/core/hle/service/apm/apm.cpp
+++ b/src/core/hle/service/apm/apm.cpp
@@ -9,6 +9,9 @@
9 9
10namespace Service::APM { 10namespace Service::APM {
11 11
12Module::Module() = default;
13Module::~Module() = default;
14
12void InstallInterfaces(SM::ServiceManager& service_manager) { 15void InstallInterfaces(SM::ServiceManager& service_manager) {
13 auto module_ = std::make_shared<Module>(); 16 auto module_ = std::make_shared<Module>();
14 std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager); 17 std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager);
diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h
index 90a80d51b..4d7d5bb7c 100644
--- a/src/core/hle/service/apm/apm.h
+++ b/src/core/hle/service/apm/apm.h
@@ -15,8 +15,8 @@ enum class PerformanceMode : u8 {
15 15
16class Module final { 16class Module final {
17public: 17public:
18 Module() = default; 18 Module();
19 ~Module() = default; 19 ~Module();
20}; 20};
21 21
22/// Registers all AM services with the specified service manager. 22/// Registers all AM services with the specified service manager.
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index 4cd8132f5..c22bd3859 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -70,6 +70,8 @@ APM::APM(std::shared_ptr<Module> apm, const char* name)
70 RegisterHandlers(functions); 70 RegisterHandlers(functions);
71} 71}
72 72
73APM::~APM() = default;
74
73void APM::OpenSession(Kernel::HLERequestContext& ctx) { 75void APM::OpenSession(Kernel::HLERequestContext& ctx) {
74 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 76 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
75 rb.Push(RESULT_SUCCESS); 77 rb.Push(RESULT_SUCCESS);
@@ -93,6 +95,8 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
93 RegisterHandlers(functions); 95 RegisterHandlers(functions);
94} 96}
95 97
98APM_Sys::~APM_Sys() = default;
99
96void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { 100void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
97 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 101 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
98 rb.Push(RESULT_SUCCESS); 102 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h
index d14264ad7..773541aa4 100644
--- a/src/core/hle/service/apm/interface.h
+++ b/src/core/hle/service/apm/interface.h
@@ -11,7 +11,7 @@ namespace Service::APM {
11class APM final : public ServiceFramework<APM> { 11class APM final : public ServiceFramework<APM> {
12public: 12public:
13 explicit APM(std::shared_ptr<Module> apm, const char* name); 13 explicit APM(std::shared_ptr<Module> apm, const char* name);
14 ~APM() = default; 14 ~APM() override;
15 15
16private: 16private:
17 void OpenSession(Kernel::HLERequestContext& ctx); 17 void OpenSession(Kernel::HLERequestContext& ctx);
@@ -22,6 +22,7 @@ private:
22class APM_Sys final : public ServiceFramework<APM_Sys> { 22class APM_Sys final : public ServiceFramework<APM_Sys> {
23public: 23public:
24 explicit APM_Sys(); 24 explicit APM_Sys();
25 ~APM_Sys() override;
25 26
26private: 27private:
27 void GetPerformanceEvent(Kernel::HLERequestContext& ctx); 28 void GetPerformanceEvent(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp
index 37c3fdcac..b6b71f966 100644
--- a/src/core/hle/service/audio/audctl.cpp
+++ b/src/core/hle/service/audio/audctl.cpp
@@ -42,4 +42,6 @@ AudCtl::AudCtl() : ServiceFramework{"audctl"} {
42 RegisterHandlers(functions); 42 RegisterHandlers(functions);
43} 43}
44 44
45AudCtl::~AudCtl() = default;
46
45} // namespace Service::Audio 47} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h
index ed837bdf2..9d2d9e83b 100644
--- a/src/core/hle/service/audio/audctl.h
+++ b/src/core/hle/service/audio/audctl.h
@@ -11,6 +11,7 @@ namespace Service::Audio {
11class AudCtl final : public ServiceFramework<AudCtl> { 11class AudCtl final : public ServiceFramework<AudCtl> {
12public: 12public:
13 explicit AudCtl(); 13 explicit AudCtl();
14 ~AudCtl() override;
14}; 15};
15 16
16} // namespace Service::Audio 17} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/auddbg.cpp b/src/core/hle/service/audio/auddbg.cpp
index b08c21a20..8fff3e4b4 100644
--- a/src/core/hle/service/audio/auddbg.cpp
+++ b/src/core/hle/service/audio/auddbg.cpp
@@ -17,4 +17,6 @@ AudDbg::AudDbg(const char* name) : ServiceFramework{name} {
17 RegisterHandlers(functions); 17 RegisterHandlers(functions);
18} 18}
19 19
20AudDbg::~AudDbg() = default;
21
20} // namespace Service::Audio 22} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/auddbg.h b/src/core/hle/service/audio/auddbg.h
index a2f540b75..6689f4759 100644
--- a/src/core/hle/service/audio/auddbg.h
+++ b/src/core/hle/service/audio/auddbg.h
@@ -11,6 +11,7 @@ namespace Service::Audio {
11class AudDbg final : public ServiceFramework<AudDbg> { 11class AudDbg final : public ServiceFramework<AudDbg> {
12public: 12public:
13 explicit AudDbg(const char* name); 13 explicit AudDbg(const char* name);
14 ~AudDbg() override;
14}; 15};
15 16
16} // namespace Service::Audio 17} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp
index a70d5bca4..ddd12f35e 100644
--- a/src/core/hle/service/audio/audin_a.cpp
+++ b/src/core/hle/service/audio/audin_a.cpp
@@ -19,4 +19,6 @@ AudInA::AudInA() : ServiceFramework{"audin:a"} {
19 RegisterHandlers(functions); 19 RegisterHandlers(functions);
20} 20}
21 21
22AudInA::~AudInA() = default;
23
22} // namespace Service::Audio 24} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_a.h b/src/core/hle/service/audio/audin_a.h
index e4c75510f..e7623bc29 100644
--- a/src/core/hle/service/audio/audin_a.h
+++ b/src/core/hle/service/audio/audin_a.h
@@ -11,6 +11,7 @@ namespace Service::Audio {
11class AudInA final : public ServiceFramework<AudInA> { 11class AudInA final : public ServiceFramework<AudInA> {
12public: 12public:
13 explicit AudInA(); 13 explicit AudInA();
14 ~AudInA() override;
14}; 15};
15 16
16} // namespace Service::Audio 17} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index cbc49e55e..657010312 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -41,4 +41,6 @@ AudInU::AudInU() : ServiceFramework("audin:u") {
41 RegisterHandlers(functions); 41 RegisterHandlers(functions);
42} 42}
43 43
44AudInU::~AudInU() = default;
45
44} // namespace Service::Audio 46} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h
index 2e65efb5b..0538b9560 100644
--- a/src/core/hle/service/audio/audin_u.h
+++ b/src/core/hle/service/audio/audin_u.h
@@ -15,7 +15,7 @@ namespace Service::Audio {
15class AudInU final : public ServiceFramework<AudInU> { 15class AudInU final : public ServiceFramework<AudInU> {
16public: 16public:
17 explicit AudInU(); 17 explicit AudInU();
18 ~AudInU() = default; 18 ~AudInU() override;
19}; 19};
20 20
21} // namespace Service::Audio 21} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 6b5e15633..128df7db5 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -15,6 +15,7 @@
15#include "core/hle/service/audio/audren_u.h" 15#include "core/hle/service/audio/audren_u.h"
16#include "core/hle/service/audio/codecctl.h" 16#include "core/hle/service/audio/codecctl.h"
17#include "core/hle/service/audio/hwopus.h" 17#include "core/hle/service/audio/hwopus.h"
18#include "core/hle/service/service.h"
18 19
19namespace Service::Audio { 20namespace Service::Audio {
20 21
diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h
index 95e5691f7..f5bd3bf5f 100644
--- a/src/core/hle/service/audio/audio.h
+++ b/src/core/hle/service/audio/audio.h
@@ -4,7 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/service.h" 7namespace Service::SM {
8class ServiceManager;
9}
8 10
9namespace Service::Audio { 11namespace Service::Audio {
10 12
diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp
index bf8d40157..85febbca3 100644
--- a/src/core/hle/service/audio/audout_a.cpp
+++ b/src/core/hle/service/audio/audout_a.cpp
@@ -21,4 +21,6 @@ AudOutA::AudOutA() : ServiceFramework{"audout:a"} {
21 RegisterHandlers(functions); 21 RegisterHandlers(functions);
22} 22}
23 23
24AudOutA::~AudOutA() = default;
25
24} // namespace Service::Audio 26} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_a.h b/src/core/hle/service/audio/audout_a.h
index 91a069152..d65b66e8e 100644
--- a/src/core/hle/service/audio/audout_a.h
+++ b/src/core/hle/service/audio/audout_a.h
@@ -11,6 +11,7 @@ namespace Service::Audio {
11class AudOutA final : public ServiceFramework<AudOutA> { 11class AudOutA final : public ServiceFramework<AudOutA> {
12public: 12public:
13 explicit AudOutA(); 13 explicit AudOutA();
14 ~AudOutA() override;
14}; 15};
15 16
16} // namespace Service::Audio 17} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 5f370bbdf..80a002322 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -3,15 +3,20 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array> 5#include <array>
6#include <cstring>
6#include <vector> 7#include <vector>
7 8
9#include "audio_core/audio_out.h"
8#include "audio_core/codec.h" 10#include "audio_core/codec.h"
11#include "common/common_funcs.h"
9#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/swap.h"
10#include "core/core.h" 14#include "core/core.h"
11#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/hle_ipc.h" 17#include "core/hle/kernel/hle_ipc.h"
14#include "core/hle/service/audio/audout_u.h" 18#include "core/hle/service/audio/audout_u.h"
19#include "core/memory.h"
15 20
16namespace Service::Audio { 21namespace Service::Audio {
17 22
@@ -25,6 +30,18 @@ enum {
25constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}}; 30constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}};
26constexpr int DefaultSampleRate{48000}; 31constexpr int DefaultSampleRate{48000};
27 32
33struct AudoutParams {
34 s32_le sample_rate;
35 u16_le channel_count;
36 INSERT_PADDING_BYTES(2);
37};
38static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size");
39
40enum class AudioState : u32 {
41 Started,
42 Stopped,
43};
44
28class IAudioOut final : public ServiceFramework<IAudioOut> { 45class IAudioOut final : public ServiceFramework<IAudioOut> {
29public: 46public:
30 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) 47 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core)
@@ -218,4 +235,6 @@ AudOutU::AudOutU() : ServiceFramework("audout:u") {
218 audio_core = std::make_unique<AudioCore::AudioOut>(); 235 audio_core = std::make_unique<AudioCore::AudioOut>();
219} 236}
220 237
238AudOutU::~AudOutU() = default;
239
221} // namespace Service::Audio 240} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index fd491f65d..dcaf64708 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -4,33 +4,24 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "audio_core/audio_out.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9 8
9namespace AudioCore {
10class AudioOut;
11}
12
10namespace Kernel { 13namespace Kernel {
11class HLERequestContext; 14class HLERequestContext;
12} 15}
13 16
14namespace Service::Audio { 17namespace Service::Audio {
15 18
16struct AudoutParams {
17 s32_le sample_rate;
18 u16_le channel_count;
19 INSERT_PADDING_BYTES(2);
20};
21static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size");
22
23enum class AudioState : u32 {
24 Started,
25 Stopped,
26};
27
28class IAudioOut; 19class IAudioOut;
29 20
30class AudOutU final : public ServiceFramework<AudOutU> { 21class AudOutU final : public ServiceFramework<AudOutU> {
31public: 22public:
32 AudOutU(); 23 AudOutU();
33 ~AudOutU() = default; 24 ~AudOutU() override;
34 25
35private: 26private:
36 std::shared_ptr<IAudioOut> audio_out_interface; 27 std::shared_ptr<IAudioOut> audio_out_interface;
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/audrec_a.cpp
index 016eabf53..ce1bfb48d 100644
--- a/src/core/hle/service/audio/audrec_a.cpp
+++ b/src/core/hle/service/audio/audrec_a.cpp
@@ -17,4 +17,6 @@ AudRecA::AudRecA() : ServiceFramework{"audrec:a"} {
17 RegisterHandlers(functions); 17 RegisterHandlers(functions);
18} 18}
19 19
20AudRecA::~AudRecA() = default;
21
20} // namespace Service::Audio 22} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/audrec_a.h
index 9685047f2..384d24c69 100644
--- a/src/core/hle/service/audio/audrec_a.h
+++ b/src/core/hle/service/audio/audrec_a.h
@@ -11,6 +11,7 @@ namespace Service::Audio {
11class AudRecA final : public ServiceFramework<AudRecA> { 11class AudRecA final : public ServiceFramework<AudRecA> {
12public: 12public:
13 explicit AudRecA(); 13 explicit AudRecA();
14 ~AudRecA() override;
14}; 15};
15 16
16} // namespace Service::Audio 17} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp
index 74909415c..34974afa9 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/audrec_u.cpp
@@ -36,4 +36,6 @@ AudRecU::AudRecU() : ServiceFramework("audrec:u") {
36 RegisterHandlers(functions); 36 RegisterHandlers(functions);
37} 37}
38 38
39AudRecU::~AudRecU() = default;
40
39} // namespace Service::Audio 41} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/audrec_u.h
index 46daa33a4..ca3d638e8 100644
--- a/src/core/hle/service/audio/audrec_u.h
+++ b/src/core/hle/service/audio/audrec_u.h
@@ -15,7 +15,7 @@ namespace Service::Audio {
15class AudRecU final : public ServiceFramework<AudRecU> { 15class AudRecU final : public ServiceFramework<AudRecU> {
16public: 16public:
17 explicit AudRecU(); 17 explicit AudRecU();
18 ~AudRecU() = default; 18 ~AudRecU() override;
19}; 19};
20 20
21} // namespace Service::Audio 21} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp
index 616ff3dc4..edb66d985 100644
--- a/src/core/hle/service/audio/audren_a.cpp
+++ b/src/core/hle/service/audio/audren_a.cpp
@@ -23,4 +23,6 @@ AudRenA::AudRenA() : ServiceFramework{"audren:a"} {
23 RegisterHandlers(functions); 23 RegisterHandlers(functions);
24} 24}
25 25
26AudRenA::~AudRenA() = default;
27
26} // namespace Service::Audio 28} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_a.h b/src/core/hle/service/audio/audren_a.h
index 5ecf2e184..81fef0ffe 100644
--- a/src/core/hle/service/audio/audren_a.h
+++ b/src/core/hle/service/audio/audren_a.h
@@ -11,6 +11,7 @@ namespace Service::Audio {
11class AudRenA final : public ServiceFramework<AudRenA> { 11class AudRenA final : public ServiceFramework<AudRenA> {
12public: 12public:
13 explicit AudRenA(); 13 explicit AudRenA();
14 ~AudRenA() override;
14}; 15};
15 16
16} // namespace Service::Audio 17} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 016db7c82..e84c4fa2b 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -2,12 +2,14 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <array> 6#include <array>
7#include <memory>
6 8
9#include "audio_core/audio_renderer.h"
7#include "common/alignment.h" 10#include "common/alignment.h"
11#include "common/common_funcs.h"
8#include "common/logging/log.h" 12#include "common/logging/log.h"
9#include "core/core_timing.h"
10#include "core/core_timing_util.h"
11#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/event.h" 14#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/hle_ipc.h" 15#include "core/hle/kernel/hle_ipc.h"
@@ -198,6 +200,8 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
198 RegisterHandlers(functions); 200 RegisterHandlers(functions);
199} 201}
200 202
203AudRenU::~AudRenU() = default;
204
201void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { 205void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
202 IPC::RequestParser rp{ctx}; 206 IPC::RequestParser rp{ctx};
203 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); 207 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 8600ac6e4..c6bc3a90a 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "audio_core/audio_renderer.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9 8
10namespace Kernel { 9namespace Kernel {
@@ -16,7 +15,7 @@ namespace Service::Audio {
16class AudRenU final : public ServiceFramework<AudRenU> { 15class AudRenU final : public ServiceFramework<AudRenU> {
17public: 16public:
18 explicit AudRenU(); 17 explicit AudRenU();
19 ~AudRenU() = default; 18 ~AudRenU() override;
20 19
21private: 20private:
22 void OpenAudioRenderer(Kernel::HLERequestContext& ctx); 21 void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp
index 212c8d448..c6864146d 100644
--- a/src/core/hle/service/audio/codecctl.cpp
+++ b/src/core/hle/service/audio/codecctl.cpp
@@ -28,4 +28,6 @@ CodecCtl::CodecCtl() : ServiceFramework("codecctl") {
28 RegisterHandlers(functions); 28 RegisterHandlers(functions);
29} 29}
30 30
31CodecCtl::~CodecCtl() = default;
32
31} // namespace Service::Audio 33} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h
index d9ac29b67..2fe75b6e2 100644
--- a/src/core/hle/service/audio/codecctl.h
+++ b/src/core/hle/service/audio/codecctl.h
@@ -15,7 +15,7 @@ namespace Service::Audio {
15class CodecCtl final : public ServiceFramework<CodecCtl> { 15class CodecCtl final : public ServiceFramework<CodecCtl> {
16public: 16public:
17 explicit CodecCtl(); 17 explicit CodecCtl();
18 ~CodecCtl() = default; 18 ~CodecCtl() override;
19}; 19};
20 20
21} // namespace Service::Audio 21} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 371cd4997..668fef145 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -3,7 +3,12 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include <memory>
7#include <vector>
8
6#include <opus.h> 9#include <opus.h>
10
11#include "common/common_funcs.h"
7#include "common/logging/log.h" 12#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h" 14#include "core/hle/kernel/hle_ipc.h"
@@ -151,4 +156,6 @@ HwOpus::HwOpus() : ServiceFramework("hwopus") {
151 RegisterHandlers(functions); 156 RegisterHandlers(functions);
152} 157}
153 158
159HwOpus::~HwOpus() = default;
160
154} // namespace Service::Audio 161} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h
index 5258d59f3..602ede8ba 100644
--- a/src/core/hle/service/audio/hwopus.h
+++ b/src/core/hle/service/audio/hwopus.h
@@ -11,7 +11,7 @@ namespace Service::Audio {
11class HwOpus final : public ServiceFramework<HwOpus> { 11class HwOpus final : public ServiceFramework<HwOpus> {
12public: 12public:
13 explicit HwOpus(); 13 explicit HwOpus();
14 ~HwOpus() = default; 14 ~HwOpus() override;
15 15
16private: 16private:
17 void OpenOpusDecoder(Kernel::HLERequestContext& ctx); 17 void OpenOpusDecoder(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp
index 20ce692dc..179aa4949 100644
--- a/src/core/hle/service/bcat/bcat.cpp
+++ b/src/core/hle/service/bcat/bcat.cpp
@@ -13,4 +13,6 @@ BCAT::BCAT(std::shared_ptr<Module> module, const char* name)
13 }; 13 };
14 RegisterHandlers(functions); 14 RegisterHandlers(functions);
15} 15}
16
17BCAT::~BCAT() = default;
16} // namespace Service::BCAT 18} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h
index 6632996a0..802bd689a 100644
--- a/src/core/hle/service/bcat/bcat.h
+++ b/src/core/hle/service/bcat/bcat.h
@@ -11,6 +11,7 @@ namespace Service::BCAT {
11class BCAT final : public Module::Interface { 11class BCAT final : public Module::Interface {
12public: 12public:
13 explicit BCAT(std::shared_ptr<Module> module, const char* name); 13 explicit BCAT(std::shared_ptr<Module> module, const char* name);
14 ~BCAT() override;
14}; 15};
15 16
16} // namespace Service::BCAT 17} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 35e024c3d..6e7b795fb 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -42,6 +42,8 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
42Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 42Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
43 : ServiceFramework(name), module(std::move(module)) {} 43 : ServiceFramework(name), module(std::move(module)) {}
44 44
45Module::Interface::~Interface() = default;
46
45void InstallInterfaces(SM::ServiceManager& service_manager) { 47void InstallInterfaces(SM::ServiceManager& service_manager) {
46 auto module = std::make_shared<Module>(); 48 auto module = std::make_shared<Module>();
47 std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager); 49 std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager);
diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h
index 62f6f5f9d..f0d63cab0 100644
--- a/src/core/hle/service/bcat/module.h
+++ b/src/core/hle/service/bcat/module.h
@@ -13,6 +13,7 @@ public:
13 class Interface : public ServiceFramework<Interface> { 13 class Interface : public ServiceFramework<Interface> {
14 public: 14 public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 15 explicit Interface(std::shared_ptr<Module> module, const char* name);
16 ~Interface() override;
16 17
17 void CreateBcatService(Kernel::HLERequestContext& ctx); 18 void CreateBcatService(Kernel::HLERequestContext& ctx);
18 19
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index 299b9474f..b436ce4e6 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -13,6 +13,8 @@ namespace Service::Fatal {
13Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 13Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
14 : ServiceFramework(name), module(std::move(module)) {} 14 : ServiceFramework(name), module(std::move(module)) {}
15 15
16Module::Interface::~Interface() = default;
17
16void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) { 18void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) {
17 IPC::RequestParser rp(ctx); 19 IPC::RequestParser rp(ctx);
18 u32 error_code = rp.Pop<u32>(); 20 u32 error_code = rp.Pop<u32>();
diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h
index ca607e236..4d9a5be52 100644
--- a/src/core/hle/service/fatal/fatal.h
+++ b/src/core/hle/service/fatal/fatal.h
@@ -13,6 +13,7 @@ public:
13 class Interface : public ServiceFramework<Interface> { 13 class Interface : public ServiceFramework<Interface> {
14 public: 14 public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 15 explicit Interface(std::shared_ptr<Module> module, const char* name);
16 ~Interface() override;
16 17
17 void ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx); 18 void ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx);
18 void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx); 19 void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp
index a5254ac2f..9e5f872ff 100644
--- a/src/core/hle/service/fatal/fatal_p.cpp
+++ b/src/core/hle/service/fatal/fatal_p.cpp
@@ -9,4 +9,6 @@ namespace Service::Fatal {
9Fatal_P::Fatal_P(std::shared_ptr<Module> module) 9Fatal_P::Fatal_P(std::shared_ptr<Module> module)
10 : Module::Interface(std::move(module), "fatal:p") {} 10 : Module::Interface(std::move(module), "fatal:p") {}
11 11
12Fatal_P::~Fatal_P() = default;
13
12} // namespace Service::Fatal 14} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal_p.h b/src/core/hle/service/fatal/fatal_p.h
index bfd8c8b74..6e9c5979f 100644
--- a/src/core/hle/service/fatal/fatal_p.h
+++ b/src/core/hle/service/fatal/fatal_p.h
@@ -11,6 +11,7 @@ namespace Service::Fatal {
11class Fatal_P final : public Module::Interface { 11class Fatal_P final : public Module::Interface {
12public: 12public:
13 explicit Fatal_P(std::shared_ptr<Module> module); 13 explicit Fatal_P(std::shared_ptr<Module> module);
14 ~Fatal_P() override;
14}; 15};
15 16
16} // namespace Service::Fatal 17} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp
index f0631329e..befc307cf 100644
--- a/src/core/hle/service/fatal/fatal_u.cpp
+++ b/src/core/hle/service/fatal/fatal_u.cpp
@@ -15,4 +15,6 @@ Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(m
15 RegisterHandlers(functions); 15 RegisterHandlers(functions);
16} 16}
17 17
18Fatal_U::~Fatal_U() = default;
19
18} // namespace Service::Fatal 20} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal_u.h b/src/core/hle/service/fatal/fatal_u.h
index 9b1a9e97a..72cb6d076 100644
--- a/src/core/hle/service/fatal/fatal_u.h
+++ b/src/core/hle/service/fatal/fatal_u.h
@@ -11,6 +11,7 @@ namespace Service::Fatal {
11class Fatal_U final : public Module::Interface { 11class Fatal_U final : public Module::Interface {
12public: 12public:
13 explicit Fatal_U(std::shared_ptr<Module> module); 13 explicit Fatal_U(std::shared_ptr<Module> module);
14 ~Fatal_U() override;
14}; 15};
15 16
16} // namespace Service::Fatal 17} // namespace Service::Fatal
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 04c9d750f..5c4971724 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -40,6 +40,8 @@ static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
40VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_) 40VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_)
41 : backing(std::move(backing_)) {} 41 : backing(std::move(backing_)) {}
42 42
43VfsDirectoryServiceWrapper::~VfsDirectoryServiceWrapper() = default;
44
43std::string VfsDirectoryServiceWrapper::GetName() const { 45std::string VfsDirectoryServiceWrapper::GetName() const {
44 return backing->GetName(); 46 return backing->GetName();
45} 47}
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 793a7b06f..aab65a2b8 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -64,6 +64,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::Virtu
64class VfsDirectoryServiceWrapper { 64class VfsDirectoryServiceWrapper {
65public: 65public:
66 explicit VfsDirectoryServiceWrapper(FileSys::VirtualDir backing); 66 explicit VfsDirectoryServiceWrapper(FileSys::VirtualDir backing);
67 ~VfsDirectoryServiceWrapper();
67 68
68 /** 69 /**
69 * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) 70 * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)
diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp_ldr.cpp
index 0ab9c2606..fb487d5bc 100644
--- a/src/core/hle/service/filesystem/fsp_ldr.cpp
+++ b/src/core/hle/service/filesystem/fsp_ldr.cpp
@@ -19,4 +19,6 @@ FSP_LDR::FSP_LDR() : ServiceFramework{"fsp:ldr"} {
19 RegisterHandlers(functions); 19 RegisterHandlers(functions);
20} 20}
21 21
22FSP_LDR::~FSP_LDR() = default;
23
22} // namespace Service::FileSystem 24} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp_ldr.h
index fa8e11b4c..8210b7729 100644
--- a/src/core/hle/service/filesystem/fsp_ldr.h
+++ b/src/core/hle/service/filesystem/fsp_ldr.h
@@ -11,6 +11,7 @@ namespace Service::FileSystem {
11class FSP_LDR final : public ServiceFramework<FSP_LDR> { 11class FSP_LDR final : public ServiceFramework<FSP_LDR> {
12public: 12public:
13 explicit FSP_LDR(); 13 explicit FSP_LDR();
14 ~FSP_LDR() override;
14}; 15};
15 16
16} // namespace Service::FileSystem 17} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp_pr.cpp
index 32b0ae454..378201610 100644
--- a/src/core/hle/service/filesystem/fsp_pr.cpp
+++ b/src/core/hle/service/filesystem/fsp_pr.cpp
@@ -20,4 +20,6 @@ FSP_PR::FSP_PR() : ServiceFramework{"fsp:pr"} {
20 RegisterHandlers(functions); 20 RegisterHandlers(functions);
21} 21}
22 22
23FSP_PR::~FSP_PR() = default;
24
23} // namespace Service::FileSystem 25} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp_pr.h
index 62edcd08a..556ae5ce9 100644
--- a/src/core/hle/service/filesystem/fsp_pr.h
+++ b/src/core/hle/service/filesystem/fsp_pr.h
@@ -11,6 +11,7 @@ namespace Service::FileSystem {
11class FSP_PR final : public ServiceFramework<FSP_PR> { 11class FSP_PR final : public ServiceFramework<FSP_PR> {
12public: 12public:
13 explicit FSP_PR(); 13 explicit FSP_PR();
14 ~FSP_PR() override;
14}; 15};
15 16
16} // namespace Service::FileSystem 17} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 3f8ff67e8..cabaf5a55 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -520,6 +520,8 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
520 RegisterHandlers(functions); 520 RegisterHandlers(functions);
521} 521}
522 522
523FSP_SRV::~FSP_SRV() = default;
524
523void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) { 525void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) {
524 LOG_WARNING(Service_FS, "(STUBBED) called"); 526 LOG_WARNING(Service_FS, "(STUBBED) called");
525 527
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 2b5c21abb..4aa0358cb 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -16,7 +16,7 @@ namespace Service::FileSystem {
16class FSP_SRV final : public ServiceFramework<FSP_SRV> { 16class FSP_SRV final : public ServiceFramework<FSP_SRV> {
17public: 17public:
18 explicit FSP_SRV(); 18 explicit FSP_SRV();
19 ~FSP_SRV() = default; 19 ~FSP_SRV() override;
20 20
21private: 21private:
22 void Initialize(Kernel::HLERequestContext& ctx); 22 void Initialize(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index f2b0e509a..d9225d624 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -118,6 +118,8 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
118Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 118Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
119 : ServiceFramework(name), module(std::move(module)) {} 119 : ServiceFramework(name), module(std::move(module)) {}
120 120
121Module::Interface::~Interface() = default;
122
121void InstallInterfaces(SM::ServiceManager& service_manager) { 123void InstallInterfaces(SM::ServiceManager& service_manager) {
122 auto module = std::make_shared<Module>(); 124 auto module = std::make_shared<Module>();
123 std::make_shared<Friend>(module, "friend:a")->InstallAsService(service_manager); 125 std::make_shared<Friend>(module, "friend:a")->InstallAsService(service_manager);
diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h
index c1b36518a..e762840cb 100644
--- a/src/core/hle/service/friend/friend.h
+++ b/src/core/hle/service/friend/friend.h
@@ -13,6 +13,7 @@ public:
13 class Interface : public ServiceFramework<Interface> { 13 class Interface : public ServiceFramework<Interface> {
14 public: 14 public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 15 explicit Interface(std::shared_ptr<Module> module, const char* name);
16 ~Interface() override;
16 17
17 void CreateFriendService(Kernel::HLERequestContext& ctx); 18 void CreateFriendService(Kernel::HLERequestContext& ctx);
18 19
diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp
index 27c6a09e2..5a6840af5 100644
--- a/src/core/hle/service/friend/interface.cpp
+++ b/src/core/hle/service/friend/interface.cpp
@@ -16,4 +16,6 @@ Friend::Friend(std::shared_ptr<Module> module, const char* name)
16 RegisterHandlers(functions); 16 RegisterHandlers(functions);
17} 17}
18 18
19Friend::~Friend() = default;
20
19} // namespace Service::Friend 21} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/interface.h b/src/core/hle/service/friend/interface.h
index 89dae8471..1963def39 100644
--- a/src/core/hle/service/friend/interface.h
+++ b/src/core/hle/service/friend/interface.h
@@ -11,6 +11,7 @@ namespace Service::Friend {
11class Friend final : public Module::Interface { 11class Friend final : public Module::Interface {
12public: 12public:
13 explicit Friend(std::shared_ptr<Module> module, const char* name); 13 explicit Friend(std::shared_ptr<Module> module, const char* name);
14 ~Friend() override;
14}; 15};
15 16
16} // namespace Service::Friend 17} // namespace Service::Friend
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 0d31abe8b..a8e0c869f 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -2,7 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <atomic>
6#include "common/logging/log.h" 5#include "common/logging/log.h"
7#include "core/core.h" 6#include "core/core.h"
8#include "core/core_timing.h" 7#include "core/core_timing.h"
@@ -78,7 +77,7 @@ private:
78 SharedMemory mem{}; 77 SharedMemory mem{};
79 std::memcpy(&mem, shared_mem->GetPointer(), sizeof(SharedMemory)); 78 std::memcpy(&mem, shared_mem->GetPointer(), sizeof(SharedMemory));
80 79
81 if (is_device_reload_pending.exchange(false)) 80 if (Settings::values.is_device_reload_pending.exchange(false))
82 LoadInputDevices(); 81 LoadInputDevices();
83 82
84 // Set up controllers as neon red+blue Joy-Con attached to console 83 // Set up controllers as neon red+blue Joy-Con attached to console
@@ -267,7 +266,6 @@ private:
267 CoreTiming::EventType* pad_update_event; 266 CoreTiming::EventType* pad_update_event;
268 267
269 // Stored input state info 268 // Stored input state info
270 std::atomic<bool> is_device_reload_pending{true};
271 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> 269 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
272 buttons; 270 buttons;
273 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks; 271 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks;
@@ -797,7 +795,9 @@ public:
797 } 795 }
798}; 796};
799 797
800void ReloadInputDevices() {} 798void ReloadInputDevices() {
799 Settings::values.is_device_reload_pending.store(true);
800}
801 801
802void InstallInterfaces(SM::ServiceManager& service_manager) { 802void InstallInterfaces(SM::ServiceManager& service_manager) {
803 std::make_shared<Hid>()->InstallAsService(service_manager); 803 std::make_shared<Hid>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index aaf311912..e587ad0d8 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -33,6 +33,8 @@ IRS::IRS() : ServiceFramework{"irs"} {
33 RegisterHandlers(functions); 33 RegisterHandlers(functions);
34} 34}
35 35
36IRS::~IRS() = default;
37
36IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} { 38IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} {
37 // clang-format off 39 // clang-format off
38 static const FunctionInfo functions[] = { 40 static const FunctionInfo functions[] = {
@@ -46,4 +48,6 @@ IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} {
46 RegisterHandlers(functions); 48 RegisterHandlers(functions);
47} 49}
48 50
51IRS_SYS::~IRS_SYS() = default;
52
49} // namespace Service::HID 53} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index a8be701c7..6fb16b45d 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -11,11 +11,13 @@ namespace Service::HID {
11class IRS final : public ServiceFramework<IRS> { 11class IRS final : public ServiceFramework<IRS> {
12public: 12public:
13 explicit IRS(); 13 explicit IRS();
14 ~IRS() override;
14}; 15};
15 16
16class IRS_SYS final : public ServiceFramework<IRS_SYS> { 17class IRS_SYS final : public ServiceFramework<IRS_SYS> {
17public: 18public:
18 explicit IRS_SYS(); 19 explicit IRS_SYS();
20 ~IRS_SYS() override;
19}; 21};
20 22
21} // namespace Service::HID 23} // namespace Service::HID
diff --git a/src/core/hle/service/hid/xcd.cpp b/src/core/hle/service/hid/xcd.cpp
index 49f733f60..c8e9125f6 100644
--- a/src/core/hle/service/hid/xcd.cpp
+++ b/src/core/hle/service/hid/xcd.cpp
@@ -34,4 +34,6 @@ XCD_SYS::XCD_SYS() : ServiceFramework{"xcd:sys"} {
34 RegisterHandlers(functions); 34 RegisterHandlers(functions);
35} 35}
36 36
37XCD_SYS::~XCD_SYS() = default;
38
37} // namespace Service::HID 39} // namespace Service::HID
diff --git a/src/core/hle/service/hid/xcd.h b/src/core/hle/service/hid/xcd.h
index 232a044df..fd506d303 100644
--- a/src/core/hle/service/hid/xcd.h
+++ b/src/core/hle/service/hid/xcd.h
@@ -11,6 +11,7 @@ namespace Service::HID {
11class XCD_SYS final : public ServiceFramework<XCD_SYS> { 11class XCD_SYS final : public ServiceFramework<XCD_SYS> {
12public: 12public:
13 explicit XCD_SYS(); 13 explicit XCD_SYS();
14 ~XCD_SYS() override;
14}; 15};
15 16
16} // namespace Service::HID 17} // namespace Service::HID
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 4f7543af5..f8d2127d9 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -14,6 +14,8 @@ namespace Service::NFP {
14Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 14Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
15 : ServiceFramework(name), module(std::move(module)) {} 15 : ServiceFramework(name), module(std::move(module)) {}
16 16
17Module::Interface::~Interface() = default;
18
17class IUser final : public ServiceFramework<IUser> { 19class IUser final : public ServiceFramework<IUser> {
18public: 20public:
19 IUser() : ServiceFramework("IUser") { 21 IUser() : ServiceFramework("IUser") {
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 0cd7be3d5..77df343c4 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -13,6 +13,7 @@ public:
13 class Interface : public ServiceFramework<Interface> { 13 class Interface : public ServiceFramework<Interface> {
14 public: 14 public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 15 explicit Interface(std::shared_ptr<Module> module, const char* name);
16 ~Interface() override;
16 17
17 void CreateUserInterface(Kernel::HLERequestContext& ctx); 18 void CreateUserInterface(Kernel::HLERequestContext& ctx);
18 19
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp
index b608fe693..784a87c1b 100644
--- a/src/core/hle/service/nfp/nfp_user.cpp
+++ b/src/core/hle/service/nfp/nfp_user.cpp
@@ -14,4 +14,6 @@ NFP_User::NFP_User(std::shared_ptr<Module> module)
14 RegisterHandlers(functions); 14 RegisterHandlers(functions);
15} 15}
16 16
17NFP_User::~NFP_User() = default;
18
17} // namespace Service::NFP 19} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h
index 700043114..65d9aaf48 100644
--- a/src/core/hle/service/nfp/nfp_user.h
+++ b/src/core/hle/service/nfp/nfp_user.h
@@ -11,6 +11,7 @@ namespace Service::NFP {
11class NFP_User final : public Module::Interface { 11class NFP_User final : public Module::Interface {
12public: 12public:
13 explicit NFP_User(std::shared_ptr<Module> module); 13 explicit NFP_User(std::shared_ptr<Module> module);
14 ~NFP_User() override;
14}; 15};
15 16
16} // namespace Service::NFP 17} // namespace Service::NFP
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 878bbe439..ac0eaaa8f 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -2,14 +2,30 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cstring>
7#include <vector>
8
9#include <FontChineseSimplified.h>
10#include <FontChineseTraditional.h>
11#include <FontExtendedChineseSimplified.h>
12#include <FontKorean.h>
13#include <FontNintendoExtended.h>
14#include <FontStandard.h>
15
16#include "common/assert.h"
5#include "common/common_paths.h" 17#include "common/common_paths.h"
18#include "common/common_types.h"
6#include "common/file_util.h" 19#include "common/file_util.h"
20#include "common/logging/log.h"
21#include "common/swap.h"
7#include "core/core.h" 22#include "core/core.h"
8#include "core/file_sys/content_archive.h" 23#include "core/file_sys/content_archive.h"
9#include "core/file_sys/nca_metadata.h" 24#include "core/file_sys/nca_metadata.h"
10#include "core/file_sys/registered_cache.h" 25#include "core/file_sys/registered_cache.h"
11#include "core/file_sys/romfs.h" 26#include "core/file_sys/romfs.h"
12#include "core/hle/ipc_helpers.h" 27#include "core/hle/ipc_helpers.h"
28#include "core/hle/kernel/shared_memory.h"
13#include "core/hle/service/filesystem/filesystem.h" 29#include "core/hle/service/filesystem/filesystem.h"
14#include "core/hle/service/ns/pl_u.h" 30#include "core/hle/service/ns/pl_u.h"
15 31
@@ -28,49 +44,41 @@ struct FontRegion {
28 u32 size; 44 u32 size;
29}; 45};
30 46
31static constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ 47constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{
32 std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), 48 std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"),
33 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), 49 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"),
34 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"), 50 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"),
35 std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"), 51 std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"),
36 std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"), 52 std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"),
37 std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"), 53 std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"),
38 std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf")}; 54 std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"),
55};
39 56
40static constexpr std::array<const char*, 7> SHARED_FONTS_TTF{"FontStandard.ttf", 57constexpr std::array<const char*, 7> SHARED_FONTS_TTF{
41 "FontChineseSimplified.ttf", 58 "FontStandard.ttf",
42 "FontExtendedChineseSimplified.ttf", 59 "FontChineseSimplified.ttf",
43 "FontChineseTraditional.ttf", 60 "FontExtendedChineseSimplified.ttf",
44 "FontKorean.ttf", 61 "FontChineseTraditional.ttf",
45 "FontNintendoExtended.ttf", 62 "FontKorean.ttf",
46 "FontNintendoExtended2.ttf"}; 63 "FontNintendoExtended.ttf",
64 "FontNintendoExtended2.ttf",
65};
47 66
48// The below data is specific to shared font data dumped from Switch on f/w 2.2 67// The below data is specific to shared font data dumped from Switch on f/w 2.2
49// Virtual address and offsets/sizes likely will vary by dump 68// Virtual address and offsets/sizes likely will vary by dump
50static constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; 69constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL};
51static constexpr u32 EXPECTED_RESULT{ 70constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be
52 0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be 71constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be
53static constexpr u32 EXPECTED_MAGIC{ 72constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
54 0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be 73constexpr FontRegion EMPTY_REGION{0, 0};
55static constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
56static constexpr FontRegion EMPTY_REGION{0, 0};
57std::vector<FontRegion>
58 SHARED_FONT_REGIONS{}; // Automatically populated based on shared_fonts dump or system archives
59
60const FontRegion& GetSharedFontRegion(size_t index) {
61 if (index >= SHARED_FONT_REGIONS.size() || SHARED_FONT_REGIONS.empty()) {
62 // No font fallback
63 return EMPTY_REGION;
64 }
65 return SHARED_FONT_REGIONS.at(index);
66}
67 74
68enum class LoadState : u32 { 75enum class LoadState : u32 {
69 Loading = 0, 76 Loading = 0,
70 Done = 1, 77 Done = 1,
71}; 78};
72 79
73void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, size_t& offset) { 80static void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output,
81 size_t& offset) {
74 ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, 82 ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE,
75 "Shared fonts exceeds 17mb!"); 83 "Shared fonts exceeds 17mb!");
76 ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); 84 ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number");
@@ -97,28 +105,52 @@ static void EncryptSharedFont(const std::vector<u8>& input, std::vector<u8>& out
97 offset += input.size() + (sizeof(u32) * 2); 105 offset += input.size() + (sizeof(u32) * 2);
98} 106}
99 107
108// Helper function to make BuildSharedFontsRawRegions a bit nicer
100static u32 GetU32Swapped(const u8* data) { 109static u32 GetU32Swapped(const u8* data) {
101 u32 value; 110 u32 value;
102 std::memcpy(&value, data, sizeof(value)); 111 std::memcpy(&value, data, sizeof(value));
103 return Common::swap32(value); // Helper function to make BuildSharedFontsRawRegions a bit nicer 112 return Common::swap32(value);
104} 113}
105 114
106void BuildSharedFontsRawRegions(const std::vector<u8>& input) { 115struct PL_U::Impl {
107 unsigned cur_offset = 0; // As we can derive the xor key we can just populate the offsets based 116 const FontRegion& GetSharedFontRegion(size_t index) const {
108 // on the shared memory dump 117 if (index >= shared_font_regions.size() || shared_font_regions.empty()) {
109 for (size_t i = 0; i < SHARED_FONTS.size(); i++) { 118 // No font fallback
110 // Out of shared fonts/Invalid font 119 return EMPTY_REGION;
111 if (GetU32Swapped(input.data() + cur_offset) != EXPECTED_RESULT) 120 }
112 break; 121 return shared_font_regions.at(index);
113 const u32 KEY = GetU32Swapped(input.data() + cur_offset) ^
114 EXPECTED_MAGIC; // Derive key withing inverse xor
115 const u32 SIZE = GetU32Swapped(input.data() + cur_offset + 4) ^ KEY;
116 SHARED_FONT_REGIONS.push_back(FontRegion{cur_offset + 8, SIZE});
117 cur_offset += SIZE + 8;
118 } 122 }
119}
120 123
121PL_U::PL_U() : ServiceFramework("pl:u") { 124 void BuildSharedFontsRawRegions(const std::vector<u8>& input) {
125 // As we can derive the xor key we can just populate the offsets
126 // based on the shared memory dump
127 unsigned cur_offset = 0;
128
129 for (size_t i = 0; i < SHARED_FONTS.size(); i++) {
130 // Out of shared fonts/invalid font
131 if (GetU32Swapped(input.data() + cur_offset) != EXPECTED_RESULT) {
132 break;
133 }
134
135 // Derive key withing inverse xor
136 const u32 KEY = GetU32Swapped(input.data() + cur_offset) ^ EXPECTED_MAGIC;
137 const u32 SIZE = GetU32Swapped(input.data() + cur_offset + 4) ^ KEY;
138 shared_font_regions.push_back(FontRegion{cur_offset + 8, SIZE});
139 cur_offset += SIZE + 8;
140 }
141 }
142
143 /// Handle to shared memory region designated for a shared font
144 Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
145
146 /// Backing memory for the shared font data
147 std::shared_ptr<std::vector<u8>> shared_font;
148
149 // Automatically populated based on shared_fonts dump or system archives.
150 std::vector<FontRegion> shared_font_regions;
151};
152
153PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
122 static const FunctionInfo functions[] = { 154 static const FunctionInfo functions[] = {
123 {0, &PL_U::RequestLoad, "RequestLoad"}, 155 {0, &PL_U::RequestLoad, "RequestLoad"},
124 {1, &PL_U::GetLoadState, "GetLoadState"}, 156 {1, &PL_U::GetLoadState, "GetLoadState"},
@@ -134,7 +166,7 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
134 // Rebuild shared fonts from data ncas 166 // Rebuild shared fonts from data ncas
135 if (nand->HasEntry(static_cast<u64>(FontArchives::Standard), 167 if (nand->HasEntry(static_cast<u64>(FontArchives::Standard),
136 FileSys::ContentRecordType::Data)) { 168 FileSys::ContentRecordType::Data)) {
137 shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE); 169 impl->shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE);
138 for (auto font : SHARED_FONTS) { 170 for (auto font : SHARED_FONTS) {
139 const auto nca = 171 const auto nca =
140 nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data); 172 nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data);
@@ -170,12 +202,12 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
170 static_cast<u32>(offset + 8), 202 static_cast<u32>(offset + 8),
171 static_cast<u32>((font_data_u32.size() * sizeof(u32)) - 203 static_cast<u32>((font_data_u32.size() * sizeof(u32)) -
172 8)}; // Font offset and size do not account for the header 204 8)}; // Font offset and size do not account for the header
173 DecryptSharedFont(font_data_u32, *shared_font, offset); 205 DecryptSharedFont(font_data_u32, *impl->shared_font, offset);
174 SHARED_FONT_REGIONS.push_back(region); 206 impl->shared_font_regions.push_back(region);
175 } 207 }
176 208
177 } else { 209 } else {
178 shared_font = std::make_shared<std::vector<u8>>( 210 impl->shared_font = std::make_shared<std::vector<u8>>(
179 SHARED_FONT_MEM_SIZE); // Shared memory needs to always be allocated and a fixed size 211 SHARED_FONT_MEM_SIZE); // Shared memory needs to always be allocated and a fixed size
180 212
181 const std::string user_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir); 213 const std::string user_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir);
@@ -199,8 +231,8 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
199 static_cast<u32>(offset + 8), 231 static_cast<u32>(offset + 8),
200 static_cast<u32>(ttf_bytes.size())}; // Font offset and size do not account 232 static_cast<u32>(ttf_bytes.size())}; // Font offset and size do not account
201 // for the header 233 // for the header
202 EncryptSharedFont(ttf_bytes, *shared_font, offset); 234 EncryptSharedFont(ttf_bytes, *impl->shared_font, offset);
203 SHARED_FONT_REGIONS.push_back(region); 235 impl->shared_font_regions.push_back(region);
204 } else { 236 } else {
205 LOG_WARNING(Service_NS, "Unable to load font: {}", font_ttf); 237 LOG_WARNING(Service_NS, "Unable to load font: {}", font_ttf);
206 } 238 }
@@ -215,14 +247,33 @@ PL_U::PL_U() : ServiceFramework("pl:u") {
215 if (file.IsOpen()) { 247 if (file.IsOpen()) {
216 // Read shared font data 248 // Read shared font data
217 ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE); 249 ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE);
218 file.ReadBytes(shared_font->data(), shared_font->size()); 250 file.ReadBytes(impl->shared_font->data(), impl->shared_font->size());
219 BuildSharedFontsRawRegions(*shared_font); 251 impl->BuildSharedFontsRawRegions(*impl->shared_font);
220 } else { 252 } else {
221 LOG_WARNING(Service_NS, "Unable to load shared font: {}", filepath); 253 LOG_WARNING(Service_NS,
254 "Shared Font file missing. Loading open source replacement from memory");
255
256 const std::vector<std::vector<u8>> open_source_shared_fonts_ttf = {
257 {std::begin(FontChineseSimplified), std::end(FontChineseSimplified)},
258 {std::begin(FontChineseTraditional), std::end(FontChineseTraditional)},
259 {std::begin(FontExtendedChineseSimplified),
260 std::end(FontExtendedChineseSimplified)},
261 {std::begin(FontNintendoExtended), std::end(FontNintendoExtended)},
262 {std::begin(FontStandard), std::end(FontStandard)},
263 };
264
265 for (const std::vector<u8>& font_ttf : open_source_shared_fonts_ttf) {
266 const FontRegion region{static_cast<u32>(offset + 8),
267 static_cast<u32>(font_ttf.size())};
268 EncryptSharedFont(font_ttf, *impl->shared_font, offset);
269 impl->shared_font_regions.push_back(region);
270 }
222 } 271 }
223 } 272 }
224} 273}
225 274
275PL_U::~PL_U() = default;
276
226void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { 277void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
227 IPC::RequestParser rp{ctx}; 278 IPC::RequestParser rp{ctx};
228 const u32 shared_font_type{rp.Pop<u32>()}; 279 const u32 shared_font_type{rp.Pop<u32>()};
@@ -249,7 +300,7 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
249 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 300 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
250 IPC::ResponseBuilder rb{ctx, 3}; 301 IPC::ResponseBuilder rb{ctx, 3};
251 rb.Push(RESULT_SUCCESS); 302 rb.Push(RESULT_SUCCESS);
252 rb.Push<u32>(GetSharedFontRegion(font_id).size); 303 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size);
253} 304}
254 305
255void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { 306void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
@@ -259,17 +310,18 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
259 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 310 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
260 IPC::ResponseBuilder rb{ctx, 3}; 311 IPC::ResponseBuilder rb{ctx, 3};
261 rb.Push(RESULT_SUCCESS); 312 rb.Push(RESULT_SUCCESS);
262 rb.Push<u32>(GetSharedFontRegion(font_id).offset); 313 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset);
263} 314}
264 315
265void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 316void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
266 // Map backing memory for the font data 317 // Map backing memory for the font data
267 Core::CurrentProcess()->vm_manager.MapMemoryBlock( 318 Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
268 SHARED_FONT_MEM_VADDR, shared_font, 0, SHARED_FONT_MEM_SIZE, Kernel::MemoryState::Shared); 319 SHARED_FONT_MEM_SIZE,
320 Kernel::MemoryState::Shared);
269 321
270 // Create shared font memory object 322 // Create shared font memory object
271 auto& kernel = Core::System::GetInstance().Kernel(); 323 auto& kernel = Core::System::GetInstance().Kernel();
272 shared_font_mem = Kernel::SharedMemory::Create( 324 impl->shared_font_mem = Kernel::SharedMemory::Create(
273 kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, 325 kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite,
274 Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, 326 Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
275 "PL_U:shared_font_mem"); 327 "PL_U:shared_font_mem");
@@ -277,7 +329,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
277 LOG_DEBUG(Service_NS, "called"); 329 LOG_DEBUG(Service_NS, "called");
278 IPC::ResponseBuilder rb{ctx, 2, 1}; 330 IPC::ResponseBuilder rb{ctx, 2, 1};
279 rb.Push(RESULT_SUCCESS); 331 rb.Push(RESULT_SUCCESS);
280 rb.PushCopyObjects(shared_font_mem); 332 rb.PushCopyObjects(impl->shared_font_mem);
281} 333}
282 334
283void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { 335void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
@@ -290,9 +342,9 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
290 std::vector<u32> font_sizes; 342 std::vector<u32> font_sizes;
291 343
292 // TODO(ogniK): Have actual priority order 344 // TODO(ogniK): Have actual priority order
293 for (size_t i = 0; i < SHARED_FONT_REGIONS.size(); i++) { 345 for (size_t i = 0; i < impl->shared_font_regions.size(); i++) {
294 font_codes.push_back(static_cast<u32>(i)); 346 font_codes.push_back(static_cast<u32>(i));
295 auto region = GetSharedFontRegion(i); 347 auto region = impl->GetSharedFontRegion(i);
296 font_offsets.push_back(region.offset); 348 font_offsets.push_back(region.offset);
297 font_sizes.push_back(region.size); 349 font_sizes.push_back(region.size);
298 } 350 }
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h
index fcc2acab7..253f26a2a 100644
--- a/src/core/hle/service/ns/pl_u.h
+++ b/src/core/hle/service/ns/pl_u.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include "core/hle/kernel/shared_memory.h"
9#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
10 9
11namespace Service::NS { 10namespace Service::NS {
@@ -13,7 +12,7 @@ namespace Service::NS {
13class PL_U final : public ServiceFramework<PL_U> { 12class PL_U final : public ServiceFramework<PL_U> {
14public: 13public:
15 PL_U(); 14 PL_U();
16 ~PL_U() = default; 15 ~PL_U() override;
17 16
18private: 17private:
19 void RequestLoad(Kernel::HLERequestContext& ctx); 18 void RequestLoad(Kernel::HLERequestContext& ctx);
@@ -23,11 +22,8 @@ private:
23 void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); 22 void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
24 void GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx); 23 void GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx);
25 24
26 /// Handle to shared memory region designated for a shared font 25 struct Impl;
27 Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; 26 std::unique_ptr<Impl> impl;
28
29 /// Backing memory for the shared font data
30 std::shared_ptr<std::vector<u8>> shared_font;
31}; 27};
32 28
33} // namespace Service::NS 29} // namespace Service::NS
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 0b37098e1..92acc57b1 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -13,6 +13,9 @@
13 13
14namespace Service::Nvidia::Devices { 14namespace Service::Nvidia::Devices {
15 15
16nvdisp_disp0::nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
17nvdisp_disp0 ::~nvdisp_disp0() = default;
18
16u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 19u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
17 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 20 UNIMPLEMENTED_MSG("Unimplemented ioctl");
18 return 0; 21 return 0;
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 6f0697b58..a45086e45 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -17,8 +17,8 @@ class nvmap;
17 17
18class nvdisp_disp0 final : public nvdevice { 18class nvdisp_disp0 final : public nvdevice {
19public: 19public:
20 explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} 20 explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev);
21 ~nvdisp_disp0() = default; 21 ~nvdisp_disp0();
22 22
23 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 23 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
24 24
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 75487c4e8..25d5a93fa 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -3,6 +3,8 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include <utility>
7
6#include "common/assert.h" 8#include "common/assert.h"
7#include "common/logging/log.h" 9#include "common/logging/log.h"
8#include "core/core.h" 10#include "core/core.h"
@@ -14,6 +16,9 @@
14 16
15namespace Service::Nvidia::Devices { 17namespace Service::Nvidia::Devices {
16 18
19nvhost_as_gpu::nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
20nvhost_as_gpu::~nvhost_as_gpu() = default;
21
17u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 22u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
18 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 23 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
19 command.raw, input.size(), output.size()); 24 command.raw, input.size(), output.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 9f8999d9c..eb14b1da8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -6,7 +6,6 @@
6 6
7#include <memory> 7#include <memory>
8#include <unordered_map> 8#include <unordered_map>
9#include <utility>
10#include <vector> 9#include <vector>
11#include "common/common_types.h" 10#include "common/common_types.h"
12#include "common/swap.h" 11#include "common/swap.h"
@@ -18,8 +17,8 @@ class nvmap;
18 17
19class nvhost_as_gpu final : public nvdevice { 18class nvhost_as_gpu final : public nvdevice {
20public: 19public:
21 explicit nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} 20 explicit nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev);
22 ~nvhost_as_gpu() override = default; 21 ~nvhost_as_gpu() override;
23 22
24 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 23 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
25 24
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 5685eb2be..b39fb9ef9 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -11,6 +11,9 @@
11 11
12namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13 13
14nvhost_ctrl::nvhost_ctrl() = default;
15nvhost_ctrl::~nvhost_ctrl() = default;
16
14u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 17u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
15 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 18 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
16 command.raw, input.size(), output.size()); 19 command.raw, input.size(), output.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 6b496e9fe..6d0de2212 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices {
13 13
14class nvhost_ctrl final : public nvdevice { 14class nvhost_ctrl final : public nvdevice {
15public: 15public:
16 nvhost_ctrl() = default; 16 nvhost_ctrl();
17 ~nvhost_ctrl() override = default; 17 ~nvhost_ctrl() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20 20
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index ae421247d..7a88ae029 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -9,6 +9,9 @@
9 9
10namespace Service::Nvidia::Devices { 10namespace Service::Nvidia::Devices {
11 11
12nvhost_ctrl_gpu::nvhost_ctrl_gpu() = default;
13nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
14
12u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 15u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
13 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 16 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
14 command.raw, input.size(), output.size()); 17 command.raw, input.size(), output.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index f09113e67..3bbf028ad 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices {
13 13
14class nvhost_ctrl_gpu final : public nvdevice { 14class nvhost_ctrl_gpu final : public nvdevice {
15public: 15public:
16 nvhost_ctrl_gpu() = default; 16 nvhost_ctrl_gpu();
17 ~nvhost_ctrl_gpu() override = default; 17 ~nvhost_ctrl_gpu() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20 20
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 4cdf7f613..874d5e1c3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -8,11 +8,15 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_gpu.h" 9#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
10#include "core/memory.h" 10#include "core/memory.h"
11#include "video_core/command_processor.h"
11#include "video_core/gpu.h" 12#include "video_core/gpu.h"
12#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
13 14
14namespace Service::Nvidia::Devices { 15namespace Service::Nvidia::Devices {
15 16
17nvhost_gpu::nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
18nvhost_gpu::~nvhost_gpu() = default;
19
16u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 20u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
17 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 21 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
18 command.raw, input.size(), output.size()); 22 command.raw, input.size(), output.size());
@@ -134,17 +138,16 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
134 LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", 138 LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
135 params.address, params.num_entries, params.flags); 139 params.address, params.num_entries, params.flags);
136 140
137 ASSERT_MSG(input.size() == 141 ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) +
138 sizeof(IoctlSubmitGpfifo) + params.num_entries * sizeof(IoctlGpfifoEntry), 142 params.num_entries * sizeof(Tegra::CommandListHeader),
139 "Incorrect input size"); 143 "Incorrect input size");
140 144
141 std::vector<IoctlGpfifoEntry> entries(params.num_entries); 145 std::vector<Tegra::CommandListHeader> entries(params.num_entries);
142 std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], 146 std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)],
143 params.num_entries * sizeof(IoctlGpfifoEntry)); 147 params.num_entries * sizeof(Tegra::CommandListHeader));
144 for (auto entry : entries) { 148
145 Tegra::GPUVAddr va_addr = entry.Address(); 149 Core::System::GetInstance().GPU().ProcessCommandLists(entries);
146 Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz); 150
147 }
148 params.fence_out.id = 0; 151 params.fence_out.id = 0;
149 params.fence_out.value = 0; 152 params.fence_out.value = 0;
150 std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo)); 153 std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo));
@@ -160,14 +163,12 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output)
160 LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", 163 LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
161 params.address, params.num_entries, params.flags); 164 params.address, params.num_entries, params.flags);
162 165
163 std::vector<IoctlGpfifoEntry> entries(params.num_entries); 166 std::vector<Tegra::CommandListHeader> entries(params.num_entries);
164 Memory::ReadBlock(params.address, entries.data(), 167 Memory::ReadBlock(params.address, entries.data(),
165 params.num_entries * sizeof(IoctlGpfifoEntry)); 168 params.num_entries * sizeof(Tegra::CommandListHeader));
169
170 Core::System::GetInstance().GPU().ProcessCommandLists(entries);
166 171
167 for (auto entry : entries) {
168 Tegra::GPUVAddr va_addr = entry.Address();
169 Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz);
170 }
171 params.fence_out.id = 0; 172 params.fence_out.id = 0;
172 params.fence_out.value = 0; 173 params.fence_out.value = 0;
173 std::memcpy(output.data(), &params, output.size()); 174 std::memcpy(output.data(), &params, output.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 03b7356d0..62beb5c0c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -10,7 +10,6 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/hle/service/nvdrv/devices/nvdevice.h" 12#include "core/hle/service/nvdrv/devices/nvdevice.h"
13#include "video_core/memory_manager.h"
14 13
15namespace Service::Nvidia::Devices { 14namespace Service::Nvidia::Devices {
16 15
@@ -21,8 +20,8 @@ constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
21 20
22class nvhost_gpu final : public nvdevice { 21class nvhost_gpu final : public nvdevice {
23public: 22public:
24 explicit nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} 23 explicit nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev);
25 ~nvhost_gpu() override = default; 24 ~nvhost_gpu() override;
26 25
27 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 26 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
28 27
@@ -151,22 +150,6 @@ private:
151 }; 150 };
152 static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); 151 static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size");
153 152
154 struct IoctlGpfifoEntry {
155 u32_le entry0; // gpu_va_lo
156 union {
157 u32_le entry1; // gpu_va_hi | (unk_0x02 << 0x08) | (size << 0x0A) | (unk_0x01 << 0x1F)
158 BitField<0, 8, u32_le> gpu_va_hi;
159 BitField<8, 2, u32_le> unk1;
160 BitField<10, 21, u32_le> sz;
161 BitField<31, 1, u32_le> unk2;
162 };
163
164 Tegra::GPUVAddr Address() const {
165 return (static_cast<Tegra::GPUVAddr>(gpu_va_hi) << 32) | entry0;
166 }
167 };
168 static_assert(sizeof(IoctlGpfifoEntry) == 8, "IoctlGpfifoEntry is incorrect size");
169
170 struct IoctlSubmitGpfifo { 153 struct IoctlSubmitGpfifo {
171 u64_le address; // pointer to gpfifo entry structs 154 u64_le address; // pointer to gpfifo entry structs
172 u32_le num_entries; // number of fence objects being submitted 155 u32_le num_entries; // number of fence objects being submitted
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 364619e67..46dbbc37c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -10,6 +10,9 @@
10 10
11namespace Service::Nvidia::Devices { 11namespace Service::Nvidia::Devices {
12 12
13nvhost_nvdec::nvhost_nvdec() = default;
14nvhost_nvdec::~nvhost_nvdec() = default;
15
13u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 16u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
14 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 17 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
15 command.raw, input.size(), output.size()); 18 command.raw, input.size(), output.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 6ad74421b..0e7b284f8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices {
13 13
14class nvhost_nvdec final : public nvdevice { 14class nvhost_nvdec final : public nvdevice {
15public: 15public:
16 nvhost_nvdec() = default; 16 nvhost_nvdec();
17 ~nvhost_nvdec() override = default; 17 ~nvhost_nvdec() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20 20
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index 51f01077b..c67f934f6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -10,6 +10,9 @@
10 10
11namespace Service::Nvidia::Devices { 11namespace Service::Nvidia::Devices {
12 12
13nvhost_nvjpg::nvhost_nvjpg() = default;
14nvhost_nvjpg::~nvhost_nvjpg() = default;
15
13u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 16u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
14 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 17 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
15 command.raw, input.size(), output.size()); 18 command.raw, input.size(), output.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 2b0eb43ee..89fd5e95e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices {
13 13
14class nvhost_nvjpg final : public nvdevice { 14class nvhost_nvjpg final : public nvdevice {
15public: 15public:
16 nvhost_nvjpg() = default; 16 nvhost_nvjpg();
17 ~nvhost_nvjpg() override = default; 17 ~nvhost_nvjpg() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20 20
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index fcb488d50..727b9fee4 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -10,6 +10,9 @@
10 10
11namespace Service::Nvidia::Devices { 11namespace Service::Nvidia::Devices {
12 12
13nvhost_vic::nvhost_vic() = default;
14nvhost_vic::~nvhost_vic() = default;
15
13u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 16u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
14 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 17 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
15 command.raw, input.size(), output.size()); 18 command.raw, input.size(), output.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index c7d681e52..fc24c3f9c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices {
13 13
14class nvhost_vic final : public nvdevice { 14class nvhost_vic final : public nvdevice {
15public: 15public:
16 nvhost_vic() = default; 16 nvhost_vic();
17 ~nvhost_vic() override = default; 17 ~nvhost_vic() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20 20
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index e9305bfb3..a2287cc1b 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -11,6 +11,9 @@
11 11
12namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13 13
14nvmap::nvmap() = default;
15nvmap::~nvmap() = default;
16
14VAddr nvmap::GetObjectAddress(u32 handle) const { 17VAddr nvmap::GetObjectAddress(u32 handle) const {
15 auto object = GetObject(handle); 18 auto object = GetObject(handle);
16 ASSERT(object); 19 ASSERT(object);
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index f2eec6409..396230c19 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -16,8 +16,8 @@ namespace Service::Nvidia::Devices {
16 16
17class nvmap final : public nvdevice { 17class nvmap final : public nvdevice {
18public: 18public:
19 nvmap() = default; 19 nvmap();
20 ~nvmap() override = default; 20 ~nvmap() override;
21 21
22 /// Returns the allocated address of an nvmap object given its handle. 22 /// Returns the allocated address of an nvmap object given its handle.
23 VAddr GetObjectAddress(u32 handle) const; 23 VAddr GetObjectAddress(u32 handle) const;
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index 634ab9196..ac3859353 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -112,4 +112,6 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
112 query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event"); 112 query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event");
113} 113}
114 114
115NVDRV::~NVDRV() = default;
116
115} // namespace Service::Nvidia 117} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 1c3529bb6..d340893c2 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -14,7 +14,7 @@ namespace Service::Nvidia {
14class NVDRV final : public ServiceFramework<NVDRV> { 14class NVDRV final : public ServiceFramework<NVDRV> {
15public: 15public:
16 NVDRV(std::shared_ptr<Module> nvdrv, const char* name); 16 NVDRV(std::shared_ptr<Module> nvdrv, const char* name);
17 ~NVDRV() = default; 17 ~NVDRV();
18 18
19private: 19private:
20 void Open(Kernel::HLERequestContext& ctx); 20 void Open(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 2de39822f..6e4b8f2c6 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -45,6 +45,8 @@ Module::Module() {
45 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(); 45 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>();
46} 46}
47 47
48Module::~Module() = default;
49
48u32 Module::Open(const std::string& device_name) { 50u32 Module::Open(const std::string& device_name) {
49 ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", 51 ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}",
50 device_name); 52 device_name);
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index 99eb1128a..53564f696 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -30,7 +30,7 @@ static_assert(sizeof(IoctlFence) == 8, "IoctlFence has wrong size");
30class Module final { 30class Module final {
31public: 31public:
32 Module(); 32 Module();
33 ~Module() = default; 33 ~Module();
34 34
35 /// Returns a pointer to one of the available devices, identified by its name. 35 /// Returns a pointer to one of the available devices, identified by its name.
36 template <typename T> 36 template <typename T>
diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp
index 0e8e21bad..b7b8b7a1b 100644
--- a/src/core/hle/service/nvdrv/nvmemp.cpp
+++ b/src/core/hle/service/nvdrv/nvmemp.cpp
@@ -16,6 +16,8 @@ NVMEMP::NVMEMP() : ServiceFramework("nvmemp") {
16 RegisterHandlers(functions); 16 RegisterHandlers(functions);
17} 17}
18 18
19NVMEMP::~NVMEMP() = default;
20
19void NVMEMP::Cmd0(Kernel::HLERequestContext& ctx) { 21void NVMEMP::Cmd0(Kernel::HLERequestContext& ctx) {
20 UNIMPLEMENTED(); 22 UNIMPLEMENTED();
21} 23}
diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h
index dfdcabf4a..5a4dfc1f9 100644
--- a/src/core/hle/service/nvdrv/nvmemp.h
+++ b/src/core/hle/service/nvdrv/nvmemp.h
@@ -11,7 +11,7 @@ namespace Service::Nvidia {
11class NVMEMP final : public ServiceFramework<NVMEMP> { 11class NVMEMP final : public ServiceFramework<NVMEMP> {
12public: 12public:
13 NVMEMP(); 13 NVMEMP();
14 ~NVMEMP() = default; 14 ~NVMEMP();
15 15
16private: 16private:
17 void Cmd0(Kernel::HLERequestContext& ctx); 17 void Cmd0(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 8d8962276..34f98fe5a 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -18,6 +18,8 @@ BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
18 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); 18 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle");
19} 19}
20 20
21BufferQueue::~BufferQueue() = default;
22
21void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { 23void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
22 Buffer buffer{}; 24 Buffer buffer{};
23 buffer.slot = slot; 25 buffer.slot = slot;
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index db2e17c0c..17c81928a 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -46,7 +46,7 @@ public:
46 }; 46 };
47 47
48 BufferQueue(u32 id, u64 layer_id); 48 BufferQueue(u32 id, u64 layer_id);
49 ~BufferQueue() = default; 49 ~BufferQueue();
50 50
51 enum class BufferTransformFlags : u32 { 51 enum class BufferTransformFlags : u32 {
52 /// No transform flags are set 52 /// No transform flags are set
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 06040da6f..7455ddd19 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -160,10 +160,13 @@ void NVFlinger::Compose() {
160} 160}
161 161
162Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {} 162Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {}
163Layer::~Layer() = default;
163 164
164Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { 165Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
165 auto& kernel = Core::System::GetInstance().Kernel(); 166 auto& kernel = Core::System::GetInstance().Kernel();
166 vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event"); 167 vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event");
167} 168}
168 169
170Display::~Display() = default;
171
169} // namespace Service::NVFlinger 172} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index f7112949f..3dc69e69b 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -26,7 +26,7 @@ class BufferQueue;
26 26
27struct Layer { 27struct Layer {
28 Layer(u64 id, std::shared_ptr<BufferQueue> queue); 28 Layer(u64 id, std::shared_ptr<BufferQueue> queue);
29 ~Layer() = default; 29 ~Layer();
30 30
31 u64 id; 31 u64 id;
32 std::shared_ptr<BufferQueue> buffer_queue; 32 std::shared_ptr<BufferQueue> buffer_queue;
@@ -34,7 +34,7 @@ struct Layer {
34 34
35struct Display { 35struct Display {
36 Display(u64 id, std::string name); 36 Display(u64 id, std::string name);
37 ~Display() = default; 37 ~Display();
38 38
39 u64 id; 39 u64 id;
40 std::string name; 40 std::string name;
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp
index 6cc3b1992..4fd185f69 100644
--- a/src/core/hle/service/pctl/module.cpp
+++ b/src/core/hle/service/pctl/module.cpp
@@ -142,6 +142,8 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
142Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 142Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
143 : ServiceFramework(name), module(std::move(module)) {} 143 : ServiceFramework(name), module(std::move(module)) {}
144 144
145Module::Interface::~Interface() = default;
146
145void InstallInterfaces(SM::ServiceManager& service_manager) { 147void InstallInterfaces(SM::ServiceManager& service_manager) {
146 auto module = std::make_shared<Module>(); 148 auto module = std::make_shared<Module>();
147 std::make_shared<PCTL>(module, "pctl")->InstallAsService(service_manager); 149 std::make_shared<PCTL>(module, "pctl")->InstallAsService(service_manager);
diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h
index e7d492760..3e449110d 100644
--- a/src/core/hle/service/pctl/module.h
+++ b/src/core/hle/service/pctl/module.h
@@ -13,6 +13,7 @@ public:
13 class Interface : public ServiceFramework<Interface> { 13 class Interface : public ServiceFramework<Interface> {
14 public: 14 public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 15 explicit Interface(std::shared_ptr<Module> module, const char* name);
16 ~Interface() override;
16 17
17 void CreateService(Kernel::HLERequestContext& ctx); 18 void CreateService(Kernel::HLERequestContext& ctx);
18 void CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx); 19 void CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index de2741d66..af9d1433a 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -14,4 +14,6 @@ PCTL::PCTL(std::shared_ptr<Module> module, const char* name)
14 }; 14 };
15 RegisterHandlers(functions); 15 RegisterHandlers(functions);
16} 16}
17
18PCTL::~PCTL() = default;
17} // namespace Service::PCTL 19} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index 8ddf69128..c33ea80b6 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -11,6 +11,7 @@ namespace Service::PCTL {
11class PCTL final : public Module::Interface { 11class PCTL final : public Module::Interface {
12public: 12public:
13 explicit PCTL(std::shared_ptr<Module> module, const char* name); 13 explicit PCTL(std::shared_ptr<Module> module, const char* name);
14 ~PCTL() override;
14}; 15};
15 16
16} // namespace Service::PCTL 17} // namespace Service::PCTL
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 3c43b8d8c..6a9eccfb5 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -1,36 +1,47 @@
1#include <cinttypes> 1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
2#include "common/logging/log.h" 5#include "common/logging/log.h"
3#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
4#include "core/hle/kernel/event.h"
5#include "core/hle/service/prepo/prepo.h" 7#include "core/hle/service/prepo/prepo.h"
8#include "core/hle/service/service.h"
6 9
7namespace Service::PlayReport { 10namespace Service::PlayReport {
8PlayReport::PlayReport(const char* name) : ServiceFramework(name) {
9 static const FunctionInfo functions[] = {
10 {10100, nullptr, "SaveReport"},
11 {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"},
12 {10200, nullptr, "RequestImmediateTransmission"},
13 {10300, nullptr, "GetTransmissionStatus"},
14 {20100, nullptr, "SaveSystemReport"},
15 {20200, nullptr, "SetOperationMode"},
16 {20101, nullptr, "SaveSystemReportWithUser"},
17 {30100, nullptr, "ClearStorage"},
18 {40100, nullptr, "IsUserAgreementCheckEnabled"},
19 {40101, nullptr, "SetUserAgreementCheckEnabled"},
20 {90100, nullptr, "GetStorageUsage"},
21 {90200, nullptr, "GetStatistics"},
22 {90201, nullptr, "GetThroughputHistory"},
23 {90300, nullptr, "GetLastUploadError"},
24 };
25 RegisterHandlers(functions);
26};
27 11
28void PlayReport::SaveReportWithUser(Kernel::HLERequestContext& ctx) { 12class PlayReport final : public ServiceFramework<PlayReport> {
29 // TODO(ogniK): Do we want to add play report? 13public:
30 LOG_WARNING(Service_PREPO, "(STUBBED) called"); 14 explicit PlayReport(const char* name) : ServiceFramework{name} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {10100, nullptr, "SaveReport"},
18 {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"},
19 {10200, nullptr, "RequestImmediateTransmission"},
20 {10300, nullptr, "GetTransmissionStatus"},
21 {20100, nullptr, "SaveSystemReport"},
22 {20200, nullptr, "SetOperationMode"},
23 {20101, nullptr, "SaveSystemReportWithUser"},
24 {30100, nullptr, "ClearStorage"},
25 {40100, nullptr, "IsUserAgreementCheckEnabled"},
26 {40101, nullptr, "SetUserAgreementCheckEnabled"},
27 {90100, nullptr, "GetStorageUsage"},
28 {90200, nullptr, "GetStatistics"},
29 {90201, nullptr, "GetThroughputHistory"},
30 {90300, nullptr, "GetLastUploadError"},
31 };
32 // clang-format on
33
34 RegisterHandlers(functions);
35 }
36
37private:
38 void SaveReportWithUser(Kernel::HLERequestContext& ctx) {
39 // TODO(ogniK): Do we want to add play report?
40 LOG_WARNING(Service_PREPO, "(STUBBED) called");
31 41
32 IPC::ResponseBuilder rb{ctx, 2}; 42 IPC::ResponseBuilder rb{ctx, 2};
33 rb.Push(RESULT_SUCCESS); 43 rb.Push(RESULT_SUCCESS);
44 }
34}; 45};
35 46
36void InstallInterfaces(SM::ServiceManager& service_manager) { 47void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h
index f5a6aba6d..0e7b01331 100644
--- a/src/core/hle/service/prepo/prepo.h
+++ b/src/core/hle/service/prepo/prepo.h
@@ -4,22 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory> 7namespace Service::SM {
8#include <string> 8class ServiceManager;
9#include "core/hle/kernel/event.h" 9}
10#include "core/hle/service/service.h"
11 10
12namespace Service::PlayReport { 11namespace Service::PlayReport {
13 12
14class PlayReport final : public ServiceFramework<PlayReport> {
15public:
16 explicit PlayReport(const char* name);
17 ~PlayReport() = default;
18
19private:
20 void SaveReportWithUser(Kernel::HLERequestContext& ctx);
21};
22
23void InstallInterfaces(SM::ServiceManager& service_manager); 13void InstallInterfaces(SM::ServiceManager& service_manager);
24 14
25} // namespace Service::PlayReport 15} // namespace Service::PlayReport
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 9d804652e..9bb7c7b26 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -74,8 +74,6 @@ using Kernel::SharedPtr;
74 74
75namespace Service { 75namespace Service {
76 76
77std::unordered_map<std::string, SharedPtr<ClientPort>> g_kernel_named_ports;
78
79/** 77/**
80 * Creates a function string for logging, complete with the name (or header code, depending 78 * Creates a function string for logging, complete with the name (or header code, depending
81 * on what's passed in) the port name, and all the cmd_buff arguments. 79 * on what's passed in) the port name, and all the cmd_buff arguments.
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 92b0640e8..59eb20155 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -112,4 +112,6 @@ SET::SET() : ServiceFramework("set") {
112 RegisterHandlers(functions); 112 RegisterHandlers(functions);
113} 113}
114 114
115SET::~SET() = default;
116
115} // namespace Service::Set 117} // namespace Service::Set
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 669e740b7..5f0214359 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -33,7 +33,7 @@ LanguageCode GetLanguageCodeFromIndex(size_t idx);
33class SET final : public ServiceFramework<SET> { 33class SET final : public ServiceFramework<SET> {
34public: 34public:
35 explicit SET(); 35 explicit SET();
36 ~SET() = default; 36 ~SET() override;
37 37
38private: 38private:
39 void GetLanguageCode(Kernel::HLERequestContext& ctx); 39 void GetLanguageCode(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp
index 7066ef725..5af356d10 100644
--- a/src/core/hle/service/set/set_cal.cpp
+++ b/src/core/hle/service/set/set_cal.cpp
@@ -44,4 +44,6 @@ SET_CAL::SET_CAL() : ServiceFramework("set:cal") {
44 RegisterHandlers(functions); 44 RegisterHandlers(functions);
45} 45}
46 46
47SET_CAL::~SET_CAL() = default;
48
47} // namespace Service::Set 49} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_cal.h b/src/core/hle/service/set/set_cal.h
index bb50336aa..583036eac 100644
--- a/src/core/hle/service/set/set_cal.h
+++ b/src/core/hle/service/set/set_cal.h
@@ -11,7 +11,7 @@ namespace Service::Set {
11class SET_CAL final : public ServiceFramework<SET_CAL> { 11class SET_CAL final : public ServiceFramework<SET_CAL> {
12public: 12public:
13 explicit SET_CAL(); 13 explicit SET_CAL();
14 ~SET_CAL() = default; 14 ~SET_CAL();
15}; 15};
16 16
17} // namespace Service::Set 17} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp
index c9f938716..cac6af86d 100644
--- a/src/core/hle/service/set/set_fd.cpp
+++ b/src/core/hle/service/set/set_fd.cpp
@@ -20,4 +20,6 @@ SET_FD::SET_FD() : ServiceFramework("set:fd") {
20 RegisterHandlers(functions); 20 RegisterHandlers(functions);
21} 21}
22 22
23SET_FD::~SET_FD() = default;
24
23} // namespace Service::Set 25} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_fd.h b/src/core/hle/service/set/set_fd.h
index dbd850bc7..216e65f1f 100644
--- a/src/core/hle/service/set/set_fd.h
+++ b/src/core/hle/service/set/set_fd.h
@@ -11,7 +11,7 @@ namespace Service::Set {
11class SET_FD final : public ServiceFramework<SET_FD> { 11class SET_FD final : public ServiceFramework<SET_FD> {
12public: 12public:
13 explicit SET_FD(); 13 explicit SET_FD();
14 ~SET_FD() = default; 14 ~SET_FD() override;
15}; 15};
16 16
17} // namespace Service::Set 17} // namespace Service::Set
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 3211a8346..4342f3b2d 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -109,6 +109,8 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
109 RegisterHandlers(functions); 109 RegisterHandlers(functions);
110} 110}
111 111
112BSD::~BSD() = default;
113
112BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} { 114BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} {
113 // clang-format off 115 // clang-format off
114 static const FunctionInfo functions[] = { 116 static const FunctionInfo functions[] = {
@@ -131,4 +133,6 @@ BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} {
131 RegisterHandlers(functions); 133 RegisterHandlers(functions);
132} 134}
133 135
136BSDCFG::~BSDCFG() = default;
137
134} // namespace Service::Sockets 138} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index c1da59b24..0fe0e65c6 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -12,7 +12,7 @@ namespace Service::Sockets {
12class BSD final : public ServiceFramework<BSD> { 12class BSD final : public ServiceFramework<BSD> {
13public: 13public:
14 explicit BSD(const char* name); 14 explicit BSD(const char* name);
15 ~BSD() = default; 15 ~BSD() override;
16 16
17private: 17private:
18 void RegisterClient(Kernel::HLERequestContext& ctx); 18 void RegisterClient(Kernel::HLERequestContext& ctx);
@@ -29,6 +29,7 @@ private:
29class BSDCFG final : public ServiceFramework<BSDCFG> { 29class BSDCFG final : public ServiceFramework<BSDCFG> {
30public: 30public:
31 explicit BSDCFG(); 31 explicit BSDCFG();
32 ~BSDCFG() override;
32}; 33};
33 34
34} // namespace Service::Sockets 35} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp
index d53c25eec..abbeb4c50 100644
--- a/src/core/hle/service/sockets/ethc.cpp
+++ b/src/core/hle/service/sockets/ethc.cpp
@@ -21,6 +21,8 @@ ETHC_C::ETHC_C() : ServiceFramework{"ethc:c"} {
21 RegisterHandlers(functions); 21 RegisterHandlers(functions);
22} 22}
23 23
24ETHC_C::~ETHC_C() = default;
25
24ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} { 26ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} {
25 // clang-format off 27 // clang-format off
26 static const FunctionInfo functions[] = { 28 static const FunctionInfo functions[] = {
@@ -35,4 +37,6 @@ ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} {
35 RegisterHandlers(functions); 37 RegisterHandlers(functions);
36} 38}
37 39
40ETHC_I::~ETHC_I() = default;
41
38} // namespace Service::Sockets 42} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/ethc.h b/src/core/hle/service/sockets/ethc.h
index 9a3c88100..da2c7f741 100644
--- a/src/core/hle/service/sockets/ethc.h
+++ b/src/core/hle/service/sockets/ethc.h
@@ -11,11 +11,13 @@ namespace Service::Sockets {
11class ETHC_C final : public ServiceFramework<ETHC_C> { 11class ETHC_C final : public ServiceFramework<ETHC_C> {
12public: 12public:
13 explicit ETHC_C(); 13 explicit ETHC_C();
14 ~ETHC_C() override;
14}; 15};
15 16
16class ETHC_I final : public ServiceFramework<ETHC_I> { 17class ETHC_I final : public ServiceFramework<ETHC_I> {
17public: 18public:
18 explicit ETHC_I(); 19 explicit ETHC_I();
20 ~ETHC_I() override;
19}; 21};
20 22
21} // namespace Service::Sockets 23} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp
index 8682dc2e0..e6d73065e 100644
--- a/src/core/hle/service/sockets/nsd.cpp
+++ b/src/core/hle/service/sockets/nsd.cpp
@@ -29,4 +29,6 @@ NSD::NSD(const char* name) : ServiceFramework(name) {
29 RegisterHandlers(functions); 29 RegisterHandlers(functions);
30} 30}
31 31
32NSD::~NSD() = default;
33
32} // namespace Service::Sockets 34} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/nsd.h b/src/core/hle/service/sockets/nsd.h
index 3b7edfc43..d842e3232 100644
--- a/src/core/hle/service/sockets/nsd.h
+++ b/src/core/hle/service/sockets/nsd.h
@@ -12,7 +12,7 @@ namespace Service::Sockets {
12class NSD final : public ServiceFramework<NSD> { 12class NSD final : public ServiceFramework<NSD> {
13public: 13public:
14 explicit NSD(const char* name); 14 explicit NSD(const char* name);
15 ~NSD() = default; 15 ~NSD() override;
16}; 16};
17 17
18} // namespace Service::Sockets 18} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index d235c4cfd..13ab1d31e 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -34,4 +34,6 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") {
34 RegisterHandlers(functions); 34 RegisterHandlers(functions);
35} 35}
36 36
37SFDNSRES::~SFDNSRES() = default;
38
37} // namespace Service::Sockets 39} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h
index 62c7e35bf..eda432903 100644
--- a/src/core/hle/service/sockets/sfdnsres.h
+++ b/src/core/hle/service/sockets/sfdnsres.h
@@ -12,7 +12,7 @@ namespace Service::Sockets {
12class SFDNSRES final : public ServiceFramework<SFDNSRES> { 12class SFDNSRES final : public ServiceFramework<SFDNSRES> {
13public: 13public:
14 explicit SFDNSRES(); 14 explicit SFDNSRES();
15 ~SFDNSRES() = default; 15 ~SFDNSRES() override;
16 16
17private: 17private:
18 void GetAddrInfo(Kernel::HLERequestContext& ctx); 18 void GetAddrInfo(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/spl/csrng.cpp b/src/core/hle/service/spl/csrng.cpp
index b9e6b799d..674928798 100644
--- a/src/core/hle/service/spl/csrng.cpp
+++ b/src/core/hle/service/spl/csrng.cpp
@@ -13,4 +13,6 @@ CSRNG::CSRNG(std::shared_ptr<Module> module) : Module::Interface(std::move(modul
13 RegisterHandlers(functions); 13 RegisterHandlers(functions);
14} 14}
15 15
16CSRNG::~CSRNG() = default;
17
16} // namespace Service::SPL 18} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/csrng.h b/src/core/hle/service/spl/csrng.h
index 3f849b5a7..764d5ceb0 100644
--- a/src/core/hle/service/spl/csrng.h
+++ b/src/core/hle/service/spl/csrng.h
@@ -11,6 +11,7 @@ namespace Service::SPL {
11class CSRNG final : public Module::Interface { 11class CSRNG final : public Module::Interface {
12public: 12public:
13 explicit CSRNG(std::shared_ptr<Module> module); 13 explicit CSRNG(std::shared_ptr<Module> module);
14 ~CSRNG() override;
14}; 15};
15 16
16} // namespace Service::SPL 17} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 3f5a342a7..0d8441fb1 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -16,6 +16,8 @@ namespace Service::SPL {
16Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 16Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
17 : ServiceFramework(name), module(std::move(module)) {} 17 : ServiceFramework(name), module(std::move(module)) {}
18 18
19Module::Interface::~Interface() = default;
20
19void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { 21void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
20 IPC::RequestParser rp{ctx}; 22 IPC::RequestParser rp{ctx};
21 23
diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h
index f24d998e8..48fda6099 100644
--- a/src/core/hle/service/spl/module.h
+++ b/src/core/hle/service/spl/module.h
@@ -13,6 +13,7 @@ public:
13 class Interface : public ServiceFramework<Interface> { 13 class Interface : public ServiceFramework<Interface> {
14 public: 14 public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 15 explicit Interface(std::shared_ptr<Module> module, const char* name);
16 ~Interface() override;
16 17
17 void GetRandomBytes(Kernel::HLERequestContext& ctx); 18 void GetRandomBytes(Kernel::HLERequestContext& ctx);
18 19
diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp
index bb1e03342..70cb41905 100644
--- a/src/core/hle/service/spl/spl.cpp
+++ b/src/core/hle/service/spl/spl.cpp
@@ -42,4 +42,6 @@ SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module),
42 RegisterHandlers(functions); 42 RegisterHandlers(functions);
43} 43}
44 44
45SPL::~SPL() = default;
46
45} // namespace Service::SPL 47} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/spl.h b/src/core/hle/service/spl/spl.h
index 69c4c1747..3637d1623 100644
--- a/src/core/hle/service/spl/spl.h
+++ b/src/core/hle/service/spl/spl.h
@@ -11,6 +11,7 @@ namespace Service::SPL {
11class SPL final : public Module::Interface { 11class SPL final : public Module::Interface {
12public: 12public:
13 explicit SPL(std::shared_ptr<Module> module); 13 explicit SPL(std::shared_ptr<Module> module);
14 ~SPL() override;
14}; 15};
15 16
16} // namespace Service::SPL 17} // namespace Service::SPL
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index 048d5b077..18a5d71d5 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -29,4 +29,6 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
29 RegisterHandlers(functions); 29 RegisterHandlers(functions);
30} 30}
31 31
32Time::~Time() = default;
33
32} // namespace Service::Time 34} // namespace Service::Time
diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h
index 183a53db1..cd6b44dec 100644
--- a/src/core/hle/service/time/interface.h
+++ b/src/core/hle/service/time/interface.h
@@ -11,6 +11,7 @@ namespace Service::Time {
11class Time final : public Module::Interface { 11class Time final : public Module::Interface {
12public: 12public:
13 explicit Time(std::shared_ptr<Module> time, const char* name); 13 explicit Time(std::shared_ptr<Module> time, const char* name);
14 ~Time() override;
14}; 15};
15 16
16} // namespace Service::Time 17} // namespace Service::Time
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 2172c681b..28fd8debc 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -210,6 +210,8 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c
210Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) 210Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
211 : ServiceFramework(name), time(std::move(time)) {} 211 : ServiceFramework(name), time(std::move(time)) {}
212 212
213Module::Interface::~Interface() = default;
214
213void InstallInterfaces(SM::ServiceManager& service_manager) { 215void InstallInterfaces(SM::ServiceManager& service_manager) {
214 auto time = std::make_shared<Module>(); 216 auto time = std::make_shared<Module>();
215 std::make_shared<Time>(time, "time:a")->InstallAsService(service_manager); 217 std::make_shared<Time>(time, "time:a")->InstallAsService(service_manager);
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 8dde28a94..5659ecad3 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -58,6 +58,7 @@ public:
58 class Interface : public ServiceFramework<Interface> { 58 class Interface : public ServiceFramework<Interface> {
59 public: 59 public:
60 explicit Interface(std::shared_ptr<Module> time, const char* name); 60 explicit Interface(std::shared_ptr<Module> time, const char* name);
61 ~Interface() override;
61 62
62 void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); 63 void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
63 void GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx); 64 void GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 993f1e65a..85244ac3b 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -984,6 +984,8 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name,
984 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) 984 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
985 : ServiceFramework(name), module(std::move(module)), nv_flinger(std::move(nv_flinger)) {} 985 : ServiceFramework(name), module(std::move(module)), nv_flinger(std::move(nv_flinger)) {}
986 986
987Module::Interface::~Interface() = default;
988
987void Module::Interface::GetDisplayService(Kernel::HLERequestContext& ctx) { 989void Module::Interface::GetDisplayService(Kernel::HLERequestContext& ctx) {
988 LOG_WARNING(Service_VI, "(STUBBED) called"); 990 LOG_WARNING(Service_VI, "(STUBBED) called");
989 991
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 92f5b6059..c2dc83605 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -26,6 +26,7 @@ public:
26 public: 26 public:
27 explicit Interface(std::shared_ptr<Module> module, const char* name, 27 explicit Interface(std::shared_ptr<Module> module, const char* name,
28 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); 28 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
29 ~Interface() override;
29 30
30 void GetDisplayService(Kernel::HLERequestContext& ctx); 31 void GetDisplayService(Kernel::HLERequestContext& ctx);
31 32
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp
index d47da565b..207c06b16 100644
--- a/src/core/hle/service/vi/vi_m.cpp
+++ b/src/core/hle/service/vi/vi_m.cpp
@@ -15,4 +15,6 @@ VI_M::VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger>
15 RegisterHandlers(functions); 15 RegisterHandlers(functions);
16} 16}
17 17
18VI_M::~VI_M() = default;
19
18} // namespace Service::VI 20} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h
index 6abb9b3a3..487d58d50 100644
--- a/src/core/hle/service/vi/vi_m.h
+++ b/src/core/hle/service/vi/vi_m.h
@@ -11,6 +11,7 @@ namespace Service::VI {
11class VI_M final : public Module::Interface { 11class VI_M final : public Module::Interface {
12public: 12public:
13 explicit VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); 13 explicit VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
14 ~VI_M() override;
14}; 15};
15 16
16} // namespace Service::VI 17} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp
index 8f82e797f..920e6a1f6 100644
--- a/src/core/hle/service/vi/vi_s.cpp
+++ b/src/core/hle/service/vi/vi_s.cpp
@@ -15,4 +15,6 @@ VI_S::VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger>
15 RegisterHandlers(functions); 15 RegisterHandlers(functions);
16} 16}
17 17
18VI_S::~VI_S() = default;
19
18} // namespace Service::VI 20} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h
index 8f16f804f..bbc31148f 100644
--- a/src/core/hle/service/vi/vi_s.h
+++ b/src/core/hle/service/vi/vi_s.h
@@ -11,6 +11,7 @@ namespace Service::VI {
11class VI_S final : public Module::Interface { 11class VI_S final : public Module::Interface {
12public: 12public:
13 explicit VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); 13 explicit VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
14 ~VI_S() override;
14}; 15};
15 16
16} // namespace Service::VI 17} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp
index b84aed1d5..d81e410d6 100644
--- a/src/core/hle/service/vi/vi_u.cpp
+++ b/src/core/hle/service/vi/vi_u.cpp
@@ -14,4 +14,6 @@ VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger>
14 RegisterHandlers(functions); 14 RegisterHandlers(functions);
15} 15}
16 16
17VI_U::~VI_U() = default;
18
17} // namespace Service::VI 19} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h
index e9b4f76b2..b92f28c92 100644
--- a/src/core/hle/service/vi/vi_u.h
+++ b/src/core/hle/service/vi/vi_u.h
@@ -11,6 +11,7 @@ namespace Service::VI {
11class VI_U final : public Module::Interface { 11class VI_U final : public Module::Interface {
12public: 12public:
13 explicit VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); 13 explicit VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
14 ~VI_U() override;
14}; 15};
15 16
16} // namespace Service::VI 17} // namespace Service::VI
diff --git a/src/core/settings.h b/src/core/settings.h
index c25f8ba70..0318d019c 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <atomic>
8#include <string> 9#include <string>
9#include "common/common_types.h" 10#include "common/common_types.h"
10 11
@@ -120,6 +121,7 @@ struct Values {
120 std::array<std::string, NativeAnalog::NumAnalogs> analogs; 121 std::array<std::string, NativeAnalog::NumAnalogs> analogs;
121 std::string motion_device; 122 std::string motion_device;
122 std::string touch_device; 123 std::string touch_device;
124 std::atomic_bool is_device_reload_pending{true};
123 125
124 // Core 126 // Core
125 bool use_cpu_jit; 127 bool use_cpu_jit;
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index b12623d55..37f572853 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory> 5#include <memory>
6#include <thread>
6#include "common/param_package.h" 7#include "common/param_package.h"
7#include "input_common/analog_from_button.h" 8#include "input_common/analog_from_button.h"
8#include "input_common/keyboard.h" 9#include "input_common/keyboard.h"
@@ -17,6 +18,10 @@ namespace InputCommon {
17static std::shared_ptr<Keyboard> keyboard; 18static std::shared_ptr<Keyboard> keyboard;
18static std::shared_ptr<MotionEmu> motion_emu; 19static std::shared_ptr<MotionEmu> motion_emu;
19 20
21#ifdef HAVE_SDL2
22static std::thread poll_thread;
23#endif
24
20void Init() { 25void Init() {
21 keyboard = std::make_shared<Keyboard>(); 26 keyboard = std::make_shared<Keyboard>();
22 Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); 27 Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
@@ -30,6 +35,12 @@ void Init() {
30#endif 35#endif
31} 36}
32 37
38void StartJoystickEventHandler() {
39#ifdef HAVE_SDL2
40 poll_thread = std::thread(SDL::PollLoop);
41#endif
42}
43
33void Shutdown() { 44void Shutdown() {
34 Input::UnregisterFactory<Input::ButtonDevice>("keyboard"); 45 Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
35 keyboard.reset(); 46 keyboard.reset();
@@ -39,6 +50,7 @@ void Shutdown() {
39 50
40#ifdef HAVE_SDL2 51#ifdef HAVE_SDL2
41 SDL::Shutdown(); 52 SDL::Shutdown();
53 poll_thread.join();
42#endif 54#endif
43} 55}
44 56
diff --git a/src/input_common/main.h b/src/input_common/main.h
index 77a0ce90b..9eb13106e 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -20,6 +20,8 @@ void Init();
20/// Deregisters all built-in input device factories and shuts them down. 20/// Deregisters all built-in input device factories and shuts them down.
21void Shutdown(); 21void Shutdown();
22 22
23void StartJoystickEventHandler();
24
23class Keyboard; 25class Keyboard;
24 26
25/// Gets the keyboard button device factory. 27/// Gets the keyboard button device factory.
diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp
index d1b960fd7..faf3c1fa3 100644
--- a/src/input_common/sdl/sdl.cpp
+++ b/src/input_common/sdl/sdl.cpp
@@ -2,15 +2,24 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <atomic>
5#include <cmath> 7#include <cmath>
8#include <functional>
9#include <iterator>
10#include <mutex>
6#include <string> 11#include <string>
12#include <thread>
7#include <tuple> 13#include <tuple>
8#include <unordered_map> 14#include <unordered_map>
9#include <utility> 15#include <utility>
16#include <vector>
10#include <SDL.h> 17#include <SDL.h>
18#include "common/assert.h"
11#include "common/logging/log.h" 19#include "common/logging/log.h"
12#include "common/math_util.h" 20#include "common/math_util.h"
13#include "common/param_package.h" 21#include "common/param_package.h"
22#include "common/threadsafe_queue.h"
14#include "input_common/main.h" 23#include "input_common/main.h"
15#include "input_common/sdl/sdl.h" 24#include "input_common/sdl/sdl.h"
16 25
@@ -21,33 +30,51 @@ namespace SDL {
21class SDLJoystick; 30class SDLJoystick;
22class SDLButtonFactory; 31class SDLButtonFactory;
23class SDLAnalogFactory; 32class SDLAnalogFactory;
24static std::unordered_map<int, std::weak_ptr<SDLJoystick>> joystick_list; 33
34/// Map of GUID of a list of corresponding virtual Joysticks
35static std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
36static std::mutex joystick_map_mutex;
37
25static std::shared_ptr<SDLButtonFactory> button_factory; 38static std::shared_ptr<SDLButtonFactory> button_factory;
26static std::shared_ptr<SDLAnalogFactory> analog_factory; 39static std::shared_ptr<SDLAnalogFactory> analog_factory;
27 40
28static bool initialized = false; 41/// Used by the Pollers during config
42static std::atomic<bool> polling;
43static Common::SPSCQueue<SDL_Event> event_queue;
44
45static std::atomic<bool> initialized = false;
46
47static std::string GetGUID(SDL_Joystick* joystick) {
48 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
49 char guid_str[33];
50 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
51 return guid_str;
52}
29 53
30class SDLJoystick { 54class SDLJoystick {
31public: 55public:
32 explicit SDLJoystick(int joystick_index) 56 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
33 : joystick{SDL_JoystickOpen(joystick_index), SDL_JoystickClose} { 57 decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose)
34 if (!joystick) { 58 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, deleter} {}
35 LOG_ERROR(Input, "failed to open joystick {}", joystick_index); 59
36 } 60 void SetButton(int button, bool value) {
61 std::lock_guard<std::mutex> lock(mutex);
62 state.buttons[button] = value;
37 } 63 }
38 64
39 bool GetButton(int button) const { 65 bool GetButton(int button) const {
40 if (!joystick) 66 std::lock_guard<std::mutex> lock(mutex);
41 return {}; 67 return state.buttons.at(button);
42 SDL_JoystickUpdate(); 68 }
43 return SDL_JoystickGetButton(joystick.get(), button) == 1; 69
70 void SetAxis(int axis, Sint16 value) {
71 std::lock_guard<std::mutex> lock(mutex);
72 state.axes[axis] = value;
44 } 73 }
45 74
46 float GetAxis(int axis) const { 75 float GetAxis(int axis) const {
47 if (!joystick) 76 std::lock_guard<std::mutex> lock(mutex);
48 return {}; 77 return state.axes.at(axis) / 32767.0f;
49 SDL_JoystickUpdate();
50 return SDL_JoystickGetAxis(joystick.get(), axis) / 32767.0f;
51 } 78 }
52 79
53 std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { 80 std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const {
@@ -67,18 +94,213 @@ public:
67 return std::make_tuple(x, y); 94 return std::make_tuple(x, y);
68 } 95 }
69 96
97 void SetHat(int hat, Uint8 direction) {
98 std::lock_guard<std::mutex> lock(mutex);
99 state.hats[hat] = direction;
100 }
101
70 bool GetHatDirection(int hat, Uint8 direction) const { 102 bool GetHatDirection(int hat, Uint8 direction) const {
71 return (SDL_JoystickGetHat(joystick.get(), hat) & direction) != 0; 103 std::lock_guard<std::mutex> lock(mutex);
104 return (state.hats.at(hat) & direction) != 0;
105 }
106 /**
107 * The guid of the joystick
108 */
109 const std::string& GetGUID() const {
110 return guid;
111 }
112
113 /**
114 * The number of joystick from the same type that were connected before this joystick
115 */
116 int GetPort() const {
117 return port;
118 }
119
120 SDL_Joystick* GetSDLJoystick() const {
121 return sdl_joystick.get();
72 } 122 }
73 123
74 SDL_JoystickID GetJoystickID() const { 124 void SetSDLJoystick(SDL_Joystick* joystick,
75 return SDL_JoystickInstanceID(joystick.get()); 125 decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) {
126 sdl_joystick =
127 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)>(joystick, deleter);
76 } 128 }
77 129
78private: 130private:
79 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> joystick; 131 struct State {
132 std::unordered_map<int, bool> buttons;
133 std::unordered_map<int, Sint16> axes;
134 std::unordered_map<int, Uint8> hats;
135 } state;
136 std::string guid;
137 int port;
138 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
139 mutable std::mutex mutex;
80}; 140};
81 141
142/**
143 * Get the nth joystick with the corresponding GUID
144 */
145static std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port) {
146 std::lock_guard<std::mutex> lock(joystick_map_mutex);
147 const auto it = joystick_map.find(guid);
148 if (it != joystick_map.end()) {
149 while (it->second.size() <= port) {
150 auto joystick = std::make_shared<SDLJoystick>(guid, it->second.size(), nullptr,
151 [](SDL_Joystick*) {});
152 it->second.emplace_back(std::move(joystick));
153 }
154 return it->second[port];
155 }
156 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, [](SDL_Joystick*) {});
157 return joystick_map[guid].emplace_back(std::move(joystick));
158}
159
160/**
161 * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie
162 * it to a SDLJoystick with the same guid and that port
163 */
164static std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
165 std::lock_guard<std::mutex> lock(joystick_map_mutex);
166 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
167 const std::string guid = GetGUID(sdl_joystick);
168 auto map_it = joystick_map.find(guid);
169 if (map_it != joystick_map.end()) {
170 auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
171 [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
172 return sdl_joystick == joystick->GetSDLJoystick();
173 });
174 if (vec_it != map_it->second.end()) {
175 // This is the common case: There is already an existing SDL_Joystick maped to a
176 // SDLJoystick. return the SDLJoystick
177 return *vec_it;
178 }
179 // Search for a SDLJoystick without a mapped SDL_Joystick...
180 auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
181 [](const std::shared_ptr<SDLJoystick>& joystick) {
182 return !joystick->GetSDLJoystick();
183 });
184 if (nullptr_it != map_it->second.end()) {
185 // ... and map it
186 (*nullptr_it)->SetSDLJoystick(sdl_joystick);
187 return *nullptr_it;
188 }
189 // There is no SDLJoystick without a mapped SDL_Joystick
190 // Create a new SDLJoystick
191 auto joystick = std::make_shared<SDLJoystick>(guid, map_it->second.size(), sdl_joystick);
192 return map_it->second.emplace_back(std::move(joystick));
193 }
194 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
195 return joystick_map[guid].emplace_back(std::move(joystick));
196}
197
198void InitJoystick(int joystick_index) {
199 std::lock_guard<std::mutex> lock(joystick_map_mutex);
200 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
201 if (!sdl_joystick) {
202 LOG_ERROR(Input, "failed to open joystick {}", joystick_index);
203 return;
204 }
205 std::string guid = GetGUID(sdl_joystick);
206 if (joystick_map.find(guid) == joystick_map.end()) {
207 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
208 joystick_map[guid].emplace_back(std::move(joystick));
209 return;
210 }
211 auto& joystick_guid_list = joystick_map[guid];
212 const auto it = std::find_if(
213 joystick_guid_list.begin(), joystick_guid_list.end(),
214 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); });
215 if (it != joystick_guid_list.end()) {
216 (*it)->SetSDLJoystick(sdl_joystick);
217 return;
218 }
219 auto joystick = std::make_shared<SDLJoystick>(guid, joystick_guid_list.size(), sdl_joystick);
220 joystick_guid_list.emplace_back(std::move(joystick));
221}
222
223void CloseJoystick(SDL_Joystick* sdl_joystick) {
224 std::lock_guard<std::mutex> lock(joystick_map_mutex);
225 std::string guid = GetGUID(sdl_joystick);
226 // This call to guid is save since the joystick is guranteed to be in that map
227 auto& joystick_guid_list = joystick_map[guid];
228 const auto joystick_it =
229 std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
230 [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
231 return joystick->GetSDLJoystick() == sdl_joystick;
232 });
233 (*joystick_it)->SetSDLJoystick(nullptr, [](SDL_Joystick*) {});
234}
235
236void HandleGameControllerEvent(const SDL_Event& event) {
237 switch (event.type) {
238 case SDL_JOYBUTTONUP: {
239 auto joystick = GetSDLJoystickBySDLID(event.jbutton.which);
240 if (joystick) {
241 joystick->SetButton(event.jbutton.button, false);
242 }
243 break;
244 }
245 case SDL_JOYBUTTONDOWN: {
246 auto joystick = GetSDLJoystickBySDLID(event.jbutton.which);
247 if (joystick) {
248 joystick->SetButton(event.jbutton.button, true);
249 }
250 break;
251 }
252 case SDL_JOYHATMOTION: {
253 auto joystick = GetSDLJoystickBySDLID(event.jhat.which);
254 if (joystick) {
255 joystick->SetHat(event.jhat.hat, event.jhat.value);
256 }
257 break;
258 }
259 case SDL_JOYAXISMOTION: {
260 auto joystick = GetSDLJoystickBySDLID(event.jaxis.which);
261 if (joystick) {
262 joystick->SetAxis(event.jaxis.axis, event.jaxis.value);
263 }
264 break;
265 }
266 case SDL_JOYDEVICEREMOVED:
267 LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
268 CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
269 break;
270 case SDL_JOYDEVICEADDED:
271 LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which);
272 InitJoystick(event.jdevice.which);
273 break;
274 }
275}
276
277void CloseSDLJoysticks() {
278 std::lock_guard<std::mutex> lock(joystick_map_mutex);
279 joystick_map.clear();
280}
281
282void PollLoop() {
283 if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
284 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
285 return;
286 }
287
288 SDL_Event event;
289 while (initialized) {
290 // Wait for 10 ms or until an event happens
291 if (SDL_WaitEventTimeout(&event, 10)) {
292 // Don't handle the event if we are configuring
293 if (polling) {
294 event_queue.Push(event);
295 } else {
296 HandleGameControllerEvent(event);
297 }
298 }
299 }
300 CloseSDLJoysticks();
301 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
302}
303
82class SDLButton final : public Input::ButtonDevice { 304class SDLButton final : public Input::ButtonDevice {
83public: 305public:
84 explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_) 306 explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_)
@@ -144,22 +366,14 @@ private:
144 int axis_y; 366 int axis_y;
145}; 367};
146 368
147static std::shared_ptr<SDLJoystick> GetJoystick(int joystick_index) {
148 std::shared_ptr<SDLJoystick> joystick = joystick_list[joystick_index].lock();
149 if (!joystick) {
150 joystick = std::make_shared<SDLJoystick>(joystick_index);
151 joystick_list[joystick_index] = joystick;
152 }
153 return joystick;
154}
155
156/// A button device factory that creates button devices from SDL joystick 369/// A button device factory that creates button devices from SDL joystick
157class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { 370class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
158public: 371public:
159 /** 372 /**
160 * Creates a button device from a joystick button 373 * Creates a button device from a joystick button
161 * @param params contains parameters for creating the device: 374 * @param params contains parameters for creating the device:
162 * - "joystick": the index of the joystick to bind 375 * - "guid": the guid of the joystick to bind
376 * - "port": the nth joystick of the same type to bind
163 * - "button"(optional): the index of the button to bind 377 * - "button"(optional): the index of the button to bind
164 * - "hat"(optional): the index of the hat to bind as direction buttons 378 * - "hat"(optional): the index of the hat to bind as direction buttons
165 * - "axis"(optional): the index of the axis to bind 379 * - "axis"(optional): the index of the axis to bind
@@ -167,12 +381,15 @@ public:
167 * "down", "left" or "right" 381 * "down", "left" or "right"
168 * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is 382 * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is
169 * triggered if the axis value crosses 383 * triggered if the axis value crosses
170 * - "direction"(only used for axis): "+" means the button is triggered when the axis value 384 * - "direction"(only used for axis): "+" means the button is triggered when the axis
171 * is greater than the threshold; "-" means the button is triggered when the axis value 385 * value is greater than the threshold; "-" means the button is triggered when the axis
172 * is smaller than the threshold 386 * value is smaller than the threshold
173 */ 387 */
174 std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override { 388 std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override {
175 const int joystick_index = params.Get("joystick", 0); 389 const std::string guid = params.Get("guid", "0");
390 const int port = params.Get("port", 0);
391
392 auto joystick = GetSDLJoystickByGUID(guid, port);
176 393
177 if (params.Has("hat")) { 394 if (params.Has("hat")) {
178 const int hat = params.Get("hat", 0); 395 const int hat = params.Get("hat", 0);
@@ -189,8 +406,9 @@ public:
189 } else { 406 } else {
190 direction = 0; 407 direction = 0;
191 } 408 }
192 return std::make_unique<SDLDirectionButton>(GetJoystick(joystick_index), hat, 409 // This is necessary so accessing GetHat with hat won't crash
193 direction); 410 joystick->SetHat(hat, SDL_HAT_CENTERED);
411 return std::make_unique<SDLDirectionButton>(joystick, hat, direction);
194 } 412 }
195 413
196 if (params.Has("axis")) { 414 if (params.Has("axis")) {
@@ -206,12 +424,15 @@ public:
206 trigger_if_greater = true; 424 trigger_if_greater = true;
207 LOG_ERROR(Input, "Unknown direction '{}'", direction_name); 425 LOG_ERROR(Input, "Unknown direction '{}'", direction_name);
208 } 426 }
209 return std::make_unique<SDLAxisButton>(GetJoystick(joystick_index), axis, threshold, 427 // This is necessary so accessing GetAxis with axis won't crash
210 trigger_if_greater); 428 joystick->SetAxis(axis, 0);
429 return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater);
211 } 430 }
212 431
213 const int button = params.Get("button", 0); 432 const int button = params.Get("button", 0);
214 return std::make_unique<SDLButton>(GetJoystick(joystick_index), button); 433 // This is necessary so accessing GetButton with button won't crash
434 joystick->SetButton(button, false);
435 return std::make_unique<SDLButton>(joystick, button);
215 } 436 }
216}; 437};
217 438
@@ -221,27 +442,32 @@ public:
221 /** 442 /**
222 * Creates analog device from joystick axes 443 * Creates analog device from joystick axes
223 * @param params contains parameters for creating the device: 444 * @param params contains parameters for creating the device:
224 * - "joystick": the index of the joystick to bind 445 * - "guid": the guid of the joystick to bind
446 * - "port": the nth joystick of the same type
225 * - "axis_x": the index of the axis to be bind as x-axis 447 * - "axis_x": the index of the axis to be bind as x-axis
226 * - "axis_y": the index of the axis to be bind as y-axis 448 * - "axis_y": the index of the axis to be bind as y-axis
227 */ 449 */
228 std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override { 450 std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override {
229 const int joystick_index = params.Get("joystick", 0); 451 const std::string guid = params.Get("guid", "0");
452 const int port = params.Get("port", 0);
230 const int axis_x = params.Get("axis_x", 0); 453 const int axis_x = params.Get("axis_x", 0);
231 const int axis_y = params.Get("axis_y", 1); 454 const int axis_y = params.Get("axis_y", 1);
232 return std::make_unique<SDLAnalog>(GetJoystick(joystick_index), axis_x, axis_y); 455
456 auto joystick = GetSDLJoystickByGUID(guid, port);
457
458 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
459 joystick->SetAxis(axis_x, 0);
460 joystick->SetAxis(axis_y, 0);
461 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y);
233 } 462 }
234}; 463};
235 464
236void Init() { 465void Init() {
237 if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { 466 using namespace Input;
238 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); 467 RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>());
239 } else { 468 RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>());
240 using namespace Input; 469 polling = false;
241 RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>()); 470 initialized = true;
242 RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>());
243 initialized = true;
244 }
245} 471}
246 472
247void Shutdown() { 473void Shutdown() {
@@ -249,30 +475,17 @@ void Shutdown() {
249 using namespace Input; 475 using namespace Input;
250 UnregisterFactory<ButtonDevice>("sdl"); 476 UnregisterFactory<ButtonDevice>("sdl");
251 UnregisterFactory<AnalogDevice>("sdl"); 477 UnregisterFactory<AnalogDevice>("sdl");
252 SDL_QuitSubSystem(SDL_INIT_JOYSTICK); 478 initialized = false;
253 } 479 }
254} 480}
255 481
256/**
257 * This function converts a joystick ID used in SDL events to the device index. This is necessary
258 * because Citra opens joysticks using their indices, not their IDs.
259 */
260static int JoystickIDToDeviceIndex(SDL_JoystickID id) {
261 int num_joysticks = SDL_NumJoysticks();
262 for (int i = 0; i < num_joysticks; i++) {
263 auto joystick = GetJoystick(i);
264 if (joystick->GetJoystickID() == id) {
265 return i;
266 }
267 }
268 return -1;
269}
270
271Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) { 482Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) {
272 Common::ParamPackage params({{"engine", "sdl"}}); 483 Common::ParamPackage params({{"engine", "sdl"}});
273 switch (event.type) { 484 switch (event.type) {
274 case SDL_JOYAXISMOTION: 485 case SDL_JOYAXISMOTION: {
275 params.Set("joystick", JoystickIDToDeviceIndex(event.jaxis.which)); 486 auto joystick = GetSDLJoystickBySDLID(event.jaxis.which);
487 params.Set("port", joystick->GetPort());
488 params.Set("guid", joystick->GetGUID());
276 params.Set("axis", event.jaxis.axis); 489 params.Set("axis", event.jaxis.axis);
277 if (event.jaxis.value > 0) { 490 if (event.jaxis.value > 0) {
278 params.Set("direction", "+"); 491 params.Set("direction", "+");
@@ -282,12 +495,18 @@ Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) {
282 params.Set("threshold", "-0.5"); 495 params.Set("threshold", "-0.5");
283 } 496 }
284 break; 497 break;
285 case SDL_JOYBUTTONUP: 498 }
286 params.Set("joystick", JoystickIDToDeviceIndex(event.jbutton.which)); 499 case SDL_JOYBUTTONUP: {
500 auto joystick = GetSDLJoystickBySDLID(event.jbutton.which);
501 params.Set("port", joystick->GetPort());
502 params.Set("guid", joystick->GetGUID());
287 params.Set("button", event.jbutton.button); 503 params.Set("button", event.jbutton.button);
288 break; 504 break;
289 case SDL_JOYHATMOTION: 505 }
290 params.Set("joystick", JoystickIDToDeviceIndex(event.jhat.which)); 506 case SDL_JOYHATMOTION: {
507 auto joystick = GetSDLJoystickBySDLID(event.jhat.which);
508 params.Set("port", joystick->GetPort());
509 params.Set("guid", joystick->GetGUID());
291 params.Set("hat", event.jhat.hat); 510 params.Set("hat", event.jhat.hat);
292 switch (event.jhat.value) { 511 switch (event.jhat.value) {
293 case SDL_HAT_UP: 512 case SDL_HAT_UP:
@@ -307,6 +526,7 @@ Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) {
307 } 526 }
308 break; 527 break;
309 } 528 }
529 }
310 return params; 530 return params;
311} 531}
312 532
@@ -315,31 +535,20 @@ namespace Polling {
315class SDLPoller : public InputCommon::Polling::DevicePoller { 535class SDLPoller : public InputCommon::Polling::DevicePoller {
316public: 536public:
317 void Start() override { 537 void Start() override {
318 // SDL joysticks must be opened, otherwise they don't generate events 538 event_queue.Clear();
319 SDL_JoystickUpdate(); 539 polling = true;
320 int num_joysticks = SDL_NumJoysticks();
321 for (int i = 0; i < num_joysticks; i++) {
322 joysticks_opened.emplace_back(GetJoystick(i));
323 }
324 // Empty event queue to get rid of old events. citra-qt doesn't use the queue
325 SDL_Event dummy;
326 while (SDL_PollEvent(&dummy)) {
327 }
328 } 540 }
329 541
330 void Stop() override { 542 void Stop() override {
331 joysticks_opened.clear(); 543 polling = false;
332 } 544 }
333
334private:
335 std::vector<std::shared_ptr<SDLJoystick>> joysticks_opened;
336}; 545};
337 546
338class SDLButtonPoller final : public SDLPoller { 547class SDLButtonPoller final : public SDLPoller {
339public: 548public:
340 Common::ParamPackage GetNextInput() override { 549 Common::ParamPackage GetNextInput() override {
341 SDL_Event event; 550 SDL_Event event;
342 while (SDL_PollEvent(&event)) { 551 while (event_queue.Pop(event)) {
343 switch (event.type) { 552 switch (event.type) {
344 case SDL_JOYAXISMOTION: 553 case SDL_JOYAXISMOTION:
345 if (std::abs(event.jaxis.value / 32767.0) < 0.5) { 554 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
@@ -367,7 +576,7 @@ public:
367 576
368 Common::ParamPackage GetNextInput() override { 577 Common::ParamPackage GetNextInput() override {
369 SDL_Event event; 578 SDL_Event event;
370 while (SDL_PollEvent(&event)) { 579 while (event_queue.Pop(event)) {
371 if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { 580 if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) {
372 continue; 581 continue;
373 } 582 }
@@ -384,8 +593,10 @@ public:
384 } 593 }
385 Common::ParamPackage params; 594 Common::ParamPackage params;
386 if (analog_xaxis != -1 && analog_yaxis != -1) { 595 if (analog_xaxis != -1 && analog_yaxis != -1) {
596 auto joystick = GetSDLJoystickBySDLID(event.jaxis.which);
387 params.Set("engine", "sdl"); 597 params.Set("engine", "sdl");
388 params.Set("joystick", JoystickIDToDeviceIndex(analog_axes_joystick)); 598 params.Set("port", joystick->GetPort());
599 params.Set("guid", joystick->GetGUID());
389 params.Set("axis_x", analog_xaxis); 600 params.Set("axis_x", analog_xaxis);
390 params.Set("axis_y", analog_yaxis); 601 params.Set("axis_y", analog_yaxis);
391 analog_xaxis = -1; 602 analog_xaxis = -1;
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h
index 7934099d4..0206860d3 100644
--- a/src/input_common/sdl/sdl.h
+++ b/src/input_common/sdl/sdl.h
@@ -28,6 +28,15 @@ void Init();
28/// Unresisters SDL device factories and shut them down. 28/// Unresisters SDL device factories and shut them down.
29void Shutdown(); 29void Shutdown();
30 30
31/// Needs to be called before SDL_QuitSubSystem.
32void CloseSDLJoysticks();
33
34/// Handle SDL_Events for joysticks from SDL_PollEvent
35void HandleGameControllerEvent(const SDL_Event& event);
36
37/// A Loop that calls HandleGameControllerEvent until Shutdown is called
38void PollLoop();
39
31/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice 40/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
32Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event); 41Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event);
33 42
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index d5831e752..2625ddfdc 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -28,98 +28,106 @@ enum class BufferMethods {
28 CountBufferMethods = 0x40, 28 CountBufferMethods = 0x40,
29}; 29};
30 30
31void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) { 31MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB(128, 128, 192));
32 LOG_TRACE(HW_GPU,
33 "Processing method {:08X} on subchannel {} value "
34 "{:08X} remaining params {}",
35 method, subchannel, value, remaining_params);
36
37 ASSERT(subchannel < bound_engines.size());
38
39 if (method == static_cast<u32>(BufferMethods::BindObject)) {
40 // Bind the current subchannel to the desired engine id.
41 LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value);
42 bound_engines[subchannel] = static_cast<EngineID>(value);
43 return;
44 }
45 32
46 if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) { 33void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) {
47 // TODO(Subv): Research and implement these methods. 34 MICROPROFILE_SCOPE(ProcessCommandLists);
48 LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
49 return;
50 }
51 35
52 const EngineID engine = bound_engines[subchannel]; 36 auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) {
53 37 LOG_TRACE(HW_GPU,
54 switch (engine) { 38 "Processing method {:08X} on subchannel {} value "
55 case EngineID::FERMI_TWOD_A: 39 "{:08X} remaining params {}",
56 fermi_2d->WriteReg(method, value); 40 method, subchannel, value, remaining_params);
57 break;
58 case EngineID::MAXWELL_B:
59 maxwell_3d->WriteReg(method, value, remaining_params);
60 break;
61 case EngineID::MAXWELL_COMPUTE_B:
62 maxwell_compute->WriteReg(method, value);
63 break;
64 case EngineID::MAXWELL_DMA_COPY_A:
65 maxwell_dma->WriteReg(method, value);
66 break;
67 default:
68 UNIMPLEMENTED_MSG("Unimplemented engine");
69 }
70}
71 41
72void GPU::ProcessCommandList(GPUVAddr address, u32 size) { 42 ASSERT(subchannel < bound_engines.size());
73 const boost::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address); 43
74 VAddr current_addr = *head_address; 44 if (method == static_cast<u32>(BufferMethods::BindObject)) {
75 while (current_addr < *head_address + size * sizeof(CommandHeader)) { 45 // Bind the current subchannel to the desired engine id.
76 const CommandHeader header = {Memory::Read32(current_addr)}; 46 LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value);
77 current_addr += sizeof(u32); 47 bound_engines[subchannel] = static_cast<EngineID>(value);
78 48 return;
79 switch (header.mode.Value()) {
80 case SubmissionMode::IncreasingOld:
81 case SubmissionMode::Increasing: {
82 // Increase the method value with each argument.
83 for (unsigned i = 0; i < header.arg_count; ++i) {
84 WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr),
85 header.arg_count - i - 1);
86 current_addr += sizeof(u32);
87 }
88 break;
89 } 49 }
90 case SubmissionMode::NonIncreasingOld: 50
91 case SubmissionMode::NonIncreasing: { 51 if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
92 // Use the same method value for all arguments. 52 // TODO(Subv): Research and implement these methods.
93 for (unsigned i = 0; i < header.arg_count; ++i) { 53 LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
94 WriteReg(header.method, header.subchannel, Memory::Read32(current_addr), 54 return;
95 header.arg_count - i - 1); 55 }
96 current_addr += sizeof(u32); 56
97 } 57 const EngineID engine = bound_engines[subchannel];
58
59 switch (engine) {
60 case EngineID::FERMI_TWOD_A:
61 fermi_2d->WriteReg(method, value);
62 break;
63 case EngineID::MAXWELL_B:
64 maxwell_3d->WriteReg(method, value, remaining_params);
98 break; 65 break;
66 case EngineID::MAXWELL_COMPUTE_B:
67 maxwell_compute->WriteReg(method, value);
68 break;
69 case EngineID::MAXWELL_DMA_COPY_A:
70 maxwell_dma->WriteReg(method, value);
71 break;
72 default:
73 UNIMPLEMENTED_MSG("Unimplemented engine");
99 } 74 }
100 case SubmissionMode::IncreaseOnce: { 75 };
101 ASSERT(header.arg_count.Value() >= 1);
102 76
103 // Use the original method for the first argument and then the next method for all other 77 for (auto entry : commands) {
104 // arguments. 78 Tegra::GPUVAddr address = entry.Address();
105 WriteReg(header.method, header.subchannel, Memory::Read32(current_addr), 79 u32 size = entry.sz;
106 header.arg_count - 1); 80 const boost::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address);
81 VAddr current_addr = *head_address;
82 while (current_addr < *head_address + size * sizeof(CommandHeader)) {
83 const CommandHeader header = {Memory::Read32(current_addr)};
107 current_addr += sizeof(u32); 84 current_addr += sizeof(u32);
108 85
109 for (unsigned i = 1; i < header.arg_count; ++i) { 86 switch (header.mode.Value()) {
110 WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr), 87 case SubmissionMode::IncreasingOld:
111 header.arg_count - i - 1); 88 case SubmissionMode::Increasing: {
89 // Increase the method value with each argument.
90 for (unsigned i = 0; i < header.arg_count; ++i) {
91 WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr),
92 header.arg_count - i - 1);
93 current_addr += sizeof(u32);
94 }
95 break;
96 }
97 case SubmissionMode::NonIncreasingOld:
98 case SubmissionMode::NonIncreasing: {
99 // Use the same method value for all arguments.
100 for (unsigned i = 0; i < header.arg_count; ++i) {
101 WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
102 header.arg_count - i - 1);
103 current_addr += sizeof(u32);
104 }
105 break;
106 }
107 case SubmissionMode::IncreaseOnce: {
108 ASSERT(header.arg_count.Value() >= 1);
109
110 // Use the original method for the first argument and then the next method for all
111 // other arguments.
112 WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
113 header.arg_count - 1);
112 current_addr += sizeof(u32); 114 current_addr += sizeof(u32);
115
116 for (unsigned i = 1; i < header.arg_count; ++i) {
117 WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr),
118 header.arg_count - i - 1);
119 current_addr += sizeof(u32);
120 }
121 break;
122 }
123 case SubmissionMode::Inline: {
124 // The register value is stored in the bits 16-28 as an immediate
125 WriteReg(header.method, header.subchannel, header.inline_data, 0);
126 break;
127 }
128 default:
129 UNIMPLEMENTED();
113 } 130 }
114 break;
115 }
116 case SubmissionMode::Inline: {
117 // The register value is stored in the bits 16-28 as an immediate
118 WriteReg(header.method, header.subchannel, header.inline_data, 0);
119 break;
120 }
121 default:
122 UNIMPLEMENTED();
123 } 131 }
124 } 132 }
125} 133}
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h
index a01153e0b..bd766e77a 100644
--- a/src/video_core/command_processor.h
+++ b/src/video_core/command_processor.h
@@ -7,6 +7,7 @@
7#include <type_traits> 7#include <type_traits>
8#include "common/bit_field.h" 8#include "common/bit_field.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/memory_manager.h"
10 11
11namespace Tegra { 12namespace Tegra {
12 13
@@ -19,6 +20,22 @@ enum class SubmissionMode : u32 {
19 IncreaseOnce = 5 20 IncreaseOnce = 5
20}; 21};
21 22
23struct CommandListHeader {
24 u32 entry0; // gpu_va_lo
25 union {
26 u32 entry1; // gpu_va_hi | (unk_0x02 << 0x08) | (size << 0x0A) | (unk_0x01 << 0x1F)
27 BitField<0, 8, u32> gpu_va_hi;
28 BitField<8, 2, u32> unk1;
29 BitField<10, 21, u32> sz;
30 BitField<31, 1, u32> unk2;
31 };
32
33 GPUVAddr Address() const {
34 return (static_cast<GPUVAddr>(gpu_va_hi) << 32) | entry0;
35 }
36};
37static_assert(sizeof(CommandListHeader) == 8, "CommandListHeader is incorrect size");
38
22union CommandHeader { 39union CommandHeader {
23 u32 hex; 40 u32 hex;
24 41
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index e63ad4d46..329079ddd 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -135,8 +135,6 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
135 break; 135 break;
136 } 136 }
137 137
138 rasterizer.NotifyMaxwellRegisterChanged(method);
139
140 if (debug_context) { 138 if (debug_context) {
141 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr); 139 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr);
142 } 140 }
@@ -293,10 +291,6 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
293 tic_entry.header_version == Texture::TICHeaderVersion::Pitch, 291 tic_entry.header_version == Texture::TICHeaderVersion::Pitch,
294 "TIC versions other than BlockLinear or Pitch are unimplemented"); 292 "TIC versions other than BlockLinear or Pitch are unimplemented");
295 293
296 ASSERT_MSG((tic_entry.texture_type == Texture::TextureType::Texture2D) ||
297 (tic_entry.texture_type == Texture::TextureType::Texture2DNoMipmap),
298 "Texture types other than Texture2D are unimplemented");
299
300 auto r_type = tic_entry.r_type.Value(); 294 auto r_type = tic_entry.r_type.Value();
301 auto g_type = tic_entry.g_type.Value(); 295 auto g_type = tic_entry.g_type.Value();
302 auto b_type = tic_entry.b_type.Value(); 296 auto b_type = tic_entry.b_type.Value();
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index f59d01738..d3be900a4 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -533,7 +533,11 @@ public:
533 u32 stencil_back_mask; 533 u32 stencil_back_mask;
534 u32 stencil_back_func_mask; 534 u32 stencil_back_func_mask;
535 535
536 INSERT_PADDING_WORDS(0x20); 536 INSERT_PADDING_WORDS(0x13);
537
538 u32 rt_separate_frag_data;
539
540 INSERT_PADDING_WORDS(0xC);
537 541
538 struct { 542 struct {
539 u32 address_high; 543 u32 address_high;
@@ -557,7 +561,22 @@ public:
557 struct { 561 struct {
558 union { 562 union {
559 BitField<0, 4, u32> count; 563 BitField<0, 4, u32> count;
564 BitField<4, 3, u32> map_0;
565 BitField<7, 3, u32> map_1;
566 BitField<10, 3, u32> map_2;
567 BitField<13, 3, u32> map_3;
568 BitField<16, 3, u32> map_4;
569 BitField<19, 3, u32> map_5;
570 BitField<22, 3, u32> map_6;
571 BitField<25, 3, u32> map_7;
560 }; 572 };
573
574 u32 GetMap(size_t index) const {
575 const std::array<u32, NumRenderTargets> maps{map_0, map_1, map_2, map_3,
576 map_4, map_5, map_6, map_7};
577 ASSERT(index < maps.size());
578 return maps[index];
579 }
561 } rt_control; 580 } rt_control;
562 581
563 INSERT_PADDING_WORDS(0x2); 582 INSERT_PADDING_WORDS(0x2);
@@ -968,6 +987,7 @@ ASSERT_REG_POSITION(clear_stencil, 0x368);
968ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); 987ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
969ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); 988ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
970ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); 989ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
990ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
971ASSERT_REG_POSITION(zeta, 0x3F8); 991ASSERT_REG_POSITION(zeta, 0x3F8);
972ASSERT_REG_POSITION(vertex_attrib_format, 0x458); 992ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
973ASSERT_REG_POSITION(rt_control, 0x487); 993ASSERT_REG_POSITION(rt_control, 0x487);
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index 6e740713f..c24d33d5c 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -41,7 +41,6 @@ void MaxwellDMA::HandleCopy() {
41 41
42 // TODO(Subv): Perform more research and implement all features of this engine. 42 // TODO(Subv): Perform more research and implement all features of this engine.
43 ASSERT(regs.exec.enable_swizzle == 0); 43 ASSERT(regs.exec.enable_swizzle == 0);
44 ASSERT(regs.exec.enable_2d == 1);
45 ASSERT(regs.exec.query_mode == Regs::QueryMode::None); 44 ASSERT(regs.exec.query_mode == Regs::QueryMode::None);
46 ASSERT(regs.exec.query_intr == Regs::QueryIntr::None); 45 ASSERT(regs.exec.query_intr == Regs::QueryIntr::None);
47 ASSERT(regs.exec.copy_mode == Regs::CopyMode::Unk2); 46 ASSERT(regs.exec.copy_mode == Regs::CopyMode::Unk2);
@@ -51,10 +50,19 @@ void MaxwellDMA::HandleCopy() {
51 ASSERT(regs.dst_params.pos_y == 0); 50 ASSERT(regs.dst_params.pos_y == 0);
52 51
53 if (regs.exec.is_dst_linear == regs.exec.is_src_linear) { 52 if (regs.exec.is_dst_linear == regs.exec.is_src_linear) {
54 Memory::CopyBlock(dest_cpu, source_cpu, regs.x_count * regs.y_count); 53 size_t copy_size = regs.x_count;
54
55 // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D
56 // buffer of length `x_count`, otherwise we copy a 2D buffer of size (x_count, y_count).
57 if (regs.exec.enable_2d) {
58 copy_size = copy_size * regs.y_count;
59 }
60
61 Memory::CopyBlock(dest_cpu, source_cpu, copy_size);
55 return; 62 return;
56 } 63 }
57 64
65 ASSERT(regs.exec.enable_2d == 1);
58 u8* src_buffer = Memory::GetPointer(source_cpu); 66 u8* src_buffer = Memory::GetPointer(source_cpu);
59 u8* dst_buffer = Memory::GetPointer(dest_cpu); 67 u8* dst_buffer = Memory::GetPointer(dest_cpu);
60 68
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index d2388673e..58f2904ce 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -244,6 +244,25 @@ enum class TextureType : u64 {
244 TextureCube = 3, 244 TextureCube = 3,
245}; 245};
246 246
247enum class TextureQueryType : u64 {
248 Dimension = 1,
249 TextureType = 2,
250 SamplePosition = 5,
251 Filter = 16,
252 LevelOfDetail = 18,
253 Wrap = 20,
254 BorderColor = 22,
255};
256
257enum class TextureProcessMode : u64 {
258 None = 0,
259 LZ = 1, // Unknown, appears to be the same as none.
260 LB = 2, // Load Bias.
261 LL = 3, // Load LOD (LevelOfDetail)
262 LBA = 6, // Load Bias. The A is unknown, does not appear to differ with LB
263 LLA = 7 // Load LOD. The A is unknown, does not appear to differ with LL
264};
265
247enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 }; 266enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 };
248enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 }; 267enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 };
249 268
@@ -414,6 +433,45 @@ union Instruction {
414 } bfe; 433 } bfe;
415 434
416 union { 435 union {
436 BitField<48, 3, u64> pred48;
437
438 union {
439 BitField<20, 20, u64> entry_a;
440 BitField<39, 5, u64> entry_b;
441 BitField<45, 1, u64> neg;
442 BitField<46, 1, u64> uses_cc;
443 } imm;
444
445 union {
446 BitField<20, 14, u64> cb_index;
447 BitField<34, 5, u64> cb_offset;
448 BitField<56, 1, u64> neg;
449 BitField<57, 1, u64> uses_cc;
450 } hi;
451
452 union {
453 BitField<20, 14, u64> cb_index;
454 BitField<34, 5, u64> cb_offset;
455 BitField<39, 5, u64> entry_a;
456 BitField<45, 1, u64> neg;
457 BitField<46, 1, u64> uses_cc;
458 } rz;
459
460 union {
461 BitField<39, 5, u64> entry_a;
462 BitField<45, 1, u64> neg;
463 BitField<46, 1, u64> uses_cc;
464 } r1;
465
466 union {
467 BitField<28, 8, u64> entry_a;
468 BitField<37, 1, u64> neg;
469 BitField<38, 1, u64> uses_cc;
470 } r2;
471
472 } lea;
473
474 union {
417 BitField<0, 5, FlowCondition> cond; 475 BitField<0, 5, FlowCondition> cond;
418 } flow; 476 } flow;
419 477
@@ -468,6 +526,18 @@ union Instruction {
468 } psetp; 526 } psetp;
469 527
470 union { 528 union {
529 BitField<12, 3, u64> pred12;
530 BitField<15, 1, u64> neg_pred12;
531 BitField<24, 2, PredOperation> cond;
532 BitField<29, 3, u64> pred29;
533 BitField<32, 1, u64> neg_pred29;
534 BitField<39, 3, u64> pred39;
535 BitField<42, 1, u64> neg_pred39;
536 BitField<44, 1, u64> bf;
537 BitField<45, 2, PredOperation> op;
538 } pset;
539
540 union {
471 BitField<39, 3, u64> pred39; 541 BitField<39, 3, u64> pred39;
472 BitField<42, 1, u64> neg_pred; 542 BitField<42, 1, u64> neg_pred;
473 BitField<43, 1, u64> neg_a; 543 BitField<43, 1, u64> neg_a;
@@ -512,6 +582,7 @@ union Instruction {
512 BitField<28, 1, u64> array; 582 BitField<28, 1, u64> array;
513 BitField<29, 2, TextureType> texture_type; 583 BitField<29, 2, TextureType> texture_type;
514 BitField<31, 4, u64> component_mask; 584 BitField<31, 4, u64> component_mask;
585 BitField<55, 3, TextureProcessMode> process_mode;
515 586
516 bool IsComponentEnabled(size_t component) const { 587 bool IsComponentEnabled(size_t component) const {
517 return ((1ull << component) & component_mask) != 0; 588 return ((1ull << component) & component_mask) != 0;
@@ -519,6 +590,21 @@ union Instruction {
519 } tex; 590 } tex;
520 591
521 union { 592 union {
593 BitField<22, 6, TextureQueryType> query_type;
594 BitField<31, 4, u64> component_mask;
595 } txq;
596
597 union {
598 BitField<28, 1, u64> array;
599 BitField<29, 2, TextureType> texture_type;
600 BitField<31, 4, u64> component_mask;
601
602 bool IsComponentEnabled(size_t component) const {
603 return ((1ull << component) & component_mask) != 0;
604 }
605 } tmml;
606
607 union {
522 BitField<28, 1, u64> array; 608 BitField<28, 1, u64> array;
523 BitField<29, 2, TextureType> texture_type; 609 BitField<29, 2, TextureType> texture_type;
524 BitField<56, 2, u64> component; 610 BitField<56, 2, u64> component;
@@ -670,11 +756,13 @@ public:
670 LDG, // Load from global memory 756 LDG, // Load from global memory
671 STG, // Store in global memory 757 STG, // Store in global memory
672 TEX, 758 TEX,
673 TEXQ, // Texture Query 759 TXQ, // Texture Query
674 TEXS, // Texture Fetch with scalar/non-vec4 source/destinations 760 TEXS, // Texture Fetch with scalar/non-vec4 source/destinations
675 TLDS, // Texture Load with scalar/non-vec4 source/destinations 761 TLDS, // Texture Load with scalar/non-vec4 source/destinations
676 TLD4, // Texture Load 4 762 TLD4, // Texture Load 4
677 TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations 763 TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations
764 TMML_B, // Texture Mip Map Level
765 TMML, // Texture Mip Map Level
678 EXIT, 766 EXIT,
679 IPA, 767 IPA,
680 FFMA_IMM, // Fused Multiply and Add 768 FFMA_IMM, // Fused Multiply and Add
@@ -699,6 +787,11 @@ public:
699 ISCADD_C, // Scale and Add 787 ISCADD_C, // Scale and Add
700 ISCADD_R, 788 ISCADD_R,
701 ISCADD_IMM, 789 ISCADD_IMM,
790 LEA_R1,
791 LEA_R2,
792 LEA_RZ,
793 LEA_IMM,
794 LEA_HI,
702 POPC_C, 795 POPC_C,
703 POPC_R, 796 POPC_R,
704 POPC_IMM, 797 POPC_IMM,
@@ -757,6 +850,7 @@ public:
757 ISET_C, 850 ISET_C,
758 ISET_IMM, 851 ISET_IMM,
759 PSETP, 852 PSETP,
853 PSET,
760 XMAD_IMM, 854 XMAD_IMM,
761 XMAD_CR, 855 XMAD_CR,
762 XMAD_RC, 856 XMAD_RC,
@@ -780,6 +874,7 @@ public:
780 IntegerSet, 874 IntegerSet,
781 IntegerSetPredicate, 875 IntegerSetPredicate,
782 PredicateSetPredicate, 876 PredicateSetPredicate,
877 PredicateSetRegister,
783 Conversion, 878 Conversion,
784 Xmad, 879 Xmad,
785 Unknown, 880 Unknown,
@@ -894,11 +989,13 @@ private:
894 INST("1110111011010---", Id::LDG, Type::Memory, "LDG"), 989 INST("1110111011010---", Id::LDG, Type::Memory, "LDG"),
895 INST("1110111011011---", Id::STG, Type::Memory, "STG"), 990 INST("1110111011011---", Id::STG, Type::Memory, "STG"),
896 INST("110000----111---", Id::TEX, Type::Memory, "TEX"), 991 INST("110000----111---", Id::TEX, Type::Memory, "TEX"),
897 INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"), 992 INST("1101111101001---", Id::TXQ, Type::Memory, "TXQ"),
898 INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"), 993 INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"),
899 INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"), 994 INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"),
900 INST("110010----111---", Id::TLD4, Type::Memory, "TLD4"), 995 INST("110010----111---", Id::TLD4, Type::Memory, "TLD4"),
901 INST("1101111100------", Id::TLD4S, Type::Memory, "TLD4S"), 996 INST("1101111100------", Id::TLD4S, Type::Memory, "TLD4S"),
997 INST("110111110110----", Id::TMML_B, Type::Memory, "TMML_B"),
998 INST("1101111101011---", Id::TMML, Type::Memory, "TMML"),
902 INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"), 999 INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"),
903 INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), 1000 INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
904 INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"), 1001 INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"),
@@ -929,6 +1026,11 @@ private:
929 INST("0100110010100---", Id::SEL_C, Type::ArithmeticInteger, "SEL_C"), 1026 INST("0100110010100---", Id::SEL_C, Type::ArithmeticInteger, "SEL_C"),
930 INST("0101110010100---", Id::SEL_R, Type::ArithmeticInteger, "SEL_R"), 1027 INST("0101110010100---", Id::SEL_R, Type::ArithmeticInteger, "SEL_R"),
931 INST("0011100-10100---", Id::SEL_IMM, Type::ArithmeticInteger, "SEL_IMM"), 1028 INST("0011100-10100---", Id::SEL_IMM, Type::ArithmeticInteger, "SEL_IMM"),
1029 INST("0101101111011---", Id::LEA_R2, Type::ArithmeticInteger, "LEA_R2"),
1030 INST("0101101111010---", Id::LEA_R1, Type::ArithmeticInteger, "LEA_R1"),
1031 INST("001101101101----", Id::LEA_IMM, Type::ArithmeticInteger, "LEA_IMM"),
1032 INST("010010111101----", Id::LEA_RZ, Type::ArithmeticInteger, "LEA_RZ"),
1033 INST("00011000--------", Id::LEA_HI, Type::ArithmeticInteger, "LEA_HI"),
932 INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"), 1034 INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"),
933 INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"), 1035 INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"),
934 INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"), 1036 INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"),
@@ -983,6 +1085,7 @@ private:
983 INST("010110110101----", Id::ISET_R, Type::IntegerSet, "ISET_R"), 1085 INST("010110110101----", Id::ISET_R, Type::IntegerSet, "ISET_R"),
984 INST("010010110101----", Id::ISET_C, Type::IntegerSet, "ISET_C"), 1086 INST("010010110101----", Id::ISET_C, Type::IntegerSet, "ISET_C"),
985 INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), 1087 INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"),
1088 INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),
986 INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), 1089 INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
987 INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), 1090 INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
988 INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), 1091 INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index e6d8e65c6..86a809f86 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -66,6 +66,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
66 case RenderTargetFormat::RGBA8_UINT: 66 case RenderTargetFormat::RGBA8_UINT:
67 case RenderTargetFormat::RGB10_A2_UNORM: 67 case RenderTargetFormat::RGB10_A2_UNORM:
68 case RenderTargetFormat::BGRA8_UNORM: 68 case RenderTargetFormat::BGRA8_UNORM:
69 case RenderTargetFormat::BGRA8_SRGB:
69 case RenderTargetFormat::RG16_UNORM: 70 case RenderTargetFormat::RG16_UNORM:
70 case RenderTargetFormat::RG16_SNORM: 71 case RenderTargetFormat::RG16_SNORM:
71 case RenderTargetFormat::RG16_UINT: 72 case RenderTargetFormat::RG16_UINT:
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index d29f31f52..589a59b4f 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include <vector>
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "core/hle/service/nvflinger/buffer_queue.h" 11#include "core/hle/service/nvflinger/buffer_queue.h"
11#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
@@ -26,6 +27,7 @@ enum class RenderTargetFormat : u32 {
26 RG32_FLOAT = 0xCB, 27 RG32_FLOAT = 0xCB,
27 RG32_UINT = 0xCD, 28 RG32_UINT = 0xCD,
28 BGRA8_UNORM = 0xCF, 29 BGRA8_UNORM = 0xCF,
30 BGRA8_SRGB = 0xD0,
29 RGB10_A2_UNORM = 0xD1, 31 RGB10_A2_UNORM = 0xD1,
30 RGBA8_UNORM = 0xD5, 32 RGBA8_UNORM = 0xD5,
31 RGBA8_SRGB = 0xD6, 33 RGBA8_SRGB = 0xD6,
@@ -67,6 +69,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format);
67/// Returns the number of bytes per pixel of each depth format. 69/// Returns the number of bytes per pixel of each depth format.
68u32 DepthFormatBytesPerPixel(DepthFormat format); 70u32 DepthFormatBytesPerPixel(DepthFormat format);
69 71
72struct CommandListHeader;
70class DebugContext; 73class DebugContext;
71 74
72/** 75/**
@@ -115,7 +118,7 @@ public:
115 ~GPU(); 118 ~GPU();
116 119
117 /// Processes a command list stored at the specified address in GPU memory. 120 /// Processes a command list stored at the specified address in GPU memory.
118 void ProcessCommandList(GPUVAddr address, u32 size); 121 void ProcessCommandLists(const std::vector<CommandListHeader>& commands);
119 122
120 /// Returns a reference to the Maxwell3D GPU engine. 123 /// Returns a reference to the Maxwell3D GPU engine.
121 Engines::Maxwell3D& Maxwell3D(); 124 Engines::Maxwell3D& Maxwell3D();
@@ -130,9 +133,6 @@ public:
130 const Tegra::MemoryManager& MemoryManager() const; 133 const Tegra::MemoryManager& MemoryManager() const;
131 134
132private: 135private:
133 /// Writes a single register in the engine bound to the specified subchannel
134 void WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params);
135
136 std::unique_ptr<Tegra::MemoryManager> memory_manager; 136 std::unique_ptr<Tegra::MemoryManager> memory_manager;
137 137
138 /// Mapping of command subchannels to their bound engine ids. 138 /// Mapping of command subchannels to their bound engine ids.
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 9d78e8b6b..cd819d69f 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -20,9 +20,6 @@ public:
20 /// Clear the current framebuffer 20 /// Clear the current framebuffer
21 virtual void Clear() = 0; 21 virtual void Clear() = 0;
22 22
23 /// Notify rasterizer that the specified Maxwell register has been changed
24 virtual void NotifyMaxwellRegisterChanged(u32 method) = 0;
25
26 /// Notify rasterizer that all caches should be flushed to Switch memory 23 /// Notify rasterizer that all caches should be flushed to Switch memory
27 virtual void FlushAll() = 0; 24 virtual void FlushAll() = 0;
28 25
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index be17a2b9c..0df3725c2 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -19,6 +19,7 @@ void RendererBase::RefreshBaseSettings() {
19 UpdateCurrentFramebufferLayout(); 19 UpdateCurrentFramebufferLayout();
20 20
21 renderer_settings.use_framelimiter = Settings::values.use_frame_limit; 21 renderer_settings.use_framelimiter = Settings::values.use_frame_limit;
22 renderer_settings.set_background_color = true;
22} 23}
23 24
24void RendererBase::UpdateCurrentFramebufferLayout() { 25void RendererBase::UpdateCurrentFramebufferLayout() {
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 2a357f9d0..2cd0738ff 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -19,6 +19,7 @@ namespace VideoCore {
19 19
20struct RendererSettings { 20struct RendererSettings {
21 std::atomic_bool use_framelimiter{false}; 21 std::atomic_bool use_framelimiter{false};
22 std::atomic_bool set_background_color{false};
22}; 23};
23 24
24class RendererBase : NonCopyable { 25class RendererBase : NonCopyable {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 0c3bbc475..c59f3af1b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -294,61 +294,80 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
294 cached_pages.add({pages_interval, delta}); 294 cached_pages.add({pages_interval, delta});
295} 295}
296 296
297std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, 297void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb,
298 bool using_depth_fb, 298 bool preserve_contents,
299 bool preserve_contents) { 299 boost::optional<size_t> single_color_target) {
300 MICROPROFILE_SCOPE(OpenGL_Framebuffer); 300 MICROPROFILE_SCOPE(OpenGL_Framebuffer);
301 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 301 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
302 302
303 if (regs.rt[0].format == Tegra::RenderTargetFormat::NONE) { 303 Surface depth_surface;
304 LOG_ERROR(HW_GPU, "RenderTargetFormat is not configured"); 304 if (using_depth_fb) {
305 using_color_fb = false; 305 depth_surface = res_cache.GetDepthBufferSurface(preserve_contents);
306 } 306 }
307 307
308 const bool has_stencil = regs.stencil_enable; 308 // TODO(bunnei): Figure out how the below register works. According to envytools, this should be
309 const bool write_color_fb = 309 // used to enable multiple render targets. However, it is left unset on all games that I have
310 state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || 310 // tested.
311 state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE; 311 ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented");
312
313 const bool write_depth_fb =
314 (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) ||
315 (has_stencil && (state.stencil.front.write_mask || state.stencil.back.write_mask));
316 312
317 Surface color_surface; 313 // Bind the framebuffer surfaces
318 Surface depth_surface; 314 state.draw.draw_framebuffer = framebuffer.handle;
319 MathUtil::Rectangle<u32> surfaces_rect; 315 state.Apply();
320 std::tie(color_surface, depth_surface, surfaces_rect) =
321 res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, preserve_contents);
322 316
323 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; 317 if (using_color_fb) {
324 const MathUtil::Rectangle<u32> draw_rect{ 318 if (single_color_target) {
325 static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left, 319 // Used when just a single color attachment is enabled, e.g. for clearing a color buffer
326 surfaces_rect.left, surfaces_rect.right)), // Left 320 Surface color_surface =
327 static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top, 321 res_cache.GetColorBufferSurface(*single_color_target, preserve_contents);
328 surfaces_rect.bottom, surfaces_rect.top)), // Top 322 glFramebufferTexture2D(
329 static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.right, 323 GL_DRAW_FRAMEBUFFER,
330 surfaces_rect.left, surfaces_rect.right)), // Right 324 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target), GL_TEXTURE_2D,
331 static_cast<u32>( 325 color_surface != nullptr ? color_surface->Texture().handle : 0, 0);
332 std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.bottom, 326 glDrawBuffer(GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target));
333 surfaces_rect.bottom, surfaces_rect.top))}; // Bottom 327 } else {
328 // Multiple color attachments are enabled
329 std::array<GLenum, Maxwell::NumRenderTargets> buffers;
330 for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
331 Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents);
332 buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
333 glFramebufferTexture2D(
334 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index),
335 GL_TEXTURE_2D, color_surface != nullptr ? color_surface->Texture().handle : 0,
336 0);
337 }
338 glDrawBuffers(regs.rt_control.count, buffers.data());
339 }
340 } else {
341 // No color attachments are enabled - zero out all of them
342 for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
343 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
344 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D,
345 0, 0);
346 }
347 glDrawBuffer(GL_NONE);
348 }
334 349
335 // Bind the framebuffer surfaces 350 if (depth_surface) {
336 BindFramebufferSurfaces(color_surface, depth_surface, has_stencil); 351 if (regs.stencil_enable) {
352 // Attach both depth and stencil
353 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
354 depth_surface->Texture().handle, 0);
355 } else {
356 // Attach depth
357 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
358 depth_surface->Texture().handle, 0);
359 // Clear stencil attachment
360 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
361 }
362 } else {
363 // Clear both depth and stencil attachment
364 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
365 0);
366 }
337 367
338 SyncViewport(surfaces_rect); 368 SyncViewport();
339 369
340 // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable
341 // scissor test to prevent drawing outside of the framebuffer region
342 state.scissor.enabled = true;
343 state.scissor.x = draw_rect.left;
344 state.scissor.y = draw_rect.bottom;
345 state.scissor.width = draw_rect.GetWidth();
346 state.scissor.height = draw_rect.GetHeight();
347 state.Apply(); 370 state.Apply();
348
349 // Only return the surface to be marked as dirty if writing to it is enabled.
350 return std::make_pair(write_color_fb ? color_surface : nullptr,
351 write_depth_fb ? depth_surface : nullptr);
352} 371}
353 372
354void RasterizerOpenGL::Clear() { 373void RasterizerOpenGL::Clear() {
@@ -356,8 +375,9 @@ void RasterizerOpenGL::Clear() {
356 SCOPE_EXIT({ prev_state.Apply(); }); 375 SCOPE_EXIT({ prev_state.Apply(); });
357 376
358 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 377 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
359 bool use_color_fb = false; 378 bool use_color{};
360 bool use_depth_fb = false; 379 bool use_depth{};
380 bool use_stencil{};
361 381
362 OpenGLState clear_state; 382 OpenGLState clear_state;
363 clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer; 383 clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer;
@@ -366,22 +386,13 @@ void RasterizerOpenGL::Clear() {
366 clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; 386 clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
367 clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; 387 clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
368 388
369 GLbitfield clear_mask{};
370 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || 389 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
371 regs.clear_buffers.A) { 390 regs.clear_buffers.A) {
372 if (regs.clear_buffers.RT == 0) { 391 use_color = true;
373 // We only support clearing the first color attachment for now
374 clear_mask |= GL_COLOR_BUFFER_BIT;
375 use_color_fb = true;
376 } else {
377 // TODO(subv): Add support for the other color attachments
378 LOG_CRITICAL(HW_GPU, "Clear unimplemented for RT {}", regs.clear_buffers.RT);
379 }
380 } 392 }
381 if (regs.clear_buffers.Z) { 393 if (regs.clear_buffers.Z) {
382 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); 394 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!");
383 use_depth_fb = true; 395 use_depth = true;
384 clear_mask |= GL_DEPTH_BUFFER_BIT;
385 396
386 // Always enable the depth write when clearing the depth buffer. The depth write mask is 397 // Always enable the depth write when clearing the depth buffer. The depth write mask is
387 // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. 398 // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true.
@@ -390,34 +401,33 @@ void RasterizerOpenGL::Clear() {
390 } 401 }
391 if (regs.clear_buffers.S) { 402 if (regs.clear_buffers.S) {
392 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); 403 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
393 use_depth_fb = true; 404 use_stencil = true;
394 clear_mask |= GL_STENCIL_BUFFER_BIT;
395 clear_state.stencil.test_enabled = true; 405 clear_state.stencil.test_enabled = true;
396 } 406 }
397 407
398 if (!use_color_fb && !use_depth_fb) { 408 if (!use_color && !use_depth && !use_stencil) {
399 // No color surface nor depth/stencil surface are enabled 409 // No color surface nor depth/stencil surface are enabled
400 return; 410 return;
401 } 411 }
402 412
403 if (clear_mask == 0) {
404 // No clear mask is enabled
405 return;
406 }
407
408 ScopeAcquireGLContext acquire_context{emu_window}; 413 ScopeAcquireGLContext acquire_context{emu_window};
409 414
410 auto [dirty_color_surface, dirty_depth_surface] = 415 ConfigureFramebuffers(use_color, use_depth || use_stencil, false,
411 ConfigureFramebuffers(use_color_fb, use_depth_fb, false); 416 regs.clear_buffers.RT.Value());
412 417
413 clear_state.Apply(); 418 clear_state.Apply();
414 419
415 glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2], 420 if (use_color) {
416 regs.clear_color[3]); 421 glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color);
417 glClearDepth(regs.clear_depth); 422 }
418 glClearStencil(regs.clear_stencil);
419 423
420 glClear(clear_mask); 424 if (use_depth && use_stencil) {
425 glClearBufferfi(GL_DEPTH_STENCIL, 0, regs.clear_depth, regs.clear_stencil);
426 } else if (use_depth) {
427 glClearBufferfv(GL_DEPTH, 0, &regs.clear_depth);
428 } else if (use_stencil) {
429 glClearBufferiv(GL_STENCIL, 0, &regs.clear_stencil);
430 }
421} 431}
422 432
423void RasterizerOpenGL::DrawArrays() { 433void RasterizerOpenGL::DrawArrays() {
@@ -430,8 +440,7 @@ void RasterizerOpenGL::DrawArrays() {
430 440
431 ScopeAcquireGLContext acquire_context{emu_window}; 441 ScopeAcquireGLContext acquire_context{emu_window};
432 442
433 const auto [dirty_color_surface, dirty_depth_surface] = 443 ConfigureFramebuffers();
434 ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0, true);
435 444
436 SyncDepthTestState(); 445 SyncDepthTestState();
437 SyncStencilTestState(); 446 SyncStencilTestState();
@@ -525,8 +534,6 @@ void RasterizerOpenGL::DrawArrays() {
525 state.Apply(); 534 state.Apply();
526} 535}
527 536
528void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {}
529
530void RasterizerOpenGL::FlushAll() {} 537void RasterizerOpenGL::FlushAll() {}
531 538
532void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {} 539void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {}
@@ -586,7 +593,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
586void RasterizerOpenGL::SamplerInfo::Create() { 593void RasterizerOpenGL::SamplerInfo::Create() {
587 sampler.Create(); 594 sampler.Create();
588 mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; 595 mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear;
589 wrap_u = wrap_v = Tegra::Texture::WrapMode::Wrap; 596 wrap_u = wrap_v = wrap_p = Tegra::Texture::WrapMode::Wrap;
590 597
591 // default is GL_LINEAR_MIPMAP_LINEAR 598 // default is GL_LINEAR_MIPMAP_LINEAR
592 glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 599 glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -613,8 +620,13 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
613 wrap_v = config.wrap_v; 620 wrap_v = config.wrap_v;
614 glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v)); 621 glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v));
615 } 622 }
623 if (wrap_p != config.wrap_p) {
624 wrap_p = config.wrap_p;
625 glSamplerParameteri(s, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p));
626 }
616 627
617 if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border) { 628 if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border ||
629 wrap_p == Tegra::Texture::WrapMode::Border) {
618 const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, 630 const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g,
619 config.border_color_b, config.border_color_a}}; 631 config.border_color_b, config.border_color_a}};
620 if (border_color != new_border_color) { 632 if (border_color != new_border_color) {
@@ -698,14 +710,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
698 const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); 710 const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset());
699 711
700 if (!texture.enabled) { 712 if (!texture.enabled) {
701 state.texture_units[current_bindpoint].texture_2d = 0; 713 state.texture_units[current_bindpoint].texture = 0;
702 continue; 714 continue;
703 } 715 }
704 716
705 texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); 717 texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
706 Surface surface = res_cache.GetTextureSurface(texture); 718 Surface surface = res_cache.GetTextureSurface(texture);
707 if (surface != nullptr) { 719 if (surface != nullptr) {
708 state.texture_units[current_bindpoint].texture_2d = surface->Texture().handle; 720 state.texture_units[current_bindpoint].texture = surface->Texture().handle;
721 state.texture_units[current_bindpoint].target = surface->Target();
709 state.texture_units[current_bindpoint].swizzle.r = 722 state.texture_units[current_bindpoint].swizzle.r =
710 MaxwellToGL::SwizzleSource(texture.tic.x_source); 723 MaxwellToGL::SwizzleSource(texture.tic.x_source);
711 state.texture_units[current_bindpoint].swizzle.g = 724 state.texture_units[current_bindpoint].swizzle.g =
@@ -716,45 +729,19 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
716 MaxwellToGL::SwizzleSource(texture.tic.w_source); 729 MaxwellToGL::SwizzleSource(texture.tic.w_source);
717 } else { 730 } else {
718 // Can occur when texture addr is null or its memory is unmapped/invalid 731 // Can occur when texture addr is null or its memory is unmapped/invalid
719 state.texture_units[current_bindpoint].texture_2d = 0; 732 state.texture_units[current_bindpoint].texture = 0;
720 } 733 }
721 } 734 }
722 735
723 return current_unit + static_cast<u32>(entries.size()); 736 return current_unit + static_cast<u32>(entries.size());
724} 737}
725 738
726void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, 739void RasterizerOpenGL::SyncViewport() {
727 const Surface& depth_surface, bool has_stencil) {
728 state.draw.draw_framebuffer = framebuffer.handle;
729 state.Apply();
730
731 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
732 color_surface != nullptr ? color_surface->Texture().handle : 0, 0);
733 if (depth_surface != nullptr) {
734 if (has_stencil) {
735 // attach both depth and stencil
736 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
737 depth_surface->Texture().handle, 0);
738 } else {
739 // attach depth
740 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
741 depth_surface->Texture().handle, 0);
742 // clear stencil attachment
743 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
744 }
745 } else {
746 // clear both depth and stencil attachment
747 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
748 0);
749 }
750}
751
752void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect) {
753 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 740 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
754 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; 741 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
755 742
756 state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left; 743 state.viewport.x = viewport_rect.left;
757 state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom; 744 state.viewport.y = viewport_rect.bottom;
758 state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); 745 state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth());
759 state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); 746 state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight());
760} 747}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9c30dc0e8..745c3dc0c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -13,6 +13,7 @@
13#include <vector> 13#include <vector>
14 14
15#include <boost/icl/interval_map.hpp> 15#include <boost/icl/interval_map.hpp>
16#include <boost/optional.hpp>
16#include <boost/range/iterator_range.hpp> 17#include <boost/range/iterator_range.hpp>
17#include <glad/glad.h> 18#include <glad/glad.h>
18 19
@@ -45,7 +46,6 @@ public:
45 46
46 void DrawArrays() override; 47 void DrawArrays() override;
47 void Clear() override; 48 void Clear() override;
48 void NotifyMaxwellRegisterChanged(u32 method) override;
49 void FlushAll() override; 49 void FlushAll() override;
50 void FlushRegion(VAddr addr, u64 size) override; 50 void FlushRegion(VAddr addr, u64 size) override;
51 void InvalidateRegion(VAddr addr, u64 size) override; 51 void InvalidateRegion(VAddr addr, u64 size) override;
@@ -93,17 +93,20 @@ private:
93 Tegra::Texture::TextureFilter min_filter; 93 Tegra::Texture::TextureFilter min_filter;
94 Tegra::Texture::WrapMode wrap_u; 94 Tegra::Texture::WrapMode wrap_u;
95 Tegra::Texture::WrapMode wrap_v; 95 Tegra::Texture::WrapMode wrap_v;
96 Tegra::Texture::WrapMode wrap_p;
96 GLvec4 border_color; 97 GLvec4 border_color;
97 }; 98 };
98 99
99 /// Configures the color and depth framebuffer states and returns the dirty <Color, Depth> 100 /**
100 /// surfaces if writing was enabled. 101 * Configures the color and depth framebuffer states.
101 std::pair<Surface, Surface> ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, 102 * @param use_color_fb If true, configure color framebuffers.
102 bool preserve_contents); 103 * @param using_depth_fb If true, configure the depth/stencil framebuffer.
103 104 * @param preserve_contents If true, tries to preserve data from a previously used framebuffer.
104 /// Binds the framebuffer color and depth surface 105 * @param single_color_target Specifies if a single color buffer target should be used.
105 void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface, 106 */
106 bool has_stencil); 107 void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true,
108 bool preserve_contents = true,
109 boost::optional<size_t> single_color_target = {});
107 110
108 /* 111 /*
109 * Configures the current constbuffers to use for the draw command. 112 * Configures the current constbuffers to use for the draw command.
@@ -126,7 +129,7 @@ private:
126 u32 current_unit); 129 u32 current_unit);
127 130
128 /// Syncs the viewport to match the guest state 131 /// Syncs the viewport to match the guest state
129 void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect); 132 void SyncViewport();
130 133
131 /// Syncs the clip enabled status to match the guest state 134 /// Syncs the clip enabled status to match the guest state
132 void SyncClipEnabled(); 135 void SyncClipEnabled();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index f6b2c5a86..32001e44b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -7,6 +7,7 @@
7 7
8#include "common/alignment.h" 8#include "common/alignment.h"
9#include "common/assert.h" 9#include "common/assert.h"
10#include "common/logging/log.h"
10#include "common/microprofile.h" 11#include "common/microprofile.h"
11#include "common/scope_exit.h" 12#include "common/scope_exit.h"
12#include "core/core.h" 13#include "core/core.h"
@@ -52,14 +53,30 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
52 params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); 53 params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format));
53 params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); 54 params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
54 params.unaligned_height = config.tic.Height(); 55 params.unaligned_height = config.tic.Height();
56 params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
57
58 switch (params.target) {
59 case SurfaceTarget::Texture1D:
60 case SurfaceTarget::Texture2D:
61 params.depth = 1;
62 break;
63 case SurfaceTarget::Texture3D:
64 case SurfaceTarget::Texture2DArray:
65 params.depth = config.tic.Depth();
66 break;
67 default:
68 LOG_CRITICAL(HW_GPU, "Unknown depth for target={}", static_cast<u32>(params.target));
69 UNREACHABLE();
70 params.depth = 1;
71 break;
72 }
73
55 params.size_in_bytes = params.SizeInBytes(); 74 params.size_in_bytes = params.SizeInBytes();
56 params.cache_width = Common::AlignUp(params.width, 16);
57 params.cache_height = Common::AlignUp(params.height, 16);
58 return params; 75 return params;
59} 76}
60 77
61/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer( 78/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer(size_t index) {
62 const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config) { 79 const auto& config{Core::System::GetInstance().GPU().Maxwell3D().regs.rt[index]};
63 SurfaceParams params{}; 80 SurfaceParams params{};
64 params.addr = TryGetCpuAddr(config.Address()); 81 params.addr = TryGetCpuAddr(config.Address());
65 params.is_tiled = true; 82 params.is_tiled = true;
@@ -70,9 +87,9 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
70 params.width = config.width; 87 params.width = config.width;
71 params.height = config.height; 88 params.height = config.height;
72 params.unaligned_height = config.height; 89 params.unaligned_height = config.height;
90 params.target = SurfaceTarget::Texture2D;
91 params.depth = 1;
73 params.size_in_bytes = params.SizeInBytes(); 92 params.size_in_bytes = params.SizeInBytes();
74 params.cache_width = Common::AlignUp(params.width, 16);
75 params.cache_height = Common::AlignUp(params.height, 16);
76 return params; 93 return params;
77} 94}
78 95
@@ -86,13 +103,12 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
86 params.pixel_format = PixelFormatFromDepthFormat(format); 103 params.pixel_format = PixelFormatFromDepthFormat(format);
87 params.component_type = ComponentTypeFromDepthFormat(format); 104 params.component_type = ComponentTypeFromDepthFormat(format);
88 params.type = GetFormatType(params.pixel_format); 105 params.type = GetFormatType(params.pixel_format);
89 params.size_in_bytes = params.SizeInBytes();
90 params.width = zeta_width; 106 params.width = zeta_width;
91 params.height = zeta_height; 107 params.height = zeta_height;
92 params.unaligned_height = zeta_height; 108 params.unaligned_height = zeta_height;
109 params.target = SurfaceTarget::Texture2D;
110 params.depth = 1;
93 params.size_in_bytes = params.SizeInBytes(); 111 params.size_in_bytes = params.SizeInBytes();
94 params.cache_width = Common::AlignUp(params.width, 16);
95 params.cache_height = Common::AlignUp(params.height, 16);
96 return params; 112 return params;
97} 113}
98 114
@@ -100,7 +116,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
100 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U 116 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
101 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S 117 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
102 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI 118 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI
103 {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U 119 {GL_RGB8, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U
104 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm, 120 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm,
105 false}, // A2B10G10R10U 121 false}, // A2B10G10R10U
106 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5U 122 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5U
@@ -166,6 +182,26 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
166 ComponentType::Float, false}, // Z32FS8 182 ComponentType::Float, false}, // Z32FS8
167}}; 183}};
168 184
185static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) {
186 switch (target) {
187 case SurfaceParams::SurfaceTarget::Texture1D:
188 return GL_TEXTURE_1D;
189 case SurfaceParams::SurfaceTarget::Texture2D:
190 return GL_TEXTURE_2D;
191 case SurfaceParams::SurfaceTarget::Texture3D:
192 return GL_TEXTURE_3D;
193 case SurfaceParams::SurfaceTarget::Texture1DArray:
194 return GL_TEXTURE_1D_ARRAY;
195 case SurfaceParams::SurfaceTarget::Texture2DArray:
196 return GL_TEXTURE_2D_ARRAY;
197 case SurfaceParams::SurfaceTarget::TextureCubemap:
198 return GL_TEXTURE_CUBE_MAP;
199 }
200 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
201 UNREACHABLE();
202 return {};
203}
204
169static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { 205static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
170 ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size()); 206 ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
171 auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)]; 207 auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)];
@@ -220,7 +256,8 @@ static bool IsFormatBCn(PixelFormat format) {
220} 256}
221 257
222template <bool morton_to_gl, PixelFormat format> 258template <bool morton_to_gl, PixelFormat format>
223void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_buffer, VAddr addr) { 259void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t gl_buffer_size,
260 VAddr addr) {
224 constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; 261 constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT;
225 constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); 262 constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
226 263
@@ -230,18 +267,18 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu
230 const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; 267 const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
231 const std::vector<u8> data = Tegra::Texture::UnswizzleTexture( 268 const std::vector<u8> data = Tegra::Texture::UnswizzleTexture(
232 addr, tile_size, bytes_per_pixel, stride, height, block_height); 269 addr, tile_size, bytes_per_pixel, stride, height, block_height);
233 const size_t size_to_copy{std::min(gl_buffer.size(), data.size())}; 270 const size_t size_to_copy{std::min(gl_buffer_size, data.size())};
234 gl_buffer.assign(data.begin(), data.begin() + size_to_copy); 271 memcpy(gl_buffer, data.data(), size_to_copy);
235 } else { 272 } else {
236 // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should 273 // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should
237 // check the configuration for this and perform more generic un/swizzle 274 // check the configuration for this and perform more generic un/swizzle
238 LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); 275 LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
239 VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel, 276 VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
240 Memory::GetPointer(addr), gl_buffer.data(), morton_to_gl); 277 Memory::GetPointer(addr), gl_buffer, morton_to_gl);
241 } 278 }
242} 279}
243 280
244static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), 281static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
245 SurfaceParams::MaxPixelFormat> 282 SurfaceParams::MaxPixelFormat>
246 morton_to_gl_fns = { 283 morton_to_gl_fns = {
247 // clang-format off 284 // clang-format off
@@ -298,7 +335,7 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr),
298 // clang-format on 335 // clang-format on
299}; 336};
300 337
301static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), 338static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
302 SurfaceParams::MaxPixelFormat> 339 SurfaceParams::MaxPixelFormat>
303 gl_to_morton_fns = { 340 gl_to_morton_fns = {
304 // clang-format off 341 // clang-format off
@@ -357,33 +394,6 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr),
357 // clang-format on 394 // clang-format on
358}; 395};
359 396
360// Allocate an uninitialized texture of appropriate size and format for the surface
361static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tuple, u32 width,
362 u32 height) {
363 OpenGLState cur_state = OpenGLState::GetCurState();
364
365 // Keep track of previous texture bindings
366 GLuint old_tex = cur_state.texture_units[0].texture_2d;
367 cur_state.texture_units[0].texture_2d = texture;
368 cur_state.Apply();
369 glActiveTexture(GL_TEXTURE0);
370
371 if (!format_tuple.compressed) {
372 // Only pre-create the texture for non-compressed textures.
373 glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0,
374 format_tuple.format, format_tuple.type, nullptr);
375 }
376
377 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
378 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
379 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
380 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
381
382 // Restore previous texture bindings
383 cur_state.texture_units[0].texture_2d = old_tex;
384 cur_state.Apply();
385}
386
387static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex, 397static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex,
388 const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type, 398 const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type,
389 GLuint read_fb_handle, GLuint draw_fb_handle) { 399 GLuint read_fb_handle, GLuint draw_fb_handle) {
@@ -438,12 +448,53 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec
438 return true; 448 return true;
439} 449}
440 450
441CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) { 451CachedSurface::CachedSurface(const SurfaceParams& params)
452 : params(params), gl_target(SurfaceTargetToGL(params.target)) {
442 texture.Create(); 453 texture.Create();
443 const auto& rect{params.GetRect()}; 454 const auto& rect{params.GetRect()};
444 AllocateSurfaceTexture(texture.handle, 455
445 GetFormatTuple(params.pixel_format, params.component_type), 456 // Keep track of previous texture bindings
457 OpenGLState cur_state = OpenGLState::GetCurState();
458 const auto& old_tex = cur_state.texture_units[0];
459 SCOPE_EXIT({
460 cur_state.texture_units[0] = old_tex;
461 cur_state.Apply();
462 });
463
464 cur_state.texture_units[0].texture = texture.handle;
465 cur_state.texture_units[0].target = SurfaceTargetToGL(params.target);
466 cur_state.Apply();
467 glActiveTexture(GL_TEXTURE0);
468
469 const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type);
470 if (!format_tuple.compressed) {
471 // Only pre-create the texture for non-compressed textures.
472 switch (params.target) {
473 case SurfaceParams::SurfaceTarget::Texture1D:
474 glTexStorage1D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format,
475 rect.GetWidth());
476 break;
477 case SurfaceParams::SurfaceTarget::Texture2D:
478 glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format,
446 rect.GetWidth(), rect.GetHeight()); 479 rect.GetWidth(), rect.GetHeight());
480 break;
481 case SurfaceParams::SurfaceTarget::Texture3D:
482 case SurfaceParams::SurfaceTarget::Texture2DArray:
483 glTexStorage3D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format,
484 rect.GetWidth(), rect.GetHeight(), params.depth);
485 break;
486 default:
487 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
488 static_cast<u32>(params.target));
489 UNREACHABLE();
490 glTexStorage2D(GL_TEXTURE_2D, 1, format_tuple.internal_format, rect.GetWidth(),
491 rect.GetHeight());
492 }
493 }
494
495 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
496 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
497 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
447} 498}
448 499
449static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { 500static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
@@ -461,7 +512,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
461 512
462 S8Z24 input_pixel{}; 513 S8Z24 input_pixel{};
463 Z24S8 output_pixel{}; 514 Z24S8 output_pixel{};
464 const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::S8Z24)}; 515 constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::S8Z24)};
465 for (size_t y = 0; y < height; ++y) { 516 for (size_t y = 0; y < height; ++y) {
466 for (size_t x = 0; x < width; ++x) { 517 for (size_t x = 0; x < width; ++x) {
467 const size_t offset{bpp * (y * width + x)}; 518 const size_t offset{bpp * (y * width + x)};
@@ -474,7 +525,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
474} 525}
475 526
476static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) { 527static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
477 const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8U)}; 528 constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8U)};
478 for (size_t y = 0; y < height; ++y) { 529 for (size_t y = 0; y < height; ++y) {
479 for (size_t x = 0; x < width; ++x) { 530 for (size_t x = 0; x < width; ++x) {
480 const size_t offset{bpp * (y * width + x)}; 531 const size_t offset{bpp * (y * width + x)};
@@ -514,23 +565,6 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
514 } 565 }
515} 566}
516 567
517/**
518 * Helper function to perform software conversion (as needed) when flushing a buffer to Switch
519 * memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with
520 * typical desktop GPUs.
521 */
522static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& /*data*/, PixelFormat pixel_format,
523 u32 /*width*/, u32 /*height*/) {
524 switch (pixel_format) {
525 case PixelFormat::ASTC_2D_4X4:
526 case PixelFormat::S8Z24:
527 LOG_CRITICAL(Render_OpenGL, "Unimplemented pixel_format={}",
528 static_cast<u32>(pixel_format));
529 UNREACHABLE();
530 break;
531 }
532}
533
534MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); 568MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
535void CachedSurface::LoadGLBuffer() { 569void CachedSurface::LoadGLBuffer() {
536 ASSERT(params.type != SurfaceType::Fill); 570 ASSERT(params.type != SurfaceType::Fill);
@@ -545,13 +579,25 @@ void CachedSurface::LoadGLBuffer() {
545 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); 579 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
546 580
547 if (params.is_tiled) { 581 if (params.is_tiled) {
548 gl_buffer.resize(copy_size); 582 // TODO(bunnei): This only unswizzles and copies a 2D texture - we do not yet know how to do
583 // this for 3D textures, etc.
584 switch (params.target) {
585 case SurfaceParams::SurfaceTarget::Texture2D:
586 // Pass impl. to the fallback code below
587 break;
588 default:
589 LOG_CRITICAL(HW_GPU, "Unimplemented tiled load for target={}",
590 static_cast<u32>(params.target));
591 UNREACHABLE();
592 }
549 593
594 gl_buffer.resize(static_cast<size_t>(params.depth) * copy_size);
550 morton_to_gl_fns[static_cast<size_t>(params.pixel_format)]( 595 morton_to_gl_fns[static_cast<size_t>(params.pixel_format)](
551 params.width, params.block_height, params.height, gl_buffer, params.addr); 596 params.width, params.block_height, params.height, gl_buffer.data(), copy_size,
597 params.addr);
552 } else { 598 } else {
553 const u8* const texture_src_data_end = texture_src_data + copy_size; 599 const u8* const texture_src_data_end{texture_src_data +
554 600 (static_cast<size_t>(params.depth) * copy_size)};
555 gl_buffer.assign(texture_src_data, texture_src_data_end); 601 gl_buffer.assign(texture_src_data, texture_src_data_end);
556 } 602 }
557 603
@@ -560,23 +606,7 @@ void CachedSurface::LoadGLBuffer() {
560 606
561MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); 607MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
562void CachedSurface::FlushGLBuffer() { 608void CachedSurface::FlushGLBuffer() {
563 u8* const dst_buffer = Memory::GetPointer(params.addr); 609 ASSERT_MSG(false, "Unimplemented");
564
565 ASSERT(dst_buffer);
566 ASSERT(gl_buffer.size() ==
567 params.width * params.height * GetGLBytesPerPixel(params.pixel_format));
568
569 MICROPROFILE_SCOPE(OpenGL_SurfaceFlush);
570
571 ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width,
572 params.height);
573
574 if (!params.is_tiled) {
575 std::memcpy(dst_buffer, gl_buffer.data(), params.size_in_bytes);
576 } else {
577 gl_to_morton_fns[static_cast<size_t>(params.pixel_format)](
578 params.width, params.block_height, params.height, gl_buffer, params.addr);
579 }
580} 610}
581 611
582MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); 612MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
@@ -586,22 +616,29 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
586 616
587 MICROPROFILE_SCOPE(OpenGL_TextureUL); 617 MICROPROFILE_SCOPE(OpenGL_TextureUL);
588 618
589 ASSERT(gl_buffer.size() == 619 ASSERT(gl_buffer.size() == static_cast<size_t>(params.width) * params.height *
590 params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); 620 GetGLBytesPerPixel(params.pixel_format) * params.depth);
591 621
592 const auto& rect{params.GetRect()}; 622 const auto& rect{params.GetRect()};
593 623
594 // Load data from memory to the surface 624 // Load data from memory to the surface
595 GLint x0 = static_cast<GLint>(rect.left); 625 const GLint x0 = static_cast<GLint>(rect.left);
596 GLint y0 = static_cast<GLint>(rect.bottom); 626 const GLint y0 = static_cast<GLint>(rect.bottom);
597 size_t buffer_offset = (y0 * params.width + x0) * GetGLBytesPerPixel(params.pixel_format); 627 const size_t buffer_offset =
628 static_cast<size_t>(static_cast<size_t>(y0) * params.width + static_cast<size_t>(x0)) *
629 GetGLBytesPerPixel(params.pixel_format);
598 630
599 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); 631 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
600 GLuint target_tex = texture.handle; 632 const GLuint target_tex = texture.handle;
601 OpenGLState cur_state = OpenGLState::GetCurState(); 633 OpenGLState cur_state = OpenGLState::GetCurState();
602 634
603 GLuint old_tex = cur_state.texture_units[0].texture_2d; 635 const auto& old_tex = cur_state.texture_units[0];
604 cur_state.texture_units[0].texture_2d = target_tex; 636 SCOPE_EXIT({
637 cur_state.texture_units[0] = old_tex;
638 cur_state.Apply();
639 });
640 cur_state.texture_units[0].texture = target_tex;
641 cur_state.texture_units[0].target = SurfaceTargetToGL(params.target);
605 cur_state.Apply(); 642 cur_state.Apply();
606 643
607 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT 644 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
@@ -610,136 +647,102 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
610 647
611 glActiveTexture(GL_TEXTURE0); 648 glActiveTexture(GL_TEXTURE0);
612 if (tuple.compressed) { 649 if (tuple.compressed) {
613 glCompressedTexImage2D( 650 switch (params.target) {
614 GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), 651 case SurfaceParams::SurfaceTarget::Texture2D:
615 static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes), 652 glCompressedTexImage2D(
616 &gl_buffer[buffer_offset]); 653 SurfaceTargetToGL(params.target), 0, tuple.internal_format,
654 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0,
655 static_cast<GLsizei>(params.size_in_bytes), &gl_buffer[buffer_offset]);
656 break;
657 case SurfaceParams::SurfaceTarget::Texture3D:
658 case SurfaceParams::SurfaceTarget::Texture2DArray:
659 glCompressedTexImage3D(
660 SurfaceTargetToGL(params.target), 0, tuple.internal_format,
661 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height),
662 static_cast<GLsizei>(params.depth), 0, static_cast<GLsizei>(params.size_in_bytes),
663 &gl_buffer[buffer_offset]);
664 break;
665 default:
666 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
667 static_cast<u32>(params.target));
668 UNREACHABLE();
669 glCompressedTexImage2D(
670 GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width),
671 static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes),
672 &gl_buffer[buffer_offset]);
673 }
617 } else { 674 } else {
618 glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
619 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
620 &gl_buffer[buffer_offset]);
621 }
622
623 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
624
625 cur_state.texture_units[0].texture_2d = old_tex;
626 cur_state.Apply();
627}
628
629MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64));
630void CachedSurface::DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) {
631 if (params.type == SurfaceType::Fill)
632 return;
633
634 MICROPROFILE_SCOPE(OpenGL_TextureDL);
635
636 gl_buffer.resize(params.width * params.height * GetGLBytesPerPixel(params.pixel_format));
637
638 OpenGLState state = OpenGLState::GetCurState();
639 OpenGLState prev_state = state;
640 SCOPE_EXIT({ prev_state.Apply(); });
641
642 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
643
644 // Ensure no bad interactions with GL_PACK_ALIGNMENT
645 ASSERT(params.width * GetGLBytesPerPixel(params.pixel_format) % 4 == 0);
646 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width));
647
648 const auto& rect{params.GetRect()};
649 size_t buffer_offset =
650 (rect.bottom * params.width + rect.left) * GetGLBytesPerPixel(params.pixel_format);
651
652 state.UnbindTexture(texture.handle);
653 state.draw.read_framebuffer = read_fb_handle;
654 state.Apply();
655 675
656 if (params.type == SurfaceType::ColorTexture) { 676 switch (params.target) {
657 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 677 case SurfaceParams::SurfaceTarget::Texture1D:
658 texture.handle, 0); 678 glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0,
659 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 679 static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
660 0); 680 &gl_buffer[buffer_offset]);
661 } else if (params.type == SurfaceType::Depth) { 681 break;
662 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 682 case SurfaceParams::SurfaceTarget::Texture2D:
663 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 683 glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0,
664 texture.handle, 0); 684 static_cast<GLsizei>(rect.GetWidth()),
665 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 685 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
666 } else { 686 &gl_buffer[buffer_offset]);
667 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 687 break;
668 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 688 case SurfaceParams::SurfaceTarget::Texture3D:
669 texture.handle, 0); 689 case SurfaceParams::SurfaceTarget::Texture2DArray:
690 glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0,
691 static_cast<GLsizei>(rect.GetWidth()),
692 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
693 tuple.type, &gl_buffer[buffer_offset]);
694 break;
695 default:
696 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
697 static_cast<u32>(params.target));
698 UNREACHABLE();
699 glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
700 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
701 &gl_buffer[buffer_offset]);
702 }
670 } 703 }
671 glReadPixels(static_cast<GLint>(rect.left), static_cast<GLint>(rect.bottom),
672 static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()),
673 tuple.format, tuple.type, &gl_buffer[buffer_offset]);
674 704
675 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 705 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
676} 706}
677 707
678RasterizerCacheOpenGL::RasterizerCacheOpenGL() { 708RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
679 read_framebuffer.Create(); 709 read_framebuffer.Create();
680 draw_framebuffer.Create(); 710 draw_framebuffer.Create();
711 copy_pbo.Create();
681} 712}
682 713
683Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { 714Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
684 return GetSurface(SurfaceParams::CreateForTexture(config)); 715 return GetSurface(SurfaceParams::CreateForTexture(config));
685} 716}
686 717
687SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(bool using_color_fb, 718Surface RasterizerCacheOpenGL::GetDepthBufferSurface(bool preserve_contents) {
688 bool using_depth_fb, 719 const auto& regs{Core::System::GetInstance().GPU().Maxwell3D().regs};
689 bool preserve_contents) { 720 if (!regs.zeta.Address() || !regs.zeta_enable) {
690 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 721 return {};
722 }
691 723
692 // TODO(bunnei): This is hard corded to use just the first render buffer 724 SurfaceParams depth_params{SurfaceParams::CreateForDepthBuffer(
693 LOG_TRACE(Render_OpenGL, "hard-coded for render target 0!"); 725 regs.zeta_width, regs.zeta_height, regs.zeta.Address(), regs.zeta.format)};
694 726
695 // get color and depth surfaces 727 return GetSurface(depth_params, preserve_contents);
696 SurfaceParams color_params{}; 728}
697 SurfaceParams depth_params{};
698 729
699 if (using_color_fb) { 730Surface RasterizerCacheOpenGL::GetColorBufferSurface(size_t index, bool preserve_contents) {
700 color_params = SurfaceParams::CreateForFramebuffer(regs.rt[0]); 731 const auto& regs{Core::System::GetInstance().GPU().Maxwell3D().regs};
701 }
702 732
703 if (using_depth_fb) { 733 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
704 depth_params = SurfaceParams::CreateForDepthBuffer(regs.zeta_width, regs.zeta_height,
705 regs.zeta.Address(), regs.zeta.format);
706 }
707 734
708 MathUtil::Rectangle<u32> color_rect{}; 735 if (index >= regs.rt_control.count) {
709 Surface color_surface; 736 return {};
710 if (using_color_fb) {
711 color_surface = GetSurface(color_params, preserve_contents);
712 if (color_surface) {
713 color_rect = color_surface->GetSurfaceParams().GetRect();
714 }
715 } 737 }
716 738
717 MathUtil::Rectangle<u32> depth_rect{}; 739 if (regs.rt[index].Address() == 0 || regs.rt[index].format == Tegra::RenderTargetFormat::NONE) {
718 Surface depth_surface; 740 return {};
719 if (using_depth_fb) {
720 depth_surface = GetSurface(depth_params, preserve_contents);
721 if (depth_surface) {
722 depth_rect = depth_surface->GetSurfaceParams().GetRect();
723 }
724 } 741 }
725 742
726 MathUtil::Rectangle<u32> fb_rect{}; 743 const SurfaceParams color_params{SurfaceParams::CreateForFramebuffer(index)};
727 if (color_surface && depth_surface) {
728 fb_rect = color_rect;
729 // Color and Depth surfaces must have the same dimensions and offsets
730 if (color_rect.bottom != depth_rect.bottom || color_rect.top != depth_rect.top ||
731 color_rect.left != depth_rect.left || color_rect.right != depth_rect.right) {
732 color_surface = GetSurface(color_params);
733 depth_surface = GetSurface(depth_params);
734 fb_rect = color_surface->GetSurfaceParams().GetRect();
735 }
736 } else if (color_surface) {
737 fb_rect = color_rect;
738 } else if (depth_surface) {
739 fb_rect = depth_rect;
740 }
741 744
742 return std::make_tuple(color_surface, depth_surface, fb_rect); 745 return GetSurface(color_params, preserve_contents);
743} 746}
744 747
745void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { 748void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) {
@@ -748,7 +751,6 @@ void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) {
748} 751}
749 752
750void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) { 753void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) {
751 surface->DownloadGLTexture(read_framebuffer.handle, draw_framebuffer.handle);
752 surface->FlushGLBuffer(); 754 surface->FlushGLBuffer();
753} 755}
754 756
@@ -806,27 +808,26 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
806 // Get a new surface with the new parameters, and blit the previous surface to it 808 // Get a new surface with the new parameters, and blit the previous surface to it
807 Surface new_surface{GetUncachedSurface(new_params)}; 809 Surface new_surface{GetUncachedSurface(new_params)};
808 810
809 // If format is unchanged, we can do a faster blit without reinterpreting pixel data 811 if (params.pixel_format == new_params.pixel_format ||
810 if (params.pixel_format == new_params.pixel_format) { 812 !Settings::values.use_accurate_framebuffers) {
813 // If the format is the same, just do a framebuffer blit. This is significantly faster than
814 // using PBOs. The is also likely less accurate, as textures will be converted rather than
815 // reinterpreted.
816
811 BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle, 817 BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
812 new_surface->GetSurfaceParams().GetRect(), params.type, 818 params.GetRect(), params.type, read_framebuffer.handle,
813 read_framebuffer.handle, draw_framebuffer.handle); 819 draw_framebuffer.handle);
814 return new_surface; 820 } else {
815 } 821 // When use_accurate_framebuffers setting is enabled, perform a more accurate surface copy,
822 // where pixels are reinterpreted as a new format (without conversion). This code path uses
823 // OpenGL PBOs and is quite slow.
816 824
817 // When using accurate framebuffers, always copy old data to new surface, regardless of format
818 if (Settings::values.use_accurate_framebuffers) {
819 auto source_format = GetFormatTuple(params.pixel_format, params.component_type); 825 auto source_format = GetFormatTuple(params.pixel_format, params.component_type);
820 auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type); 826 auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type);
821 827
822 size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes()); 828 size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes());
823 829
824 // Use a Pixel Buffer Object to download the previous texture and then upload it to the new 830 glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle);
825 // one using the new format.
826 OGLBuffer pbo;
827 pbo.Create();
828
829 glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
830 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); 831 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
831 if (source_format.compressed) { 832 if (source_format.compressed) {
832 glGetCompressedTextureImage(surface->Texture().handle, 0, 833 glGetCompressedTextureImage(surface->Texture().handle, 0,
@@ -845,8 +846,8 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
845 // of the data in this case. Games like Super Mario Odyssey seem to hit this case 846 // of the data in this case. Games like Super Mario Odyssey seem to hit this case
846 // when drawing, it re-uses the memory of a previous texture as a bigger framebuffer 847 // when drawing, it re-uses the memory of a previous texture as a bigger framebuffer
847 // but it doesn't clear it beforehand, the texture is already full of zeros. 848 // but it doesn't clear it beforehand, the texture is already full of zeros.
848 LOG_CRITICAL(HW_GPU, "Trying to upload extra texture data from the CPU during " 849 LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during "
849 "reinterpretation but the texture is tiled."); 850 "reinterpretation but the texture is tiled.");
850 } 851 }
851 size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes(); 852 size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
852 std::vector<u8> data(remaining_size); 853 std::vector<u8> data(remaining_size);
@@ -859,21 +860,38 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
859 860
860 const auto& dest_rect{new_params.GetRect()}; 861 const auto& dest_rect{new_params.GetRect()};
861 862
862 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle); 863 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo.handle);
863 if (dest_format.compressed) { 864 if (dest_format.compressed) {
864 glCompressedTexSubImage2D( 865 LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!");
865 GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()), 866 UNREACHABLE();
866 static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
867 static_cast<GLsizei>(new_params.SizeInBytes()), nullptr);
868 } else { 867 } else {
869 glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, 868 switch (new_params.target) {
870 static_cast<GLsizei>(dest_rect.GetWidth()), 869 case SurfaceParams::SurfaceTarget::Texture1D:
871 static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, 870 glTextureSubImage1D(new_surface->Texture().handle, 0, 0,
872 dest_format.type, nullptr); 871 static_cast<GLsizei>(dest_rect.GetWidth()), dest_format.format,
872 dest_format.type, nullptr);
873 break;
874 case SurfaceParams::SurfaceTarget::Texture2D:
875 glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0,
876 static_cast<GLsizei>(dest_rect.GetWidth()),
877 static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
878 dest_format.type, nullptr);
879 break;
880 case SurfaceParams::SurfaceTarget::Texture3D:
881 case SurfaceParams::SurfaceTarget::Texture2DArray:
882 glTextureSubImage3D(new_surface->Texture().handle, 0, 0, 0, 0,
883 static_cast<GLsizei>(dest_rect.GetWidth()),
884 static_cast<GLsizei>(dest_rect.GetHeight()),
885 static_cast<GLsizei>(new_params.depth), dest_format.format,
886 dest_format.type, nullptr);
887 break;
888 default:
889 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
890 static_cast<u32>(params.target));
891 UNREACHABLE();
892 }
873 } 893 }
874 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 894 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
875
876 pbo.Release();
877 } 895 }
878 896
879 return new_surface; 897 return new_surface;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index aad75f200..57ea8593b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -109,6 +109,33 @@ struct SurfaceParams {
109 Invalid = 4, 109 Invalid = 4,
110 }; 110 };
111 111
112 enum class SurfaceTarget {
113 Texture1D,
114 Texture2D,
115 Texture3D,
116 Texture1DArray,
117 Texture2DArray,
118 TextureCubemap,
119 };
120
121 static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
122 switch (texture_type) {
123 case Tegra::Texture::TextureType::Texture1D:
124 return SurfaceTarget::Texture1D;
125 case Tegra::Texture::TextureType::Texture2D:
126 case Tegra::Texture::TextureType::Texture2DNoMipmap:
127 return SurfaceTarget::Texture2D;
128 case Tegra::Texture::TextureType::Texture1DArray:
129 return SurfaceTarget::Texture1DArray;
130 case Tegra::Texture::TextureType::Texture2DArray:
131 return SurfaceTarget::Texture2DArray;
132 default:
133 LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
134 UNREACHABLE();
135 return SurfaceTarget::Texture2D;
136 }
137 }
138
112 /** 139 /**
113 * Gets the compression factor for the specified PixelFormat. This applies to just the 140 * Gets the compression factor for the specified PixelFormat. This applies to just the
114 * "compressed width" and "compressed height", not the overall compression factor of a 141 * "compressed width" and "compressed height", not the overall compression factor of a
@@ -270,6 +297,7 @@ struct SurfaceParams {
270 return PixelFormat::ABGR8S; 297 return PixelFormat::ABGR8S;
271 case Tegra::RenderTargetFormat::RGBA8_UINT: 298 case Tegra::RenderTargetFormat::RGBA8_UINT:
272 return PixelFormat::ABGR8UI; 299 return PixelFormat::ABGR8UI;
300 case Tegra::RenderTargetFormat::BGRA8_SRGB:
273 case Tegra::RenderTargetFormat::BGRA8_UNORM: 301 case Tegra::RenderTargetFormat::BGRA8_UNORM:
274 return PixelFormat::BGRA8; 302 return PixelFormat::BGRA8;
275 case Tegra::RenderTargetFormat::RGB10_A2_UNORM: 303 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
@@ -542,6 +570,7 @@ struct SurfaceParams {
542 case Tegra::RenderTargetFormat::RGBA8_UNORM: 570 case Tegra::RenderTargetFormat::RGBA8_UNORM:
543 case Tegra::RenderTargetFormat::RGBA8_SRGB: 571 case Tegra::RenderTargetFormat::RGBA8_SRGB:
544 case Tegra::RenderTargetFormat::BGRA8_UNORM: 572 case Tegra::RenderTargetFormat::BGRA8_UNORM:
573 case Tegra::RenderTargetFormat::BGRA8_SRGB:
545 case Tegra::RenderTargetFormat::RGB10_A2_UNORM: 574 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
546 case Tegra::RenderTargetFormat::R8_UNORM: 575 case Tegra::RenderTargetFormat::R8_UNORM:
547 case Tegra::RenderTargetFormat::RG16_UNORM: 576 case Tegra::RenderTargetFormat::RG16_UNORM:
@@ -635,15 +664,14 @@ struct SurfaceParams {
635 ASSERT(width % compression_factor == 0); 664 ASSERT(width % compression_factor == 0);
636 ASSERT(height % compression_factor == 0); 665 ASSERT(height % compression_factor == 0);
637 return (width / compression_factor) * (height / compression_factor) * 666 return (width / compression_factor) * (height / compression_factor) *
638 GetFormatBpp(pixel_format) / CHAR_BIT; 667 GetFormatBpp(pixel_format) * depth / CHAR_BIT;
639 } 668 }
640 669
641 /// Creates SurfaceParams from a texture configuration 670 /// Creates SurfaceParams from a texture configuration
642 static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config); 671 static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config);
643 672
644 /// Creates SurfaceParams from a framebuffer configuration 673 /// Creates SurfaceParams from a framebuffer configuration
645 static SurfaceParams CreateForFramebuffer( 674 static SurfaceParams CreateForFramebuffer(size_t index);
646 const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config);
647 675
648 /// Creates SurfaceParams for a depth buffer configuration 676 /// Creates SurfaceParams for a depth buffer configuration
649 static SurfaceParams CreateForDepthBuffer(u32 zeta_width, u32 zeta_height, 677 static SurfaceParams CreateForDepthBuffer(u32 zeta_width, u32 zeta_height,
@@ -652,8 +680,8 @@ struct SurfaceParams {
652 680
653 /// Checks if surfaces are compatible for caching 681 /// Checks if surfaces are compatible for caching
654 bool IsCompatibleSurface(const SurfaceParams& other) const { 682 bool IsCompatibleSurface(const SurfaceParams& other) const {
655 return std::tie(pixel_format, type, cache_width, cache_height) == 683 return std::tie(pixel_format, type, width, height) ==
656 std::tie(other.pixel_format, other.type, other.cache_width, other.cache_height); 684 std::tie(other.pixel_format, other.type, other.width, other.height);
657 } 685 }
658 686
659 VAddr addr; 687 VAddr addr;
@@ -664,12 +692,10 @@ struct SurfaceParams {
664 SurfaceType type; 692 SurfaceType type;
665 u32 width; 693 u32 width;
666 u32 height; 694 u32 height;
695 u32 depth;
667 u32 unaligned_height; 696 u32 unaligned_height;
668 size_t size_in_bytes; 697 size_t size_in_bytes;
669 698 SurfaceTarget target;
670 // Parameters used for caching only
671 u32 cache_width;
672 u32 cache_height;
673}; 699};
674 700
675}; // namespace OpenGL 701}; // namespace OpenGL
@@ -709,6 +735,10 @@ public:
709 return texture; 735 return texture;
710 } 736 }
711 737
738 GLenum Target() const {
739 return gl_target;
740 }
741
712 static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) { 742 static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) {
713 if (format == SurfaceParams::PixelFormat::Invalid) 743 if (format == SurfaceParams::PixelFormat::Invalid)
714 return 0; 744 return 0;
@@ -724,14 +754,14 @@ public:
724 void LoadGLBuffer(); 754 void LoadGLBuffer();
725 void FlushGLBuffer(); 755 void FlushGLBuffer();
726 756
727 // Upload/Download data in gl_buffer in/to this surface's texture 757 // Upload data in gl_buffer to this surface's texture
728 void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); 758 void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
729 void DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
730 759
731private: 760private:
732 OGLTexture texture; 761 OGLTexture texture;
733 std::vector<u8> gl_buffer; 762 std::vector<u8> gl_buffer;
734 SurfaceParams params; 763 SurfaceParams params;
764 GLenum gl_target;
735}; 765};
736 766
737class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { 767class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
@@ -741,9 +771,11 @@ public:
741 /// Get a surface based on the texture configuration 771 /// Get a surface based on the texture configuration
742 Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); 772 Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config);
743 773
744 /// Get the color and depth surfaces based on the framebuffer configuration 774 /// Get the depth surface based on the framebuffer configuration
745 SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, 775 Surface GetDepthBufferSurface(bool preserve_contents);
746 bool preserve_contents); 776
777 /// Get the color surface based on the framebuffer configuration and the specified render target
778 Surface GetColorBufferSurface(size_t index, bool preserve_contents);
747 779
748 /// Flushes the surface to Switch memory 780 /// Flushes the surface to Switch memory
749 void FlushSurface(const Surface& surface); 781 void FlushSurface(const Surface& surface);
@@ -774,6 +806,10 @@ private:
774 806
775 OGLFramebuffer read_framebuffer; 807 OGLFramebuffer read_framebuffer;
776 OGLFramebuffer draw_framebuffer; 808 OGLFramebuffer draw_framebuffer;
809
810 /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one
811 /// using the new format.
812 OGLBuffer copy_pbo;
777}; 813};
778 814
779} // namespace OpenGL 815} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 7e4b85ac3..61080f5cc 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -13,8 +13,8 @@ namespace OpenGL {
13 13
14/// Gets the address for the specified shader stage program 14/// Gets the address for the specified shader stage program
15static VAddr GetShaderAddress(Maxwell::ShaderProgram program) { 15static VAddr GetShaderAddress(Maxwell::ShaderProgram program) {
16 auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); 16 const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
17 auto& shader_config = gpu.regs.shader_config[static_cast<size_t>(program)]; 17 const auto& shader_config = gpu.regs.shader_config[static_cast<size_t>(program)];
18 return *gpu.memory_manager.GpuToCpuAddress(gpu.regs.code_address.CodeAddress() + 18 return *gpu.memory_manager.GpuToCpuAddress(gpu.regs.code_address.CodeAddress() +
19 shader_config.offset); 19 shader_config.offset);
20} 20}
@@ -86,7 +86,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
86} 86}
87 87
88GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) { 88GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) {
89 auto search{resource_cache.find(buffer.GetHash())}; 89 const auto search{resource_cache.find(buffer.GetHash())};
90 if (search == resource_cache.end()) { 90 if (search == resource_cache.end()) {
91 const GLuint index{ 91 const GLuint index{
92 glGetProgramResourceIndex(program.handle, GL_UNIFORM_BLOCK, buffer.GetName().c_str())}; 92 glGetProgramResourceIndex(program.handle, GL_UNIFORM_BLOCK, buffer.GetName().c_str())};
@@ -98,7 +98,7 @@ GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& b
98} 98}
99 99
100GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) { 100GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) {
101 auto search{uniform_cache.find(sampler.GetHash())}; 101 const auto search{uniform_cache.find(sampler.GetHash())};
102 if (search == uniform_cache.end()) { 102 if (search == uniform_cache.end()) {
103 const GLint index{glGetUniformLocation(program.handle, sampler.GetName().c_str())}; 103 const GLint index{glGetUniformLocation(program.handle, sampler.GetName().c_str())};
104 uniform_cache[sampler.GetHash()] = index; 104 uniform_cache[sampler.GetHash()] = index;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 841647ebe..2d56370c7 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -113,7 +113,7 @@ private:
113 113
114 /// Scans a range of code for labels and determines the exit method. 114 /// Scans a range of code for labels and determines the exit method.
115 ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) { 115 ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) {
116 auto [iter, inserted] = 116 const auto [iter, inserted] =
117 exit_method_map.emplace(std::make_pair(begin, end), ExitMethod::Undetermined); 117 exit_method_map.emplace(std::make_pair(begin, end), ExitMethod::Undetermined);
118 ExitMethod& exit_method = iter->second; 118 ExitMethod& exit_method = iter->second;
119 if (!inserted) 119 if (!inserted)
@@ -131,22 +131,22 @@ private:
131 if (instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex)) { 131 if (instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex)) {
132 return exit_method = ExitMethod::AlwaysEnd; 132 return exit_method = ExitMethod::AlwaysEnd;
133 } else { 133 } else {
134 ExitMethod not_met = Scan(offset + 1, end, labels); 134 const ExitMethod not_met = Scan(offset + 1, end, labels);
135 return exit_method = ParallelExit(ExitMethod::AlwaysEnd, not_met); 135 return exit_method = ParallelExit(ExitMethod::AlwaysEnd, not_met);
136 } 136 }
137 } 137 }
138 case OpCode::Id::BRA: { 138 case OpCode::Id::BRA: {
139 u32 target = offset + instr.bra.GetBranchTarget(); 139 const u32 target = offset + instr.bra.GetBranchTarget();
140 labels.insert(target); 140 labels.insert(target);
141 ExitMethod no_jmp = Scan(offset + 1, end, labels); 141 const ExitMethod no_jmp = Scan(offset + 1, end, labels);
142 ExitMethod jmp = Scan(target, end, labels); 142 const ExitMethod jmp = Scan(target, end, labels);
143 return exit_method = ParallelExit(no_jmp, jmp); 143 return exit_method = ParallelExit(no_jmp, jmp);
144 } 144 }
145 case OpCode::Id::SSY: { 145 case OpCode::Id::SSY: {
146 // The SSY instruction uses a similar encoding as the BRA instruction. 146 // The SSY instruction uses a similar encoding as the BRA instruction.
147 ASSERT_MSG(instr.bra.constant_buffer == 0, 147 ASSERT_MSG(instr.bra.constant_buffer == 0,
148 "Constant buffer SSY is not supported"); 148 "Constant buffer SSY is not supported");
149 u32 target = offset + instr.bra.GetBranchTarget(); 149 const u32 target = offset + instr.bra.GetBranchTarget();
150 labels.insert(target); 150 labels.insert(target);
151 // Continue scanning for an exit method. 151 // Continue scanning for an exit method.
152 break; 152 break;
@@ -346,8 +346,8 @@ public:
346 */ 346 */
347 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute, 347 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute,
348 const Tegra::Shader::IpaMode& input_mode) { 348 const Tegra::Shader::IpaMode& input_mode) {
349 std::string dest = GetRegisterAsFloat(reg); 349 const std::string dest = GetRegisterAsFloat(reg);
350 std::string src = GetInputAttribute(attribute, input_mode) + GetSwizzle(elem); 350 const std::string src = GetInputAttribute(attribute, input_mode) + GetSwizzle(elem);
351 shader.AddLine(dest + " = " + src + ';'); 351 shader.AddLine(dest + " = " + src + ';');
352 } 352 }
353 353
@@ -359,8 +359,8 @@ public:
359 * @param reg The register to use as the source value. 359 * @param reg The register to use as the source value.
360 */ 360 */
361 void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) { 361 void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
362 std::string dest = GetOutputAttribute(attribute); 362 const std::string dest = GetOutputAttribute(attribute);
363 std::string src = GetRegisterAsFloat(reg); 363 const std::string src = GetRegisterAsFloat(reg);
364 364
365 if (!dest.empty()) { 365 if (!dest.empty()) {
366 // Can happen with unknown/unimplemented output attributes, in which case we ignore the 366 // Can happen with unknown/unimplemented output attributes, in which case we ignore the
@@ -393,9 +393,9 @@ public:
393 GLSLRegister::Type type) { 393 GLSLRegister::Type type) {
394 declr_const_buffers[cbuf_index].MarkAsUsedIndirect(cbuf_index, stage); 394 declr_const_buffers[cbuf_index].MarkAsUsedIndirect(cbuf_index, stage);
395 395
396 std::string final_offset = fmt::format("({} + {})", index_str, offset / 4); 396 const std::string final_offset = fmt::format("({} + {})", index_str, offset / 4);
397 std::string value = 'c' + std::to_string(cbuf_index) + '[' + final_offset + " / 4][" + 397 const std::string value = 'c' + std::to_string(cbuf_index) + '[' + final_offset + " / 4][" +
398 final_offset + " % 4]"; 398 final_offset + " % 4]";
399 399
400 if (type == GLSLRegister::Type::Float) { 400 if (type == GLSLRegister::Type::Float) {
401 return value; 401 return value;
@@ -443,13 +443,12 @@ public:
443 } 443 }
444 declarations.AddNewLine(); 444 declarations.AddNewLine();
445 445
446 // Append the sampler2D array for the used textures. 446 const auto& samplers = GetSamplers();
447 const size_t num_samplers = used_samplers.size(); 447 for (const auto& sampler : samplers) {
448 if (num_samplers > 0) { 448 declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() +
449 declarations.AddLine("uniform sampler2D " + SamplerEntry::GetArrayName(stage) + '[' + 449 ';');
450 std::to_string(num_samplers) + "];");
451 declarations.AddNewLine();
452 } 450 }
451 declarations.AddNewLine();
453 } 452 }
454 453
455 /// Returns a list of constant buffer declarations 454 /// Returns a list of constant buffer declarations
@@ -461,27 +460,29 @@ public:
461 } 460 }
462 461
463 /// Returns a list of samplers used in the shader 462 /// Returns a list of samplers used in the shader
464 std::vector<SamplerEntry> GetSamplers() const { 463 const std::vector<SamplerEntry>& GetSamplers() const {
465 return used_samplers; 464 return used_samplers;
466 } 465 }
467 466
468 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if 467 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
469 /// necessary. 468 /// necessary.
470 std::string AccessSampler(const Sampler& sampler) { 469 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
471 size_t offset = static_cast<size_t>(sampler.index.Value()); 470 bool is_array) {
471 const size_t offset = static_cast<size_t>(sampler.index.Value());
472 472
473 // If this sampler has already been used, return the existing mapping. 473 // If this sampler has already been used, return the existing mapping.
474 auto itr = 474 const auto itr =
475 std::find_if(used_samplers.begin(), used_samplers.end(), 475 std::find_if(used_samplers.begin(), used_samplers.end(),
476 [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); 476 [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; });
477 477
478 if (itr != used_samplers.end()) { 478 if (itr != used_samplers.end()) {
479 ASSERT(itr->GetType() == type && itr->IsArray() == is_array);
479 return itr->GetName(); 480 return itr->GetName();
480 } 481 }
481 482
482 // Otherwise create a new mapping for this sampler 483 // Otherwise create a new mapping for this sampler
483 size_t next_index = used_samplers.size(); 484 const size_t next_index = used_samplers.size();
484 SamplerEntry entry{stage, offset, next_index}; 485 const SamplerEntry entry{stage, offset, next_index, type, is_array};
485 used_samplers.emplace_back(entry); 486 used_samplers.emplace_back(entry);
486 return entry.GetName(); 487 return entry.GetName();
487 } 488 }
@@ -698,7 +699,7 @@ private:
698 }; 699 };
699 700
700 bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const { 701 bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const {
701 u32 bit = render_target * 4 + component; 702 const u32 bit = render_target * 4 + component;
702 return enabled_color_outputs & (1 << bit); 703 return enabled_color_outputs & (1 << bit);
703 } 704 }
704 }; 705 };
@@ -706,7 +707,7 @@ private:
706 707
707 /// Gets the Subroutine object corresponding to the specified address. 708 /// Gets the Subroutine object corresponding to the specified address.
708 const Subroutine& GetSubroutine(u32 begin, u32 end) const { 709 const Subroutine& GetSubroutine(u32 begin, u32 end) const {
709 auto iter = subroutines.find(Subroutine{begin, end, suffix}); 710 const auto iter = subroutines.find(Subroutine{begin, end, suffix});
710 ASSERT(iter != subroutines.end()); 711 ASSERT(iter != subroutines.end());
711 return *iter; 712 return *iter;
712 } 713 }
@@ -722,8 +723,8 @@ private:
722 } 723 }
723 724
724 /// Generates code representing a texture sampler. 725 /// Generates code representing a texture sampler.
725 std::string GetSampler(const Sampler& sampler) { 726 std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) {
726 return regs.AccessSampler(sampler); 727 return regs.AccessSampler(sampler, type, is_array);
727 } 728 }
728 729
729 /** 730 /**
@@ -751,7 +752,7 @@ private:
751 // Can't assign to the constant predicate. 752 // Can't assign to the constant predicate.
752 ASSERT(pred != static_cast<u64>(Pred::UnusedIndex)); 753 ASSERT(pred != static_cast<u64>(Pred::UnusedIndex));
753 754
754 std::string variable = 'p' + std::to_string(pred) + '_' + suffix; 755 const std::string variable = 'p' + std::to_string(pred) + '_' + suffix;
755 shader.AddLine(variable + " = " + value + ';'); 756 shader.AddLine(variable + " = " + value + ';');
756 declr_predicates.insert(std::move(variable)); 757 declr_predicates.insert(std::move(variable));
757 } 758 }
@@ -1022,7 +1023,7 @@ private:
1022 // TODO(Subv): Figure out how dual-source blending is configured in the Switch. 1023 // TODO(Subv): Figure out how dual-source blending is configured in the Switch.
1023 for (u32 component = 0; component < 4; ++component) { 1024 for (u32 component = 0; component < 4; ++component) {
1024 if (header.IsColorComponentOutputEnabled(render_target, component)) { 1025 if (header.IsColorComponentOutputEnabled(render_target, component)) {
1025 shader.AddLine(fmt::format("color[{}][{}] = {};", render_target, component, 1026 shader.AddLine(fmt::format("FragColor{}[{}] = {};", render_target, component,
1026 regs.GetRegisterAsFloat(current_reg))); 1027 regs.GetRegisterAsFloat(current_reg)));
1027 ++current_reg; 1028 ++current_reg;
1028 } 1029 }
@@ -1032,7 +1033,11 @@ private:
1032 if (header.writes_depth) { 1033 if (header.writes_depth) {
1033 // The depth output is always 2 registers after the last color output, and current_reg 1034 // The depth output is always 2 registers after the last color output, and current_reg
1034 // already contains one past the last color register. 1035 // already contains one past the last color register.
1035 shader.AddLine("gl_FragDepth = " + regs.GetRegisterAsFloat(current_reg + 1) + ';'); 1036
1037 shader.AddLine(
1038 "gl_FragDepth = " +
1039 regs.GetRegisterAsFloat(static_cast<Tegra::Shader::Register>(current_reg) + 1) +
1040 ';');
1036 } 1041 }
1037 } 1042 }
1038 1043
@@ -1434,7 +1439,7 @@ private:
1434 if (instr.alu_integer.negate_b) 1439 if (instr.alu_integer.negate_b)
1435 op_b = "-(" + op_b + ')'; 1440 op_b = "-(" + op_b + ')';
1436 1441
1437 std::string shift = std::to_string(instr.alu_integer.shift_amount.Value()); 1442 const std::string shift = std::to_string(instr.alu_integer.shift_amount.Value());
1438 1443
1439 regs.SetRegisterToInteger(instr.gpr0, true, 0, 1444 regs.SetRegisterToInteger(instr.gpr0, true, 0,
1440 "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); 1445 "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1);
@@ -1452,7 +1457,7 @@ private:
1452 case OpCode::Id::SEL_C: 1457 case OpCode::Id::SEL_C:
1453 case OpCode::Id::SEL_R: 1458 case OpCode::Id::SEL_R:
1454 case OpCode::Id::SEL_IMM: { 1459 case OpCode::Id::SEL_IMM: {
1455 std::string condition = 1460 const std::string condition =
1456 GetPredicateCondition(instr.sel.pred, instr.sel.neg_pred != 0); 1461 GetPredicateCondition(instr.sel.pred, instr.sel.neg_pred != 0);
1457 regs.SetRegisterToInteger(instr.gpr0, true, 0, 1462 regs.SetRegisterToInteger(instr.gpr0, true, 0,
1458 '(' + condition + ") ? " + op_a + " : " + op_b, 1, 1); 1463 '(' + condition + ") ? " + op_a + " : " + op_b, 1, 1);
@@ -1474,8 +1479,9 @@ private:
1474 case OpCode::Id::LOP3_C: 1479 case OpCode::Id::LOP3_C:
1475 case OpCode::Id::LOP3_R: 1480 case OpCode::Id::LOP3_R:
1476 case OpCode::Id::LOP3_IMM: { 1481 case OpCode::Id::LOP3_IMM: {
1477 std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); 1482 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
1478 std::string lut; 1483 std::string lut;
1484
1479 if (opcode->GetId() == OpCode::Id::LOP3_R) { 1485 if (opcode->GetId() == OpCode::Id::LOP3_R) {
1480 lut = '(' + std::to_string(instr.alu.lop3.GetImmLut28()) + ')'; 1486 lut = '(' + std::to_string(instr.alu.lop3.GetImmLut28()) + ')';
1481 } else { 1487 } else {
@@ -1490,15 +1496,82 @@ private:
1490 case OpCode::Id::IMNMX_IMM: { 1496 case OpCode::Id::IMNMX_IMM: {
1491 ASSERT_MSG(instr.imnmx.exchange == Tegra::Shader::IMinMaxExchange::None, 1497 ASSERT_MSG(instr.imnmx.exchange == Tegra::Shader::IMinMaxExchange::None,
1492 "Unimplemented"); 1498 "Unimplemented");
1493 std::string condition = 1499 const std::string condition =
1494 GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0); 1500 GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0);
1495 std::string parameters = op_a + ',' + op_b; 1501 const std::string parameters = op_a + ',' + op_b;
1496 regs.SetRegisterToInteger(instr.gpr0, instr.imnmx.is_signed, 0, 1502 regs.SetRegisterToInteger(instr.gpr0, instr.imnmx.is_signed, 0,
1497 '(' + condition + ") ? min(" + parameters + ") : max(" + 1503 '(' + condition + ") ? min(" + parameters + ") : max(" +
1498 parameters + ')', 1504 parameters + ')',
1499 1, 1); 1505 1, 1);
1500 break; 1506 break;
1501 } 1507 }
1508 case OpCode::Id::LEA_R2:
1509 case OpCode::Id::LEA_R1:
1510 case OpCode::Id::LEA_IMM:
1511 case OpCode::Id::LEA_RZ:
1512 case OpCode::Id::LEA_HI: {
1513 std::string op_a;
1514 std::string op_b;
1515 std::string op_c;
1516
1517 switch (opcode->GetId()) {
1518 case OpCode::Id::LEA_R2: {
1519 op_a = regs.GetRegisterAsInteger(instr.gpr20);
1520 op_b = regs.GetRegisterAsInteger(instr.gpr39);
1521 op_c = std::to_string(instr.lea.r2.entry_a);
1522 break;
1523 }
1524
1525 case OpCode::Id::LEA_R1: {
1526 const bool neg = instr.lea.r1.neg != 0;
1527 op_a = regs.GetRegisterAsInteger(instr.gpr8);
1528 if (neg)
1529 op_a = "-(" + op_a + ')';
1530 op_b = regs.GetRegisterAsInteger(instr.gpr20);
1531 op_c = std::to_string(instr.lea.r1.entry_a);
1532 break;
1533 }
1534
1535 case OpCode::Id::LEA_IMM: {
1536 const bool neg = instr.lea.imm.neg != 0;
1537 op_b = regs.GetRegisterAsInteger(instr.gpr8);
1538 if (neg)
1539 op_b = "-(" + op_b + ')';
1540 op_a = std::to_string(instr.lea.imm.entry_a);
1541 op_c = std::to_string(instr.lea.imm.entry_b);
1542 break;
1543 }
1544
1545 case OpCode::Id::LEA_RZ: {
1546 const bool neg = instr.lea.rz.neg != 0;
1547 op_b = regs.GetRegisterAsInteger(instr.gpr8);
1548 if (neg)
1549 op_b = "-(" + op_b + ')';
1550 op_a = regs.GetUniform(instr.lea.rz.cb_index, instr.lea.rz.cb_offset,
1551 GLSLRegister::Type::Integer);
1552 op_c = std::to_string(instr.lea.rz.entry_a);
1553
1554 break;
1555 }
1556
1557 case OpCode::Id::LEA_HI:
1558 default: {
1559 op_b = regs.GetRegisterAsInteger(instr.gpr8);
1560 op_a = std::to_string(instr.lea.imm.entry_a);
1561 op_c = std::to_string(instr.lea.imm.entry_b);
1562 LOG_CRITICAL(HW_GPU, "Unhandled LEA subinstruction: {}", opcode->GetName());
1563 UNREACHABLE();
1564 }
1565 }
1566 if (instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex)) {
1567 LOG_ERROR(HW_GPU, "Unhandled LEA Predicate");
1568 UNREACHABLE();
1569 }
1570 const std::string value = '(' + op_a + " + (" + op_b + "*(1 << " + op_c + ")))";
1571 regs.SetRegisterToInteger(instr.gpr0, true, 0, value, 1, 1);
1572
1573 break;
1574 }
1502 default: { 1575 default: {
1503 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", 1576 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}",
1504 opcode->GetName()); 1577 opcode->GetName());
@@ -1509,7 +1582,7 @@ private:
1509 break; 1582 break;
1510 } 1583 }
1511 case OpCode::Type::Ffma: { 1584 case OpCode::Type::Ffma: {
1512 std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 1585 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
1513 std::string op_b = instr.ffma.negate_b ? "-" : ""; 1586 std::string op_b = instr.ffma.negate_b ? "-" : "";
1514 std::string op_c = instr.ffma.negate_c ? "-" : ""; 1587 std::string op_c = instr.ffma.negate_c ? "-" : "";
1515 1588
@@ -1719,7 +1792,7 @@ private:
1719 shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + 1792 shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) +
1720 " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);"); 1793 " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);");
1721 1794
1722 std::string op_a = 1795 const std::string op_a =
1723 regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 0, "index", 1796 regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 0, "index",
1724 GLSLRegister::Type::Float); 1797 GLSLRegister::Type::Float);
1725 1798
@@ -1729,7 +1802,7 @@ private:
1729 break; 1802 break;
1730 1803
1731 case Tegra::Shader::UniformType::Double: { 1804 case Tegra::Shader::UniformType::Double: {
1732 std::string op_b = 1805 const std::string op_b =
1733 regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 4, 1806 regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 4,
1734 "index", GLSLRegister::Type::Float); 1807 "index", GLSLRegister::Type::Float);
1735 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); 1808 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
@@ -1753,17 +1826,74 @@ private:
1753 break; 1826 break;
1754 } 1827 }
1755 case OpCode::Id::TEX: { 1828 case OpCode::Id::TEX: {
1756 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 1829 ASSERT_MSG(instr.tex.array == 0, "TEX arrays unimplemented");
1757 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 1830 Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
1758 const std::string sampler = GetSampler(instr.sampler); 1831 std::string coord;
1759 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; 1832
1833 switch (texture_type) {
1834 case Tegra::Shader::TextureType::Texture1D: {
1835 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1836 coord = "float coords = " + x + ';';
1837 break;
1838 }
1839 case Tegra::Shader::TextureType::Texture2D: {
1840 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1841 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
1842 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
1843 break;
1844 }
1845 default:
1846 LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
1847 static_cast<u32>(texture_type));
1848 UNREACHABLE();
1849
1850 // Fallback to interpreting as a 2D texture for now
1851 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1852 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
1853 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
1854 texture_type = Tegra::Shader::TextureType::Texture2D;
1855 }
1856 // TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias
1857 // or lod.
1858 const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20);
1859
1860 const std::string sampler = GetSampler(instr.sampler, texture_type, false);
1760 // Add an extra scope and declare the texture coords inside to prevent 1861 // Add an extra scope and declare the texture coords inside to prevent
1761 // overwriting them in case they are used as outputs of the texs instruction. 1862 // overwriting them in case they are used as outputs of the texs instruction.
1863
1762 shader.AddLine("{"); 1864 shader.AddLine("{");
1763 ++shader.scope; 1865 ++shader.scope;
1764 shader.AddLine(coord); 1866 shader.AddLine(coord);
1765 const std::string texture = "texture(" + sampler + ", coords)"; 1867 std::string texture;
1766 1868
1869 switch (instr.tex.process_mode) {
1870 case Tegra::Shader::TextureProcessMode::None: {
1871 texture = "texture(" + sampler + ", coords)";
1872 break;
1873 }
1874 case Tegra::Shader::TextureProcessMode::LZ: {
1875 texture = "textureLod(" + sampler + ", coords, 0.0)";
1876 break;
1877 }
1878 case Tegra::Shader::TextureProcessMode::LB:
1879 case Tegra::Shader::TextureProcessMode::LBA: {
1880 // TODO: Figure if A suffix changes the equation at all.
1881 texture = "texture(" + sampler + ", coords, " + op_c + ')';
1882 break;
1883 }
1884 case Tegra::Shader::TextureProcessMode::LL:
1885 case Tegra::Shader::TextureProcessMode::LLA: {
1886 // TODO: Figure if A suffix changes the equation at all.
1887 texture = "textureLod(" + sampler + ", coords, " + op_c + ')';
1888 break;
1889 }
1890 default: {
1891 texture = "texture(" + sampler + ", coords)";
1892 LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}",
1893 static_cast<u32>(instr.tex.process_mode.Value()));
1894 UNREACHABLE();
1895 }
1896 }
1767 size_t dest_elem{}; 1897 size_t dest_elem{};
1768 for (size_t elem = 0; elem < 4; ++elem) { 1898 for (size_t elem = 0; elem < 4; ++elem) {
1769 if (!instr.tex.IsComponentEnabled(elem)) { 1899 if (!instr.tex.IsComponentEnabled(elem)) {
@@ -1778,20 +1908,65 @@ private:
1778 break; 1908 break;
1779 } 1909 }
1780 case OpCode::Id::TEXS: { 1910 case OpCode::Id::TEXS: {
1781 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 1911 std::string coord;
1782 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); 1912 Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
1783 const std::string sampler = GetSampler(instr.sampler); 1913 bool is_array{instr.texs.IsArrayTexture()};
1784 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; 1914
1915 switch (texture_type) {
1916 case Tegra::Shader::TextureType::Texture2D: {
1917 if (is_array) {
1918 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
1919 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
1920 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
1921 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
1922 } else {
1923 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1924 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
1925 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
1926 }
1927 break;
1928 }
1929 default:
1930 LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
1931 static_cast<u32>(texture_type));
1932 UNREACHABLE();
1785 1933
1934 // Fallback to interpreting as a 2D texture for now
1935 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1936 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
1937 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
1938 texture_type = Tegra::Shader::TextureType::Texture2D;
1939 is_array = false;
1940 }
1941 const std::string sampler = GetSampler(instr.sampler, texture_type, is_array);
1786 const std::string texture = "texture(" + sampler + ", coords)"; 1942 const std::string texture = "texture(" + sampler + ", coords)";
1787 WriteTexsInstruction(instr, coord, texture); 1943 WriteTexsInstruction(instr, coord, texture);
1788 break; 1944 break;
1789 } 1945 }
1790 case OpCode::Id::TLDS: { 1946 case OpCode::Id::TLDS: {
1791 const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); 1947 ASSERT(instr.tlds.GetTextureType() == Tegra::Shader::TextureType::Texture2D);
1792 const std::string op_b = regs.GetRegisterAsInteger(instr.gpr20); 1948 ASSERT(instr.tlds.IsArrayTexture() == false);
1793 const std::string sampler = GetSampler(instr.sampler); 1949 std::string coord;
1794 const std::string coord = "ivec2 coords = ivec2(" + op_a + ", " + op_b + ");"; 1950
1951 switch (instr.tlds.GetTextureType()) {
1952 case Tegra::Shader::TextureType::Texture2D: {
1953 if (instr.tlds.IsArrayTexture()) {
1954 LOG_CRITICAL(HW_GPU, "Unhandled 2d array texture");
1955 UNREACHABLE();
1956 } else {
1957 const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
1958 const std::string y = regs.GetRegisterAsInteger(instr.gpr20);
1959 coord = "ivec2 coords = ivec2(" + x + ", " + y + ");";
1960 }
1961 break;
1962 }
1963 default:
1964 LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
1965 static_cast<u32>(instr.tlds.GetTextureType()));
1966 UNREACHABLE();
1967 }
1968 const std::string sampler = GetSampler(instr.sampler, instr.tlds.GetTextureType(),
1969 instr.tlds.IsArrayTexture());
1795 const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; 1970 const std::string texture = "texelFetch(" + sampler + ", coords, 0)";
1796 WriteTexsInstruction(instr, coord, texture); 1971 WriteTexsInstruction(instr, coord, texture);
1797 break; 1972 break;
@@ -1799,12 +1974,12 @@ private:
1799 case OpCode::Id::TLD4: { 1974 case OpCode::Id::TLD4: {
1800 ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); 1975 ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D);
1801 ASSERT(instr.tld4.array == 0); 1976 ASSERT(instr.tld4.array == 0);
1802 std::string coord{}; 1977 std::string coord;
1803 1978
1804 switch (instr.tld4.texture_type) { 1979 switch (instr.tld4.texture_type) {
1805 case Tegra::Shader::TextureType::Texture2D: { 1980 case Tegra::Shader::TextureType::Texture2D: {
1806 std::string x = regs.GetRegisterAsFloat(instr.gpr8); 1981 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1807 std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 1982 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
1808 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 1983 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
1809 break; 1984 break;
1810 } 1985 }
@@ -1814,7 +1989,8 @@ private:
1814 UNREACHABLE(); 1989 UNREACHABLE();
1815 } 1990 }
1816 1991
1817 const std::string sampler = GetSampler(instr.sampler); 1992 const std::string sampler =
1993 GetSampler(instr.sampler, instr.tld4.texture_type, false);
1818 // Add an extra scope and declare the texture coords inside to prevent 1994 // Add an extra scope and declare the texture coords inside to prevent
1819 // overwriting them in case they are used as outputs of the texs instruction. 1995 // overwriting them in case they are used as outputs of the texs instruction.
1820 shader.AddLine("{"); 1996 shader.AddLine("{");
@@ -1840,13 +2016,82 @@ private:
1840 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 2016 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
1841 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); 2017 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
1842 // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. 2018 // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
1843 const std::string sampler = GetSampler(instr.sampler); 2019 const std::string sampler =
2020 GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false);
1844 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; 2021 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
1845 const std::string texture = "textureGather(" + sampler + ", coords, " + 2022 const std::string texture = "textureGather(" + sampler + ", coords, " +
1846 std::to_string(instr.tld4s.component) + ')'; 2023 std::to_string(instr.tld4s.component) + ')';
1847 WriteTexsInstruction(instr, coord, texture); 2024 WriteTexsInstruction(instr, coord, texture);
1848 break; 2025 break;
1849 } 2026 }
2027 case OpCode::Id::TXQ: {
2028 // TODO: the new commits on the texture refactor, change the way samplers work.
2029 // Sadly, not all texture instructions specify the type of texture their sampler
2030 // uses. This must be fixed at a later instance.
2031 const std::string sampler =
2032 GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false);
2033 switch (instr.txq.query_type) {
2034 case Tegra::Shader::TextureQueryType::Dimension: {
2035 const std::string texture = "textureQueryLevels(" + sampler + ')';
2036 regs.SetRegisterToInteger(instr.gpr0, true, 0, texture, 1, 1);
2037 break;
2038 }
2039 default: {
2040 LOG_CRITICAL(HW_GPU, "Unhandled texture query type: {}",
2041 static_cast<u32>(instr.txq.query_type.Value()));
2042 UNREACHABLE();
2043 }
2044 }
2045 break;
2046 }
2047 case OpCode::Id::TMML: {
2048 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
2049 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2050 const bool is_array = instr.tmml.array != 0;
2051 auto texture_type = instr.tmml.texture_type.Value();
2052 const std::string sampler = GetSampler(instr.sampler, texture_type, is_array);
2053
2054 // TODO: add coordinates for different samplers once other texture types are
2055 // implemented.
2056 std::string coord;
2057 switch (texture_type) {
2058 case Tegra::Shader::TextureType::Texture1D: {
2059 std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2060 coord = "float coords = " + x + ';';
2061 break;
2062 }
2063 case Tegra::Shader::TextureType::Texture2D: {
2064 std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2065 std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2066 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2067 break;
2068 }
2069 default:
2070 LOG_CRITICAL(HW_GPU, "Unhandled texture type {}",
2071 static_cast<u32>(texture_type));
2072 UNREACHABLE();
2073
2074 // Fallback to interpreting as a 2D texture for now
2075 std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2076 std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2077 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2078 texture_type = Tegra::Shader::TextureType::Texture2D;
2079 }
2080 // Add an extra scope and declare the texture coords inside to prevent
2081 // overwriting them in case they are used as outputs of the texs instruction.
2082 shader.AddLine('{');
2083 ++shader.scope;
2084 shader.AddLine(coord);
2085 const std::string texture = "textureQueryLod(" + sampler + ", coords)";
2086 const std::string tmp = "vec2 tmp = " + texture + "*vec2(256.0, 256.0);";
2087 shader.AddLine(tmp);
2088
2089 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1);
2090 regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1);
2091 --shader.scope;
2092 shader.AddLine('}');
2093 break;
2094 }
1850 default: { 2095 default: {
1851 LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName()); 2096 LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName());
1852 UNREACHABLE(); 2097 UNREACHABLE();
@@ -1886,12 +2131,12 @@ private:
1886 // We can't use the constant predicate as destination. 2131 // We can't use the constant predicate as destination.
1887 ASSERT(instr.fsetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); 2132 ASSERT(instr.fsetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
1888 2133
1889 std::string second_pred = 2134 const std::string second_pred =
1890 GetPredicateCondition(instr.fsetp.pred39, instr.fsetp.neg_pred != 0); 2135 GetPredicateCondition(instr.fsetp.pred39, instr.fsetp.neg_pred != 0);
1891 2136
1892 std::string combiner = GetPredicateCombiner(instr.fsetp.op); 2137 const std::string combiner = GetPredicateCombiner(instr.fsetp.op);
1893 2138
1894 std::string predicate = GetPredicateComparison(instr.fsetp.cond, op_a, op_b); 2139 const std::string predicate = GetPredicateComparison(instr.fsetp.cond, op_a, op_b);
1895 // Set the primary predicate to the result of Predicate OP SecondPredicate 2140 // Set the primary predicate to the result of Predicate OP SecondPredicate
1896 SetPredicate(instr.fsetp.pred3, 2141 SetPredicate(instr.fsetp.pred3,
1897 '(' + predicate + ") " + combiner + " (" + second_pred + ')'); 2142 '(' + predicate + ") " + combiner + " (" + second_pred + ')');
@@ -1905,7 +2150,8 @@ private:
1905 break; 2150 break;
1906 } 2151 }
1907 case OpCode::Type::IntegerSetPredicate: { 2152 case OpCode::Type::IntegerSetPredicate: {
1908 std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.isetp.is_signed); 2153 const std::string op_a =
2154 regs.GetRegisterAsInteger(instr.gpr8, 0, instr.isetp.is_signed);
1909 std::string op_b; 2155 std::string op_b;
1910 2156
1911 if (instr.is_b_imm) { 2157 if (instr.is_b_imm) {
@@ -1922,12 +2168,12 @@ private:
1922 // We can't use the constant predicate as destination. 2168 // We can't use the constant predicate as destination.
1923 ASSERT(instr.isetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); 2169 ASSERT(instr.isetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
1924 2170
1925 std::string second_pred = 2171 const std::string second_pred =
1926 GetPredicateCondition(instr.isetp.pred39, instr.isetp.neg_pred != 0); 2172 GetPredicateCondition(instr.isetp.pred39, instr.isetp.neg_pred != 0);
1927 2173
1928 std::string combiner = GetPredicateCombiner(instr.isetp.op); 2174 const std::string combiner = GetPredicateCombiner(instr.isetp.op);
1929 2175
1930 std::string predicate = GetPredicateComparison(instr.isetp.cond, op_a, op_b); 2176 const std::string predicate = GetPredicateComparison(instr.isetp.cond, op_a, op_b);
1931 // Set the primary predicate to the result of Predicate OP SecondPredicate 2177 // Set the primary predicate to the result of Predicate OP SecondPredicate
1932 SetPredicate(instr.isetp.pred3, 2178 SetPredicate(instr.isetp.pred3,
1933 '(' + predicate + ") " + combiner + " (" + second_pred + ')'); 2179 '(' + predicate + ") " + combiner + " (" + second_pred + ')');
@@ -1940,21 +2186,45 @@ private:
1940 } 2186 }
1941 break; 2187 break;
1942 } 2188 }
2189 case OpCode::Type::PredicateSetRegister: {
2190 const std::string op_a =
2191 GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0);
2192 const std::string op_b =
2193 GetPredicateCondition(instr.pset.pred29, instr.pset.neg_pred29 != 0);
2194
2195 const std::string second_pred =
2196 GetPredicateCondition(instr.pset.pred39, instr.pset.neg_pred39 != 0);
2197
2198 const std::string combiner = GetPredicateCombiner(instr.pset.op);
2199
2200 const std::string predicate =
2201 '(' + op_a + ") " + GetPredicateCombiner(instr.pset.cond) + " (" + op_b + ')';
2202 const std::string result = '(' + predicate + ") " + combiner + " (" + second_pred + ')';
2203 if (instr.pset.bf == 0) {
2204 const std::string value = '(' + result + ") ? 0xFFFFFFFF : 0";
2205 regs.SetRegisterToInteger(instr.gpr0, false, 0, value, 1, 1);
2206 } else {
2207 const std::string value = '(' + result + ") ? 1.0 : 0.0";
2208 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1);
2209 }
2210
2211 break;
2212 }
1943 case OpCode::Type::PredicateSetPredicate: { 2213 case OpCode::Type::PredicateSetPredicate: {
1944 std::string op_a = 2214 const std::string op_a =
1945 GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); 2215 GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
1946 std::string op_b = 2216 const std::string op_b =
1947 GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); 2217 GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
1948 2218
1949 // We can't use the constant predicate as destination. 2219 // We can't use the constant predicate as destination.
1950 ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); 2220 ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
1951 2221
1952 std::string second_pred = 2222 const std::string second_pred =
1953 GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); 2223 GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0);
1954 2224
1955 std::string combiner = GetPredicateCombiner(instr.psetp.op); 2225 const std::string combiner = GetPredicateCombiner(instr.psetp.op);
1956 2226
1957 std::string predicate = 2227 const std::string predicate =
1958 '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; 2228 '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')';
1959 2229
1960 // Set the primary predicate to the result of Predicate OP SecondPredicate 2230 // Set the primary predicate to the result of Predicate OP SecondPredicate
@@ -1980,7 +2250,7 @@ private:
1980 std::string op_b = instr.fset.neg_b ? "-" : ""; 2250 std::string op_b = instr.fset.neg_b ? "-" : "";
1981 2251
1982 if (instr.is_b_imm) { 2252 if (instr.is_b_imm) {
1983 std::string imm = GetImmediate19(instr); 2253 const std::string imm = GetImmediate19(instr);
1984 if (instr.fset.neg_imm) 2254 if (instr.fset.neg_imm)
1985 op_b += "(-" + imm + ')'; 2255 op_b += "(-" + imm + ')';
1986 else 2256 else
@@ -2000,13 +2270,14 @@ private:
2000 2270
2001 // The fset instruction sets a register to 1.0 or -1 (depending on the bf bit) if the 2271 // The fset instruction sets a register to 1.0 or -1 (depending on the bf bit) if the
2002 // condition is true, and to 0 otherwise. 2272 // condition is true, and to 0 otherwise.
2003 std::string second_pred = 2273 const std::string second_pred =
2004 GetPredicateCondition(instr.fset.pred39, instr.fset.neg_pred != 0); 2274 GetPredicateCondition(instr.fset.pred39, instr.fset.neg_pred != 0);
2005 2275
2006 std::string combiner = GetPredicateCombiner(instr.fset.op); 2276 const std::string combiner = GetPredicateCombiner(instr.fset.op);
2007 2277
2008 std::string predicate = "((" + GetPredicateComparison(instr.fset.cond, op_a, op_b) + 2278 const std::string predicate = "((" +
2009 ") " + combiner + " (" + second_pred + "))"; 2279 GetPredicateComparison(instr.fset.cond, op_a, op_b) +
2280 ") " + combiner + " (" + second_pred + "))";
2010 2281
2011 if (instr.fset.bf) { 2282 if (instr.fset.bf) {
2012 regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); 2283 regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1);
@@ -2017,7 +2288,7 @@ private:
2017 break; 2288 break;
2018 } 2289 }
2019 case OpCode::Type::IntegerSet: { 2290 case OpCode::Type::IntegerSet: {
2020 std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.iset.is_signed); 2291 const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.iset.is_signed);
2021 2292
2022 std::string op_b; 2293 std::string op_b;
2023 2294
@@ -2034,13 +2305,14 @@ private:
2034 2305
2035 // The iset instruction sets a register to 1.0 or -1 (depending on the bf bit) if the 2306 // The iset instruction sets a register to 1.0 or -1 (depending on the bf bit) if the
2036 // condition is true, and to 0 otherwise. 2307 // condition is true, and to 0 otherwise.
2037 std::string second_pred = 2308 const std::string second_pred =
2038 GetPredicateCondition(instr.iset.pred39, instr.iset.neg_pred != 0); 2309 GetPredicateCondition(instr.iset.pred39, instr.iset.neg_pred != 0);
2039 2310
2040 std::string combiner = GetPredicateCombiner(instr.iset.op); 2311 const std::string combiner = GetPredicateCombiner(instr.iset.op);
2041 2312
2042 std::string predicate = "((" + GetPredicateComparison(instr.iset.cond, op_a, op_b) + 2313 const std::string predicate = "((" +
2043 ") " + combiner + " (" + second_pred + "))"; 2314 GetPredicateComparison(instr.iset.cond, op_a, op_b) +
2315 ") " + combiner + " (" + second_pred + "))";
2044 2316
2045 if (instr.iset.bf) { 2317 if (instr.iset.bf) {
2046 regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); 2318 regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1);
@@ -2190,7 +2462,7 @@ private:
2190 case OpCode::Id::BRA: { 2462 case OpCode::Id::BRA: {
2191 ASSERT_MSG(instr.bra.constant_buffer == 0, 2463 ASSERT_MSG(instr.bra.constant_buffer == 0,
2192 "BRA with constant buffers are not implemented"); 2464 "BRA with constant buffers are not implemented");
2193 u32 target = offset + instr.bra.GetBranchTarget(); 2465 const u32 target = offset + instr.bra.GetBranchTarget();
2194 shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); 2466 shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
2195 break; 2467 break;
2196 } 2468 }
@@ -2214,7 +2486,7 @@ private:
2214 // has a similar structure to the BRA opcode. 2486 // has a similar structure to the BRA opcode.
2215 ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported"); 2487 ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported");
2216 2488
2217 u32 target = offset + instr.bra.GetBranchTarget(); 2489 const u32 target = offset + instr.bra.GetBranchTarget();
2218 EmitPushToSSYStack(target); 2490 EmitPushToSSYStack(target);
2219 break; 2491 break;
2220 } 2492 }
@@ -2308,10 +2580,10 @@ private:
2308 shader.AddLine("case " + std::to_string(label) + "u: {"); 2580 shader.AddLine("case " + std::to_string(label) + "u: {");
2309 ++shader.scope; 2581 ++shader.scope;
2310 2582
2311 auto next_it = labels.lower_bound(label + 1); 2583 const auto next_it = labels.lower_bound(label + 1);
2312 u32 next_label = next_it == labels.end() ? subroutine.end : *next_it; 2584 const u32 next_label = next_it == labels.end() ? subroutine.end : *next_it;
2313 2585
2314 u32 compile_end = CompileRange(label, next_label); 2586 const u32 compile_end = CompileRange(label, next_label);
2315 if (compile_end > next_label && compile_end != PROGRAM_END) { 2587 if (compile_end > next_label && compile_end != PROGRAM_END) {
2316 // This happens only when there is a label inside a IF/LOOP block 2588 // This happens only when there is a label inside a IF/LOOP block
2317 shader.AddLine(" jmp_to = " + std::to_string(compile_end) + "u; break; }"); 2589 shader.AddLine(" jmp_to = " + std::to_string(compile_end) + "u; break; }");
@@ -2374,7 +2646,8 @@ boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code,
2374 Maxwell3D::Regs::ShaderStage stage, 2646 Maxwell3D::Regs::ShaderStage stage,
2375 const std::string& suffix) { 2647 const std::string& suffix) {
2376 try { 2648 try {
2377 auto subroutines = ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines(); 2649 const auto subroutines =
2650 ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines();
2378 GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix); 2651 GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix);
2379 return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; 2652 return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
2380 } catch (const DecompileFail& exception) { 2653 } catch (const DecompileFail& exception) {
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index e1b1a9d73..b0466c18f 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -88,7 +88,14 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup) {
88 .get_value_or({}); 88 .get_value_or({});
89 out += R"( 89 out += R"(
90in vec4 position; 90in vec4 position;
91layout(location = 0) out vec4 color[8]; 91layout(location = 0) out vec4 FragColor0;
92layout(location = 1) out vec4 FragColor1;
93layout(location = 2) out vec4 FragColor2;
94layout(location = 3) out vec4 FragColor3;
95layout(location = 4) out vec4 FragColor4;
96layout(location = 5) out vec4 FragColor5;
97layout(location = 6) out vec4 FragColor6;
98layout(location = 7) out vec4 FragColor7;
92 99
93layout (std140) uniform fs_config { 100layout (std140) uniform fs_config {
94 vec4 viewport_flip; 101 vec4 viewport_flip;
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index cbb2090ea..a43e2997b 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -9,6 +9,7 @@
9#include <vector> 9#include <vector>
10 10
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/engines/shader_bytecode.h"
12 13
13namespace OpenGL::GLShader { 14namespace OpenGL::GLShader {
14 15
@@ -73,8 +74,9 @@ class SamplerEntry {
73 using Maxwell = Tegra::Engines::Maxwell3D::Regs; 74 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
74 75
75public: 76public:
76 SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index) 77 SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index,
77 : offset(offset), stage(stage), sampler_index(index) {} 78 Tegra::Shader::TextureType type, bool is_array)
79 : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {}
78 80
79 size_t GetOffset() const { 81 size_t GetOffset() const {
80 return offset; 82 return offset;
@@ -89,8 +91,41 @@ public:
89 } 91 }
90 92
91 std::string GetName() const { 93 std::string GetName() const {
92 return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '[' + 94 return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '_' +
93 std::to_string(sampler_index) + ']'; 95 std::to_string(sampler_index);
96 }
97
98 std::string GetTypeString() const {
99 using Tegra::Shader::TextureType;
100 std::string glsl_type;
101
102 switch (type) {
103 case TextureType::Texture1D:
104 glsl_type = "sampler1D";
105 break;
106 case TextureType::Texture2D:
107 glsl_type = "sampler2D";
108 break;
109 case TextureType::Texture3D:
110 glsl_type = "sampler3D";
111 break;
112 case TextureType::TextureCube:
113 glsl_type = "samplerCube";
114 break;
115 default:
116 UNIMPLEMENTED();
117 }
118 if (is_array)
119 glsl_type += "Array";
120 return glsl_type;
121 }
122
123 Tegra::Shader::TextureType GetType() const {
124 return type;
125 }
126
127 bool IsArray() const {
128 return is_array;
94 } 129 }
95 130
96 u32 GetHash() const { 131 u32 GetHash() const {
@@ -105,11 +140,14 @@ private:
105 static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = { 140 static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = {
106 "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs", 141 "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs",
107 }; 142 };
143
108 /// Offset in TSC memory from which to read the sampler object, as specified by the sampling 144 /// Offset in TSC memory from which to read the sampler object, as specified by the sampling
109 /// instruction. 145 /// instruction.
110 size_t offset; 146 size_t offset;
111 Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. 147 Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used.
112 size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. 148 size_t sampler_index; ///< Value used to index into the generated GLSL sampler array.
149 Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc)
150 bool is_array; ///< Whether the texture is being sampled as an array texture or not.
113}; 151};
114 152
115struct ShaderEntries { 153struct ShaderEntries {
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index 5781d9d16..5f3fe067e 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -25,7 +25,7 @@ GLuint LoadShader(const char* source, GLenum type) {
25 default: 25 default:
26 UNREACHABLE(); 26 UNREACHABLE();
27 } 27 }
28 GLuint shader_id = glCreateShader(type); 28 const GLuint shader_id = glCreateShader(type);
29 glShaderSource(shader_id, 1, &source, nullptr); 29 glShaderSource(shader_id, 1, &source, nullptr);
30 LOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type); 30 LOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type);
31 glCompileShader(shader_id); 31 glCompileShader(shader_id);
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 60a4defd1..6f70deb96 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -200,9 +200,9 @@ void OpenGLState::Apply() const {
200 const auto& texture_unit = texture_units[i]; 200 const auto& texture_unit = texture_units[i];
201 const auto& cur_state_texture_unit = cur_state.texture_units[i]; 201 const auto& cur_state_texture_unit = cur_state.texture_units[i];
202 202
203 if (texture_unit.texture_2d != cur_state_texture_unit.texture_2d) { 203 if (texture_unit.texture != cur_state_texture_unit.texture) {
204 glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum()); 204 glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum());
205 glBindTexture(GL_TEXTURE_2D, texture_unit.texture_2d); 205 glBindTexture(texture_unit.target, texture_unit.texture);
206 } 206 }
207 if (texture_unit.sampler != cur_state_texture_unit.sampler) { 207 if (texture_unit.sampler != cur_state_texture_unit.sampler) {
208 glBindSampler(static_cast<GLuint>(i), texture_unit.sampler); 208 glBindSampler(static_cast<GLuint>(i), texture_unit.sampler);
@@ -214,7 +214,7 @@ void OpenGLState::Apply() const {
214 texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) { 214 texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) {
215 std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g, 215 std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g,
216 texture_unit.swizzle.b, texture_unit.swizzle.a}; 216 texture_unit.swizzle.b, texture_unit.swizzle.a};
217 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask.data()); 217 glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
218 } 218 }
219 } 219 }
220 220
@@ -287,7 +287,7 @@ void OpenGLState::Apply() const {
287 287
288OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { 288OpenGLState& OpenGLState::UnbindTexture(GLuint handle) {
289 for (auto& unit : texture_units) { 289 for (auto& unit : texture_units) {
290 if (unit.texture_2d == handle) { 290 if (unit.texture == handle) {
291 unit.Unbind(); 291 unit.Unbind();
292 } 292 }
293 } 293 }
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 46e96a97d..e3e24b9e7 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -94,8 +94,9 @@ public:
94 94
95 // 3 texture units - one for each that is used in PICA fragment shader emulation 95 // 3 texture units - one for each that is used in PICA fragment shader emulation
96 struct TextureUnit { 96 struct TextureUnit {
97 GLuint texture_2d; // GL_TEXTURE_BINDING_2D 97 GLuint texture; // GL_TEXTURE_BINDING_2D
98 GLuint sampler; // GL_SAMPLER_BINDING 98 GLuint sampler; // GL_SAMPLER_BINDING
99 GLenum target;
99 struct { 100 struct {
100 GLint r; // GL_TEXTURE_SWIZZLE_R 101 GLint r; // GL_TEXTURE_SWIZZLE_R
101 GLint g; // GL_TEXTURE_SWIZZLE_G 102 GLint g; // GL_TEXTURE_SWIZZLE_G
@@ -104,7 +105,7 @@ public:
104 } swizzle; 105 } swizzle;
105 106
106 void Unbind() { 107 void Unbind() {
107 texture_2d = 0; 108 texture = 0;
108 swizzle.r = GL_RED; 109 swizzle.r = GL_RED;
109 swizzle.g = GL_GREEN; 110 swizzle.g = GL_GREEN;
110 swizzle.b = GL_BLUE; 111 swizzle.b = GL_BLUE;
@@ -114,6 +115,7 @@ public:
114 void Reset() { 115 void Reset() {
115 Unbind(); 116 Unbind();
116 sampler = 0; 117 sampler = 0;
118 target = GL_TEXTURE_2D;
117 } 119 }
118 }; 120 };
119 std::array<TextureUnit, 32> texture_units; 121 std::array<TextureUnit, 32> texture_units;
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
index e565afcee..aadf68f16 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -29,7 +29,7 @@ OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coh
29 if (GLAD_GL_ARB_buffer_storage) { 29 if (GLAD_GL_ARB_buffer_storage) {
30 persistent = true; 30 persistent = true;
31 coherent = prefer_coherent; 31 coherent = prefer_coherent;
32 GLbitfield flags = 32 const GLbitfield flags =
33 GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0); 33 GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0);
34 glBufferStorage(gl_target, allocate_size, nullptr, flags); 34 glBufferStorage(gl_target, allocate_size, nullptr, flags);
35 mapped_ptr = static_cast<u8*>(glMapBufferRange( 35 mapped_ptr = static_cast<u8*>(glMapBufferRange(
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 411a73d50..96d916b07 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -177,7 +177,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
177 Memory::GetPointer(framebuffer_addr), 177 Memory::GetPointer(framebuffer_addr),
178 gl_framebuffer_data.data(), true); 178 gl_framebuffer_data.data(), true);
179 179
180 state.texture_units[0].texture_2d = screen_info.texture.resource.handle; 180 state.texture_units[0].texture = screen_info.texture.resource.handle;
181 state.Apply(); 181 state.Apply();
182 182
183 glActiveTexture(GL_TEXTURE0); 183 glActiveTexture(GL_TEXTURE0);
@@ -194,7 +194,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
194 194
195 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 195 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
196 196
197 state.texture_units[0].texture_2d = 0; 197 state.texture_units[0].texture = 0;
198 state.Apply(); 198 state.Apply();
199 } 199 }
200} 200}
@@ -205,7 +205,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
205 */ 205 */
206void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, 206void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
207 const TextureInfo& texture) { 207 const TextureInfo& texture) {
208 state.texture_units[0].texture_2d = texture.resource.handle; 208 state.texture_units[0].texture = texture.resource.handle;
209 state.Apply(); 209 state.Apply();
210 210
211 glActiveTexture(GL_TEXTURE0); 211 glActiveTexture(GL_TEXTURE0);
@@ -214,7 +214,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
214 // Update existing texture 214 // Update existing texture
215 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data); 215 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data);
216 216
217 state.texture_units[0].texture_2d = 0; 217 state.texture_units[0].texture = 0;
218 state.Apply(); 218 state.Apply();
219} 219}
220 220
@@ -260,7 +260,7 @@ void RendererOpenGL::InitOpenGLObjects() {
260 // Allocation of storage is deferred until the first frame, when we 260 // Allocation of storage is deferred until the first frame, when we
261 // know the framebuffer size. 261 // know the framebuffer size.
262 262
263 state.texture_units[0].texture_2d = screen_info.texture.resource.handle; 263 state.texture_units[0].texture = screen_info.texture.resource.handle;
264 state.Apply(); 264 state.Apply();
265 265
266 glActiveTexture(GL_TEXTURE0); 266 glActiveTexture(GL_TEXTURE0);
@@ -272,7 +272,7 @@ void RendererOpenGL::InitOpenGLObjects() {
272 272
273 screen_info.display_texture = screen_info.texture.resource.handle; 273 screen_info.display_texture = screen_info.texture.resource.handle;
274 274
275 state.texture_units[0].texture_2d = 0; 275 state.texture_units[0].texture = 0;
276 state.Apply(); 276 state.Apply();
277 277
278 // Clear screen to black 278 // Clear screen to black
@@ -305,14 +305,14 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
305 UNREACHABLE(); 305 UNREACHABLE();
306 } 306 }
307 307
308 state.texture_units[0].texture_2d = texture.resource.handle; 308 state.texture_units[0].texture = texture.resource.handle;
309 state.Apply(); 309 state.Apply();
310 310
311 glActiveTexture(GL_TEXTURE0); 311 glActiveTexture(GL_TEXTURE0);
312 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, 312 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
313 texture.gl_format, texture.gl_type, nullptr); 313 texture.gl_format, texture.gl_type, nullptr);
314 314
315 state.texture_units[0].texture_2d = 0; 315 state.texture_units[0].texture = 0;
316 state.Apply(); 316 state.Apply();
317} 317}
318 318
@@ -354,14 +354,14 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
354 ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v), 354 ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v),
355 }}; 355 }};
356 356
357 state.texture_units[0].texture_2d = screen_info.display_texture; 357 state.texture_units[0].texture = screen_info.display_texture;
358 state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; 358 state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
359 state.Apply(); 359 state.Apply();
360 360
361 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); 361 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
362 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 362 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
363 363
364 state.texture_units[0].texture_2d = 0; 364 state.texture_units[0].texture = 0;
365 state.Apply(); 365 state.Apply();
366} 366}
367 367
@@ -369,6 +369,12 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
369 * Draws the emulated screens to the emulator window. 369 * Draws the emulated screens to the emulator window.
370 */ 370 */
371void RendererOpenGL::DrawScreen() { 371void RendererOpenGL::DrawScreen() {
372 if (renderer_settings.set_background_color) {
373 // Update background color before drawing
374 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
375 0.0f);
376 }
377
372 const auto& layout = render_window.GetFramebufferLayout(); 378 const auto& layout = render_window.GetFramebufferLayout();
373 const auto& screen = layout.screen; 379 const auto& screen = layout.screen;
374 380
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index c6bd2f4b9..c2fb824b2 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -170,8 +170,12 @@ struct TICEntry {
170 BitField<0, 16, u32> width_minus_1; 170 BitField<0, 16, u32> width_minus_1;
171 BitField<23, 4, TextureType> texture_type; 171 BitField<23, 4, TextureType> texture_type;
172 }; 172 };
173 u16 height_minus_1; 173 union {
174 INSERT_PADDING_BYTES(10); 174 BitField<0, 16, u32> height_minus_1;
175 BitField<16, 15, u32> depth_minus_1;
176 };
177
178 INSERT_PADDING_BYTES(8);
175 179
176 GPUVAddr Address() const { 180 GPUVAddr Address() const {
177 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low); 181 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low);
@@ -192,6 +196,10 @@ struct TICEntry {
192 return height_minus_1 + 1; 196 return height_minus_1 + 1;
193 } 197 }
194 198
199 u32 Depth() const {
200 return depth_minus_1 + 1;
201 }
202
195 u32 BlockHeight() const { 203 u32 BlockHeight() const {
196 ASSERT(header_version == TICHeaderVersion::BlockLinear || 204 ASSERT(header_version == TICHeaderVersion::BlockLinear ||
197 header_version == TICHeaderVersion::BlockLinearColorKey); 205 header_version == TICHeaderVersion::BlockLinearColorKey);
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index a2b6e984e..f48b69809 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -9,6 +9,8 @@ add_executable(yuzu
9 about_dialog.h 9 about_dialog.h
10 bootmanager.cpp 10 bootmanager.cpp
11 bootmanager.h 11 bootmanager.h
12 compatibility_list.cpp
13 compatibility_list.h
12 configuration/config.cpp 14 configuration/config.cpp
13 configuration/config.h 15 configuration/config.h
14 configuration/configure_audio.cpp 16 configuration/configure_audio.cpp
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 4a60f450a..4e4c108ab 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -112,6 +112,7 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
112 setWindowTitle(QString::fromStdString(window_title)); 112 setWindowTitle(QString::fromStdString(window_title));
113 113
114 InputCommon::Init(); 114 InputCommon::Init();
115 InputCommon::StartJoystickEventHandler();
115} 116}
116 117
117GRenderWindow::~GRenderWindow() { 118GRenderWindow::~GRenderWindow() {
diff --git a/src/yuzu/compatibility_list.cpp b/src/yuzu/compatibility_list.cpp
new file mode 100644
index 000000000..2d2cfd03c
--- /dev/null
+++ b/src/yuzu/compatibility_list.cpp
@@ -0,0 +1,18 @@
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
7#include <fmt/format.h>
8
9#include "yuzu/compatibility_list.h"
10
11CompatibilityList::const_iterator FindMatchingCompatibilityEntry(
12 const CompatibilityList& compatibility_list, u64 program_id) {
13 return std::find_if(compatibility_list.begin(), compatibility_list.end(),
14 [program_id](const auto& element) {
15 std::string pid = fmt::format("{:016X}", program_id);
16 return element.first == pid;
17 });
18}
diff --git a/src/yuzu/compatibility_list.h b/src/yuzu/compatibility_list.h
new file mode 100644
index 000000000..bc0175bd3
--- /dev/null
+++ b/src/yuzu/compatibility_list.h
@@ -0,0 +1,17 @@
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 <string>
8#include <unordered_map>
9
10#include <QString>
11
12#include "common/common_types.h"
13
14using CompatibilityList = std::unordered_map<std::string, std::pair<QString, QString>>;
15
16CompatibilityList::const_iterator FindMatchingCompatibilityEntry(
17 const CompatibilityList& compatibility_list, u64 program_id);
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index d8caee1e8..9292d9a42 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -20,7 +20,6 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
20 this->setConfiguration(); 20 this->setConfiguration();
21 21
22 ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 22 ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
23 ui->use_multi_core->setEnabled(!Core::System::GetInstance().IsPoweredOn());
24 ui->use_docked_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 23 ui->use_docked_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn());
25} 24}
26 25
@@ -31,7 +30,6 @@ void ConfigureGeneral::setConfiguration() {
31 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); 30 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
32 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); 31 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
33 ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit); 32 ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit);
34 ui->use_multi_core->setChecked(Settings::values.use_multi_core);
35 ui->use_docked_mode->setChecked(Settings::values.use_docked_mode); 33 ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
36} 34}
37 35
@@ -46,6 +44,5 @@ void ConfigureGeneral::applyConfiguration() {
46 ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); 44 ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
47 45
48 Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked(); 46 Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
49 Settings::values.use_multi_core = ui->use_multi_core->isChecked();
50 Settings::values.use_docked_mode = ui->use_docked_mode->isChecked(); 47 Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
51} 48}
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index 233adbe27..1775c4d40 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -58,13 +58,6 @@
58 </property> 58 </property>
59 </widget> 59 </widget>
60 </item> 60 </item>
61 <item>
62 <widget class="QCheckBox" name="use_multi_core">
63 <property name="text">
64 <string>Enable multi-core</string>
65 </property>
66 </widget>
67 </item>
68 </layout> 61 </layout>
69 </item> 62 </item>
70 </layout> 63 </layout>
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index ee1287028..839d58f59 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QColorDialog>
5#include "core/core.h" 6#include "core/core.h"
6#include "core/settings.h" 7#include "core/settings.h"
7#include "ui_configure_graphics.h" 8#include "ui_configure_graphics.h"
@@ -16,6 +17,14 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
16 ui->frame_limit->setEnabled(Settings::values.use_frame_limit); 17 ui->frame_limit->setEnabled(Settings::values.use_frame_limit);
17 connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit, 18 connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit,
18 &QSpinBox::setEnabled); 19 &QSpinBox::setEnabled);
20 connect(ui->bg_button, &QPushButton::clicked, this, [this] {
21 const QColor new_bg_color = QColorDialog::getColor(bg_color);
22 if (!new_bg_color.isValid())
23 return;
24 bg_color = new_bg_color;
25 ui->bg_button->setStyleSheet(
26 QString("QPushButton { background-color: %1 }").arg(bg_color.name()));
27 });
19} 28}
20 29
21ConfigureGraphics::~ConfigureGraphics() = default; 30ConfigureGraphics::~ConfigureGraphics() = default;
@@ -65,6 +74,10 @@ void ConfigureGraphics::setConfiguration() {
65 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); 74 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit);
66 ui->frame_limit->setValue(Settings::values.frame_limit); 75 ui->frame_limit->setValue(Settings::values.frame_limit);
67 ui->use_accurate_framebuffers->setChecked(Settings::values.use_accurate_framebuffers); 76 ui->use_accurate_framebuffers->setChecked(Settings::values.use_accurate_framebuffers);
77 bg_color = QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
78 Settings::values.bg_blue);
79 ui->bg_button->setStyleSheet(
80 QString("QPushButton { background-color: %1 }").arg(bg_color.name()));
68} 81}
69 82
70void ConfigureGraphics::applyConfiguration() { 83void ConfigureGraphics::applyConfiguration() {
@@ -73,4 +86,7 @@ void ConfigureGraphics::applyConfiguration() {
73 Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); 86 Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked();
74 Settings::values.frame_limit = ui->frame_limit->value(); 87 Settings::values.frame_limit = ui->frame_limit->value();
75 Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked(); 88 Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked();
89 Settings::values.bg_red = static_cast<float>(bg_color.redF());
90 Settings::values.bg_green = static_cast<float>(bg_color.greenF());
91 Settings::values.bg_blue = static_cast<float>(bg_color.blueF());
76} 92}
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 5497a55f7..9bda26fd6 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -25,4 +25,5 @@ private:
25 25
26private: 26private:
27 std::unique_ptr<Ui::ConfigureGraphics> ui; 27 std::unique_ptr<Ui::ConfigureGraphics> ui;
28 QColor bg_color;
28}; 29};
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 3bc18c26e..8fc00af1b 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -96,6 +96,27 @@
96 </item> 96 </item>
97 </layout> 97 </layout>
98 </item> 98 </item>
99 <item>
100 <layout class="QHBoxLayout" name="horizontalLayout_6">
101 <item>
102 <widget class="QLabel" name="bg_label">
103 <property name="text">
104 <string>Background Color:</string>
105 </property>
106 </widget>
107 </item>
108 <item>
109 <widget class="QPushButton" name="bg_button">
110 <property name="maximumSize">
111 <size>
112 <width>40</width>
113 <height>16777215</height>
114 </size>
115 </property>
116 </widget>
117 </item>
118 </layout>
119 </item>
99 </layout> 120 </layout>
100 </widget> 121 </widget>
101 </item> 122 </item>
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 5e7badedf..d29abb74b 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -1,4 +1,4 @@
1// Copyright 2016 Citra Emulator Project 1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
@@ -53,19 +53,18 @@ static QString ButtonToText(const Common::ParamPackage& param) {
53 } else if (param.Get("engine", "") == "keyboard") { 53 } else if (param.Get("engine", "") == "keyboard") {
54 return getKeyName(param.Get("code", 0)); 54 return getKeyName(param.Get("code", 0));
55 } else if (param.Get("engine", "") == "sdl") { 55 } else if (param.Get("engine", "") == "sdl") {
56 QString text = QString(QObject::tr("Joystick %1")).arg(param.Get("joystick", "").c_str());
57 if (param.Has("hat")) { 56 if (param.Has("hat")) {
58 text += QString(QObject::tr(" Hat %1 %2")) 57 return QString(QObject::tr("Hat %1 %2"))
59 .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str()); 58 .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
60 } 59 }
61 if (param.Has("axis")) { 60 if (param.Has("axis")) {
62 text += QString(QObject::tr(" Axis %1%2")) 61 return QString(QObject::tr("Axis %1%2"))
63 .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str()); 62 .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
64 } 63 }
65 if (param.Has("button")) { 64 if (param.Has("button")) {
66 text += QString(QObject::tr(" Button %1")).arg(param.Get("button", "").c_str()); 65 return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str());
67 } 66 }
68 return text; 67 return QString();
69 } else { 68 } else {
70 return QObject::tr("[unknown]"); 69 return QObject::tr("[unknown]");
71 } 70 }
@@ -81,13 +80,12 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string
81 return QString(QObject::tr("[unused]")); 80 return QString(QObject::tr("[unused]"));
82 } 81 }
83 82
84 QString text = QString(QObject::tr("Joystick %1")).arg(param.Get("joystick", "").c_str());
85 if (dir == "left" || dir == "right") { 83 if (dir == "left" || dir == "right") {
86 text += QString(QObject::tr(" Axis %1")).arg(param.Get("axis_x", "").c_str()); 84 return QString(QObject::tr("Axis %1")).arg(param.Get("axis_x", "").c_str());
87 } else if (dir == "up" || dir == "down") { 85 } else if (dir == "up" || dir == "down") {
88 text += QString(QObject::tr(" Axis %1")).arg(param.Get("axis_y", "").c_str()); 86 return QString(QObject::tr("Axis %1")).arg(param.Get("axis_y", "").c_str());
89 } 87 }
90 return text; 88 return QString();
91 } else { 89 } else {
92 return QObject::tr("[unknown]"); 90 return QObject::tr("[unknown]");
93 } 91 }
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 86532e4a9..3b3b551bb 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -19,6 +19,7 @@
19#include "common/file_util.h" 19#include "common/file_util.h"
20#include "common/logging/log.h" 20#include "common/logging/log.h"
21#include "core/file_sys/patch_manager.h" 21#include "core/file_sys/patch_manager.h"
22#include "yuzu/compatibility_list.h"
22#include "yuzu/game_list.h" 23#include "yuzu/game_list.h"
23#include "yuzu/game_list_p.h" 24#include "yuzu/game_list_p.h"
24#include "yuzu/game_list_worker.h" 25#include "yuzu/game_list_worker.h"
@@ -365,7 +366,7 @@ void GameList::LoadCompatibilityList() {
365 QJsonDocument json = QJsonDocument::fromJson(string_content.toUtf8()); 366 QJsonDocument json = QJsonDocument::fromJson(string_content.toUtf8());
366 QJsonArray arr = json.array(); 367 QJsonArray arr = json.array();
367 368
368 for (const QJsonValue& value : arr) { 369 for (const QJsonValueRef& value : arr) {
369 QJsonObject game = value.toObject(); 370 QJsonObject game = value.toObject();
370 371
371 if (game.contains("compatibility") && game["compatibility"].isDouble()) { 372 if (game.contains("compatibility") && game["compatibility"].isDouble()) {
@@ -373,9 +374,9 @@ void GameList::LoadCompatibilityList() {
373 QString directory = game["directory"].toString(); 374 QString directory = game["directory"].toString();
374 QJsonArray ids = game["releases"].toArray(); 375 QJsonArray ids = game["releases"].toArray();
375 376
376 for (const QJsonValue& value : ids) { 377 for (const QJsonValueRef& id_ref : ids) {
377 QJsonObject object = value.toObject(); 378 QJsonObject id_object = id_ref.toObject();
378 QString id = object["id"].toString(); 379 QString id = id_object["id"].toString();
379 compatibility_list.emplace( 380 compatibility_list.emplace(
380 id.toUpper().toStdString(), 381 id.toUpper().toStdString(),
381 std::make_pair(QString::number(compatibility), directory)); 382 std::make_pair(QString::number(compatibility), directory));
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 3fcb298ed..2713e7b54 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -4,8 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <unordered_map>
8
9#include <QFileSystemWatcher> 7#include <QFileSystemWatcher>
10#include <QHBoxLayout> 8#include <QHBoxLayout>
11#include <QLabel> 9#include <QLabel>
@@ -21,6 +19,7 @@
21#include <QWidget> 19#include <QWidget>
22 20
23#include "common/common_types.h" 21#include "common/common_types.h"
22#include "yuzu/compatibility_list.h"
24 23
25class GameListWorker; 24class GameListWorker;
26class GMainWindow; 25class GMainWindow;
@@ -90,9 +89,8 @@ signals:
90 void GameChosen(QString game_path); 89 void GameChosen(QString game_path);
91 void ShouldCancelWorker(); 90 void ShouldCancelWorker();
92 void OpenFolderRequested(u64 program_id, GameListOpenTarget target); 91 void OpenFolderRequested(u64 program_id, GameListOpenTarget target);
93 void NavigateToGamedbEntryRequested( 92 void NavigateToGamedbEntryRequested(u64 program_id,
94 u64 program_id, 93 const CompatibilityList& compatibility_list);
95 std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list);
96 94
97private slots: 95private slots:
98 void onTextChanged(const QString& newText); 96 void onTextChanged(const QString& newText);
@@ -114,7 +112,7 @@ private:
114 QStandardItemModel* item_model = nullptr; 112 QStandardItemModel* item_model = nullptr;
115 GameListWorker* current_worker = nullptr; 113 GameListWorker* current_worker = nullptr;
116 QFileSystemWatcher* watcher = nullptr; 114 QFileSystemWatcher* watcher = nullptr;
117 std::unordered_map<std::string, std::pair<QString, QString>> compatibility_list; 115 CompatibilityList compatibility_list;
118}; 116};
119 117
120Q_DECLARE_METATYPE(GameListOpenTarget); 118Q_DECLARE_METATYPE(GameListOpenTarget);
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index 2720bf143..f22e422e5 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -176,14 +176,3 @@ public:
176 return data(SizeRole).toULongLong() < other.data(SizeRole).toULongLong(); 176 return data(SizeRole).toULongLong() < other.data(SizeRole).toULongLong();
177 } 177 }
178}; 178};
179
180inline auto FindMatchingCompatibilityEntry(
181 const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list,
182 u64 program_id) {
183 return std::find_if(
184 compatibility_list.begin(), compatibility_list.end(),
185 [program_id](const std::pair<std::string, std::pair<QString, QString>>& element) {
186 std::string pid = fmt::format("{:016X}", program_id);
187 return element.first == pid;
188 });
189}
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 9f26935d6..e228d61bd 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -20,6 +20,7 @@
20#include "core/file_sys/registered_cache.h" 20#include "core/file_sys/registered_cache.h"
21#include "core/hle/service/filesystem/filesystem.h" 21#include "core/hle/service/filesystem/filesystem.h"
22#include "core/loader/loader.h" 22#include "core/loader/loader.h"
23#include "yuzu/compatibility_list.h"
23#include "yuzu/game_list.h" 24#include "yuzu/game_list.h"
24#include "yuzu/game_list_p.h" 25#include "yuzu/game_list_p.h"
25#include "yuzu/game_list_worker.h" 26#include "yuzu/game_list_worker.h"
@@ -75,9 +76,8 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager, bool
75} 76}
76} // Anonymous namespace 77} // Anonymous namespace
77 78
78GameListWorker::GameListWorker( 79GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan,
79 FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan, 80 const CompatibilityList& compatibility_list)
80 const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list)
81 : vfs(std::move(vfs)), dir_path(std::move(dir_path)), deep_scan(deep_scan), 81 : vfs(std::move(vfs)), dir_path(std::move(dir_path)), deep_scan(deep_scan),
82 compatibility_list(compatibility_list) {} 82 compatibility_list(compatibility_list) {}
83 83
diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h
index 42c93fc31..09d20c42f 100644
--- a/src/yuzu/game_list_worker.h
+++ b/src/yuzu/game_list_worker.h
@@ -16,6 +16,7 @@
16#include <QString> 16#include <QString>
17 17
18#include "common/common_types.h" 18#include "common/common_types.h"
19#include "yuzu/compatibility_list.h"
19 20
20class QStandardItem; 21class QStandardItem;
21 22
@@ -32,9 +33,8 @@ class GameListWorker : public QObject, public QRunnable {
32 Q_OBJECT 33 Q_OBJECT
33 34
34public: 35public:
35 GameListWorker( 36 GameListWorker(std::shared_ptr<FileSys::VfsFilesystem> vfs, QString dir_path, bool deep_scan,
36 std::shared_ptr<FileSys::VfsFilesystem> vfs, QString dir_path, bool deep_scan, 37 const CompatibilityList& compatibility_list);
37 const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list);
38 ~GameListWorker() override; 38 ~GameListWorker() override;
39 39
40 /// Starts the processing of directory tree information. 40 /// Starts the processing of directory tree information.
@@ -67,6 +67,6 @@ private:
67 QStringList watch_list; 67 QStringList watch_list;
68 QString dir_path; 68 QString dir_path;
69 bool deep_scan; 69 bool deep_scan;
70 const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list; 70 const CompatibilityList& compatibility_list;
71 std::atomic_bool stop_processing; 71 std::atomic_bool stop_processing;
72}; 72};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 2cd282a51..05a4a55e8 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -47,6 +47,7 @@
47#include "video_core/debug_utils/debug_utils.h" 47#include "video_core/debug_utils/debug_utils.h"
48#include "yuzu/about_dialog.h" 48#include "yuzu/about_dialog.h"
49#include "yuzu/bootmanager.h" 49#include "yuzu/bootmanager.h"
50#include "yuzu/compatibility_list.h"
50#include "yuzu/configuration/config.h" 51#include "yuzu/configuration/config.h"
51#include "yuzu/configuration/configure_dialog.h" 52#include "yuzu/configuration/configure_dialog.h"
52#include "yuzu/debugger/console.h" 53#include "yuzu/debugger/console.h"
@@ -446,6 +447,8 @@ QStringList GMainWindow::GetUnsupportedGLExtensions() {
446 unsupported_ext.append("ARB_texture_mirror_clamp_to_edge"); 447 unsupported_ext.append("ARB_texture_mirror_clamp_to_edge");
447 if (!GLAD_GL_ARB_base_instance) 448 if (!GLAD_GL_ARB_base_instance)
448 unsupported_ext.append("ARB_base_instance"); 449 unsupported_ext.append("ARB_base_instance");
450 if (!GLAD_GL_ARB_texture_storage)
451 unsupported_ext.append("ARB_texture_storage");
449 452
450 // Extensions required to support some texture formats. 453 // Extensions required to support some texture formats.
451 if (!GLAD_GL_EXT_texture_compression_s3tc) 454 if (!GLAD_GL_EXT_texture_compression_s3tc)
@@ -608,7 +611,7 @@ void GMainWindow::BootGame(const QString& filename) {
608 } 611 }
609 612
610 setWindowTitle(QString("yuzu %1| %4 | %2-%3") 613 setWindowTitle(QString("yuzu %1| %4 | %2-%3")
611 .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc, 614 .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc,
612 QString::fromStdString(title_name))); 615 QString::fromStdString(title_name)));
613 616
614 render_window->show(); 617 render_window->show();
@@ -643,7 +646,7 @@ void GMainWindow::ShutdownGame() {
643 game_list->show(); 646 game_list->show();
644 game_list->setFilterFocus(); 647 game_list->setFilterFocus();
645 setWindowTitle(QString("yuzu %1| %2-%3") 648 setWindowTitle(QString("yuzu %1| %2-%3")
646 .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); 649 .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc));
647 650
648 // Disable status bar updates 651 // Disable status bar updates
649 status_bar_update_timer.stop(); 652 status_bar_update_timer.stop();
@@ -725,14 +728,11 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
725 QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); 728 QDesktopServices::openUrl(QUrl::fromLocalFile(qpath));
726} 729}
727 730
728void GMainWindow::OnGameListNavigateToGamedbEntry( 731void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id,
729 u64 program_id, 732 const CompatibilityList& compatibility_list) {
730 std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list) { 733 const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
731
732 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
733 734
734 QString directory; 735 QString directory;
735
736 if (it != compatibility_list.end()) 736 if (it != compatibility_list.end())
737 directory = it->second.second; 737 directory = it->second.second;
738 738
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 089ea2445..552e3e61c 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -13,6 +13,7 @@
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "ui_main.h" 15#include "ui_main.h"
16#include "yuzu/compatibility_list.h"
16#include "yuzu/hotkeys.h" 17#include "yuzu/hotkeys.h"
17 18
18class Config; 19class Config;
@@ -137,9 +138,8 @@ private slots:
137 /// Called whenever a user selects a game in the game list widget. 138 /// Called whenever a user selects a game in the game list widget.
138 void OnGameListLoadFile(QString game_path); 139 void OnGameListLoadFile(QString game_path);
139 void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); 140 void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target);
140 void OnGameListNavigateToGamedbEntry( 141 void OnGameListNavigateToGamedbEntry(u64 program_id,
141 u64 program_id, 142 const CompatibilityList& compatibility_list);
142 std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list);
143 void OnMenuLoadFile(); 143 void OnMenuLoadFile();
144 void OnMenuLoadFolder(); 144 void OnMenuLoadFolder();
145 void OnMenuInstallToNAND(); 145 void OnMenuInstallToNAND();
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 2f7916256..d213929bd 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -16,6 +16,7 @@
16#include "input_common/keyboard.h" 16#include "input_common/keyboard.h"
17#include "input_common/main.h" 17#include "input_common/main.h"
18#include "input_common/motion_emu.h" 18#include "input_common/motion_emu.h"
19#include "input_common/sdl/sdl.h"
19#include "yuzu_cmd/emu_window/emu_window_sdl2.h" 20#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
20 21
21void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { 22void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
@@ -93,6 +94,8 @@ bool EmuWindow_SDL2::SupportsRequiredGLExtensions() {
93 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); 94 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge");
94 if (!GLAD_GL_ARB_base_instance) 95 if (!GLAD_GL_ARB_base_instance)
95 unsupported_ext.push_back("ARB_base_instance"); 96 unsupported_ext.push_back("ARB_base_instance");
97 if (!GLAD_GL_ARB_texture_storage)
98 unsupported_ext.push_back("ARB_texture_storage");
96 99
97 // Extensions required to support some texture formats. 100 // Extensions required to support some texture formats.
98 if (!GLAD_GL_EXT_texture_compression_s3tc) 101 if (!GLAD_GL_EXT_texture_compression_s3tc)
@@ -116,7 +119,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
116 SDL_SetMainReady(); 119 SDL_SetMainReady();
117 120
118 // Initialize the window 121 // Initialize the window
119 if (SDL_Init(SDL_INIT_VIDEO) < 0) { 122 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
120 LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); 123 LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting...");
121 exit(1); 124 exit(1);
122 } 125 }
@@ -176,6 +179,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
176} 179}
177 180
178EmuWindow_SDL2::~EmuWindow_SDL2() { 181EmuWindow_SDL2::~EmuWindow_SDL2() {
182 InputCommon::SDL::CloseSDLJoysticks();
179 SDL_GL_DeleteContext(gl_context); 183 SDL_GL_DeleteContext(gl_context);
180 SDL_Quit(); 184 SDL_Quit();
181 185
@@ -220,6 +224,9 @@ void EmuWindow_SDL2::PollEvents() {
220 case SDL_QUIT: 224 case SDL_QUIT:
221 is_open = false; 225 is_open = false;
222 break; 226 break;
227 default:
228 InputCommon::SDL::HandleGameControllerEvent(event);
229 break;
223 } 230 }
224 } 231 }
225} 232}
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 173ac0e0f..b1c364fbb 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -82,6 +82,9 @@ int main(int argc, char** argv) {
82 int option_index = 0; 82 int option_index = 0;
83 bool use_gdbstub = Settings::values.use_gdbstub; 83 bool use_gdbstub = Settings::values.use_gdbstub;
84 u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port); 84 u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port);
85
86 InitializeLogging();
87
85 char* endarg; 88 char* endarg;
86#ifdef _WIN32 89#ifdef _WIN32
87 int argc_w; 90 int argc_w;
@@ -144,8 +147,6 @@ int main(int argc, char** argv) {
144 LocalFree(argv_w); 147 LocalFree(argv_w);
145#endif 148#endif
146 149
147 InitializeLogging();
148
149 MicroProfileOnThreadCreate("EmuThread"); 150 MicroProfileOnThreadCreate("EmuThread");
150 SCOPE_EXIT({ MicroProfileShutdown(); }); 151 SCOPE_EXIT({ MicroProfileShutdown(); });
151 152