Compare commits

...

47 Commits

Author SHA1 Message Date
b52f26a094 Android 229 2024-02-05 01:00:43 +00:00
e957bc2b4c Merge yuzu-emu#12915 2024-02-05 01:00:43 +00:00
363c96bdc3 Merge yuzu-emu#12905 2024-02-05 01:00:43 +00:00
514c3a75e1 Merge yuzu-emu#12903 2024-02-05 01:00:43 +00:00
bef9ee5000 Merge yuzu-emu#12873 2024-02-05 01:00:43 +00:00
78ce7f00f9 Merge yuzu-emu#12756 2024-02-05 01:00:43 +00:00
9b9634454a Merge yuzu-emu#12749 2024-02-05 01:00:43 +00:00
a5cdf0aed1 Merge yuzu-emu#12461 2024-02-05 01:00:42 +00:00
4cccbe7989 Merge pull request #12892 from liamwhite/serialization-stuff
cmif_serialization: enforce const for references
2024-02-04 09:48:33 -05:00
5da55cbac9 Merge pull request #12901 from Kelebek1/timezone_firmware_fix
Fix firmware timezone boot load check.
2024-02-03 11:10:30 -05:00
81cc4df1f9 Merge pull request #12895 from german77/files
service: fs: Skip non user id folders
2024-02-03 11:10:24 -05:00
25f3d358b1 Merge pull request #12877 from german77/npad-fixed
service: hid: Multiple fixes
2024-02-03 11:10:14 -05:00
a3c8bb251d Merge pull request #12852 from Calinou/multiplayer-color-player-counts
Color player counts in the multiplayer public lobby list
2024-02-03 11:10:00 -05:00
327533be1f Merge pull request #12851 from Calinou/multiplayer-persist-filters
Persist filters in multiplayer public lobby list
2024-02-03 11:09:51 -05:00
61ea2115c7 Merge pull request #12850 from Calinou/multiplayer-add-hotkeys
Add hotkeys for multiplayer actions
2024-02-03 11:09:41 -05:00
108a72ea8a Fix firmware timezone boot load check. 2024-02-03 15:21:10 +00:00
fb3ef957bb service: fs: Skip non user id folders 2024-02-02 13:25:38 -06:00
78f72b3bf5 cmif_serialization: enforce const for references 2024-02-02 09:32:10 -05:00
6baf965777 Merge pull request #12857 from liamwhite/const
service: use const references for input raw data
2024-02-02 15:10:46 +01:00
3f86b339f3 Merge pull request #12845 from liamwhite/notif
notif: rewrite for new IPC
2024-02-02 15:09:57 +01:00
32d38a5df6 Merge pull request #12887 from abouvier/cmake-vulkan-headers
cmake: use vulkan-headers config file
2024-02-02 09:09:02 -05:00
3ac46aeced Merge pull request #12885 from Moonlacer/eclipse-fix
structured_control_flow: Add Samsung Proprietary Driver ID to Reorder Pass
2024-02-02 09:08:54 -05:00
58cf2ee1f9 Merge pull request #12761 from liamwhite/mp-composite
video_core: rewrite presentation for layer composition
2024-02-02 15:08:06 +01:00
c74b5f9ee6 cmake: use vulkan-headers config file 2024-02-02 04:38:56 +01:00
11a8ef6640 Clang Fix 2024-02-01 18:15:21 -06:00
b51b47e707 Add Samsung Proprietary Driver ID to Reorder Pass
For RDNA-based Samsung Xclipse GPUs
2024-02-01 17:53:26 -06:00
35e3c68028 service: use const references for input raw data 2024-02-01 12:57:54 -05:00
818721d12d service: hid: Multiple fixes 2024-02-01 10:37:44 -06:00
2c421a7046 hardware_composer: implement speed limit extensions 2024-01-31 11:27:21 -05:00
a595e9e8a7 nvnflinger/gpu: implement layer stack composition 2024-01-31 11:27:21 -05:00
10cf058518 renderer_opengl: implement layer stack composition 2024-01-31 11:27:21 -05:00
9bdf09bd76 renderer_vulkan: implement layer stack composition 2024-01-31 11:27:21 -05:00
d4de04584f renderer_opengl: split up blit screen resources into antialias and window adapt passes 2024-01-31 11:27:21 -05:00
dd2918efd8 renderer_opengl: move out ownership of FSR resources 2024-01-31 11:27:21 -05:00
2ed9586130 renderer_vulkan: convert FSR to graphics pipeline 2024-01-31 11:27:21 -05:00
b78900e956 renderer_opengl: move out FSR shader source construction 2024-01-31 11:27:20 -05:00
60ee29aac3 renderer_opengl: split out FXAA 2024-01-31 11:27:20 -05:00
b90eff4bc6 renderer_opengl: split out SMAA 2024-01-31 11:27:20 -05:00
0c2e5b64c9 renderer_vulkan: split up blit screen resources into separate antialias and window adapt passes 2024-01-31 11:27:20 -05:00
9568b310be renderer_vulkan: isolate FXAA from blit screen 2024-01-31 11:27:20 -05:00
2b1dd3bef5 renderer_opengl: isolate core presentation code 2024-01-31 11:27:20 -05:00
453091f611 video_core: consistently account for resolution scaling when rendering 2024-01-31 11:27:20 -05:00
80de01a5b4 video_core: simplify accelerated surface fetch and crop handling between APIs 2024-01-31 11:27:20 -05:00
442aad9b27 Persist filters in multiplayer public lobby list
After connecting to a room, the chosen filter text, "Games I Own",
"Hide Empty Rooms" and "Hide Full Rooms" values are persisted
to configuration so they are preserved across restarts.

This makes it easier to rejoin a room if you regularly play the same
game, or after a crash.
2024-01-30 17:40:29 +01:00
8e0f97ac96 Color player counts in the multiplayer public lobby list
- Full lobbies have their player count displayed in red.
- Lobbies with one slot left have their player count displayed in orange.
- Empty lobbies have their player count grayed out.
2024-01-30 17:38:21 +01:00
345d691328 Add hotkeys for multiplayer actions
Default shortcuts were chosen as to be intuitive (use the first letter
of the action, or the second word's first letter) and work on all
types of keyboards. The hotkeys can be used while playing a game too,
as they are application-wide.
2024-01-30 01:32:14 +01:00
41149d061d notif: rewrite for new IPC 2024-01-29 11:56:32 -05:00
227 changed files with 8621 additions and 5269 deletions

View File

@ -307,7 +307,7 @@ find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED)
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
find_package(Vulkan 1.3.274 REQUIRED)
find_package(VulkanHeaders 1.3.274 REQUIRED)
endif()
if (NOT YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)

View File

@ -1,3 +1,18 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [12461](https://github.com/yuzu-emu/yuzu-android//pull/12461) | [`4c08a0e6d`](https://github.com/yuzu-emu/yuzu-android//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
| [12749](https://github.com/yuzu-emu/yuzu-android//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu-android//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12756](https://github.com/yuzu-emu/yuzu-android//pull/12756) | [`cd3de0848`](https://github.com/yuzu-emu/yuzu-android//pull/12756/files) | general: applet multiprocess | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12873](https://github.com/yuzu-emu/yuzu-android//pull/12873) | [`a8488952f`](https://github.com/yuzu-emu/yuzu-android//pull/12873/files) | GPU: Implement channel scheduling. | [FernandoS27](https://github.com/FernandoS27/) | Yes |
| [12903](https://github.com/yuzu-emu/yuzu-android//pull/12903) | [`5be8121af`](https://github.com/yuzu-emu/yuzu-android//pull/12903/files) | shader_recompiler: use only ConstOffset for OpImageFetch | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12905](https://github.com/yuzu-emu/yuzu-android//pull/12905) | [`5eb5c9675`](https://github.com/yuzu-emu/yuzu-android//pull/12905/files) | nvnflinger: release buffers before presentation sleep | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12915](https://github.com/yuzu-emu/yuzu-android//pull/12915) | [`504abbd6e`](https://github.com/yuzu-emu/yuzu-android//pull/12915/files) | dmnt: cheats: Update cheat vm to latest version | [german77](https://github.com/german77/) | Yes |
End of merge log. You can find the original README.md below the break.
-----
<!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later

View File

@ -164,6 +164,7 @@ else()
if (MINGW)
add_definitions(-DMINGW_HAS_SECURE_API)
add_compile_options("-msse4.1")
if (MINGW_STATIC_BUILD)
add_definitions(-DQT_STATICPLUGIN)

View File

@ -9,6 +9,7 @@
#include <string>
#include <vector>
#include <fmt/format.h>
#include "common/assert.h"
#include "common/common_types.h"
namespace Common {
@ -29,6 +30,8 @@ namespace Common {
template <std::size_t Size, bool le = false>
[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size");
std::array<u8, Size> out{};
if constexpr (le) {
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {

View File

@ -30,6 +30,7 @@ namespace Settings {
#define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>
#define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED>
SETTING(AppletMode, false);
SETTING(AudioEngine, false);
SETTING(bool, false);
SETTING(int, false);
@ -215,6 +216,8 @@ const char* TranslateCategory(Category category) {
return "Debugging";
case Category::GpuDriver:
return "GpuDriver";
case Category::LibraryApplet:
return "LibraryApplet";
case Category::Miscellaneous:
return "Miscellaneous";
case Category::Network:

View File

@ -133,6 +133,38 @@ struct TouchFromButtonMap {
struct Values {
Linkage linkage{};
// Applet
Setting<AppletMode> cabinet_applet_mode{linkage, AppletMode::LLE, "cabinet_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> controller_applet_mode{linkage, AppletMode::HLE, "controller_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> data_erase_applet_mode{linkage, AppletMode::HLE, "data_erase_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> error_applet_mode{linkage, AppletMode::HLE, "error_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> net_connect_applet_mode{linkage, AppletMode::HLE, "net_connect_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> player_select_applet_mode{
linkage, AppletMode::HLE, "player_select_applet_mode", Category::LibraryApplet};
Setting<AppletMode> swkbd_applet_mode{linkage, AppletMode::LLE, "swkbd_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> mii_edit_applet_mode{linkage, AppletMode::LLE, "mii_edit_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> web_applet_mode{linkage, AppletMode::HLE, "web_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> shop_applet_mode{linkage, AppletMode::HLE, "shop_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> photo_viewer_applet_mode{
linkage, AppletMode::LLE, "photo_viewer_applet_mode", Category::LibraryApplet};
Setting<AppletMode> offline_web_applet_mode{linkage, AppletMode::LLE, "offline_web_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> login_share_applet_mode{linkage, AppletMode::HLE, "login_share_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> wifi_web_auth_applet_mode{
linkage, AppletMode::HLE, "wifi_web_auth_applet_mode", Category::LibraryApplet};
Setting<AppletMode> my_page_applet_mode{linkage, AppletMode::LLE, "my_page_applet_mode",
Category::LibraryApplet};
// Audio
SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine",
Category::Audio, Specialization::RuntimeList};

View File

@ -44,6 +44,7 @@ enum class Category : u32 {
Services,
Paths,
Linux,
LibraryApplet,
MaxEnum,
};

View File

@ -151,6 +151,8 @@ ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
ENUM(ConsoleMode, Handheld, Docked);
ENUM(AppletMode, HLE, LLE);
template <typename Type>
inline std::string CanonicalizeEnum(Type id) {
const auto group = EnumMetadata<Type>::Canonicalizations();

View File

@ -775,6 +775,9 @@ add_library(core STATIC
hle/service/nvnflinger/graphic_buffer_producer.h
hle/service/nvnflinger/hos_binder_driver_server.cpp
hle/service/nvnflinger/hos_binder_driver_server.h
hle/service/nvnflinger/hardware_composer.cpp
hle/service/nvnflinger/hardware_composer.h
hle/service/nvnflinger/hwc_layer.h
hle/service/nvnflinger/nvnflinger.cpp
hle/service/nvnflinger/nvnflinger.h
hle/service/nvnflinger/parcel.h

View File

@ -43,6 +43,8 @@ public:
DeviceMemoryManager(const DeviceMemory& device_memory);
~DeviceMemoryManager();
static constexpr bool HAS_FLUSH_INVALIDATION = true;
void BindInterface(DeviceInterface* device_inter);
DAddr Allocate(size_t size);

View File

@ -44,15 +44,32 @@ public:
GuestMemory() = delete;
explicit GuestMemory(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: m_memory{memory}, m_addr{addr}, m_size{size} {
: m_memory{&memory}, m_addr{addr}, m_size{size} {
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
if constexpr (FLAGS & GuestMemoryFlags::Read) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
backup->resize_destructive(this->size());
m_data_span = *backup;
m_span_valid = true;
m_is_data_copy = true;
} else {
m_data_copy.resize(this->size());
m_data_span = std::span(m_data_copy);
m_span_valid = true;
m_is_data_copy = true;
}
}
} else if constexpr (FLAGS & GuestMemoryFlags::Read) {
Read(addr, size, backup);
}
}
~GuestMemory() = default;
GuestMemory(GuestMemory&& rhs) = default;
GuestMemory& operator=(GuestMemory&& rhs) = default;
T* data() noexcept {
return m_data_span.data();
}
@ -109,8 +126,8 @@ public:
}
if (this->TrySetSpan()) {
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.FlushRegion(m_addr, this->size_bytes());
if constexpr (FLAGS & GuestMemoryFlags::Safe && M::HAS_FLUSH_INVALIDATION) {
m_memory->FlushRegion(m_addr, this->size_bytes());
}
} else {
if (backup) {
@ -123,9 +140,9 @@ public:
m_is_data_copy = true;
m_span_valid = true;
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
m_memory->ReadBlock(m_addr, this->data(), this->size_bytes());
} else {
m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
m_memory->ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
}
}
return m_data_span;
@ -133,18 +150,19 @@ public:
void Write(std::span<T> write_data) noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlock(m_addr, write_data.data(), this->size_bytes());
} else {
m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
}
}
bool TrySetSpan() noexcept {
if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
if (u8* ptr = m_memory->GetSpan(m_addr, this->size_bytes()); ptr) {
m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
m_span_valid = true;
m_is_data_copy = false;
return true;
}
return false;
@ -159,7 +177,7 @@ protected:
return m_addr_changed;
}
M& m_memory;
M* m_memory;
u64 m_addr{};
size_t m_size{};
std::span<T> m_data_span{};
@ -175,17 +193,7 @@ public:
GuestMemoryScoped() = delete;
explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
this->m_data_span = *backup;
this->m_span_valid = true;
this->m_is_data_copy = true;
}
}
}
}
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {}
~GuestMemoryScoped() {
if constexpr (FLAGS & GuestMemoryFlags::Write) {
@ -196,15 +204,17 @@ public:
if (this->AddressChanged() || this->IsDataCopy()) {
ASSERT(this->m_span_valid);
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlockCached(this->m_addr, this->data(),
this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlock(this->m_addr, this->data(), this->size_bytes());
} else {
this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlockUnsafe(this->m_addr, this->data(),
this->size_bytes());
}
} else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
(FLAGS & GuestMemoryFlags::Cached)) {
this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
this->m_memory->InvalidateRegion(this->m_addr, this->size_bytes());
}
}
}

View File

@ -4,8 +4,9 @@
#include <random>
#include "common/scope_exit.h"
#include "common/settings.h"
#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/core.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_shared_memory.h"
@ -1258,6 +1259,10 @@ void KProcess::InitializeInterfaces() {
#ifdef HAS_NCE
if (this->IsApplication() && Settings::IsNceEnabled()) {
// Register the scoped JIT handler before creating any NCE instances
// so that its signal handler will appear first in the signal chain.
Core::ScopedJitExecution::RegisterHandler();
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
}

View File

@ -130,9 +130,9 @@ enum class AppletProgramId : u64 {
enum class LibraryAppletMode : u32 {
AllForeground = 0,
Background = 1,
NoUI = 2,
BackgroundIndirectDisplay = 3,
PartialForeground = 1,
NoUi = 2,
PartialForegroundIndirectDisplay = 3,
AllForegroundInitiallyHidden = 4,
};

View File

@ -68,9 +68,9 @@ void SoftwareKeyboard::Initialize() {
case LibraryAppletMode::AllForeground:
InitializeForeground();
break;
case LibraryAppletMode::Background:
case LibraryAppletMode::BackgroundIndirectDisplay:
InitializeBackground(applet_mode);
case LibraryAppletMode::PartialForeground:
case LibraryAppletMode::PartialForegroundIndirectDisplay:
InitializePartialForeground(applet_mode);
break;
default:
ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode);
@ -243,7 +243,7 @@ void SoftwareKeyboard::InitializeForeground() {
InitializeFrontendNormalKeyboard();
}
void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) {
void SoftwareKeyboard::InitializePartialForeground(LibraryAppletMode library_applet_mode) {
LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
is_background = true;
@ -258,9 +258,9 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
swkbd_inline_initialize_arg.size());
if (swkbd_initialize_arg.library_applet_mode_flag) {
ASSERT(library_applet_mode == LibraryAppletMode::Background);
ASSERT(library_applet_mode == LibraryAppletMode::PartialForeground);
} else {
ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
ASSERT(library_applet_mode == LibraryAppletMode::PartialForegroundIndirectDisplay);
}
}

View File

@ -62,7 +62,7 @@ private:
void InitializeForeground();
/// Initializes the inline software keyboard.
void InitializeBackground(LibraryAppletMode library_applet_mode);
void InitializePartialForeground(LibraryAppletMode library_applet_mode);
/// Processes the text check sent by the application.
void ProcessTextCheck();

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h"
@ -16,6 +17,34 @@ namespace Service::AM {
namespace {
bool ShouldCreateGuestApplet(AppletId applet_id) {
#define X(Name, name) \
if (applet_id == AppletId::Name && \
Settings::values.name##_applet_mode.GetValue() != Settings::AppletMode::LLE) { \
return false; \
}
X(Cabinet, cabinet)
X(Controller, controller)
X(DataErase, data_erase)
X(Error, error)
X(NetConnect, net_connect)
X(ProfileSelect, player_select)
X(SoftwareKeyboard, swkbd)
X(MiiEdit, mii_edit)
X(Web, web)
X(Shop, shop)
X(PhotoViewer, photo_viewer)
X(OfflineWeb, offline_web)
X(LoginShare, login_share)
X(WebAuth, wifi_web_auth)
X(MyPage, my_page)
#undef X
return true;
}
AppletProgramId AppletIdToProgramId(AppletId applet_id) {
switch (applet_id) {
case AppletId::OverlayDisplay:
@ -63,9 +92,10 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
}
}
[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(
Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
LibraryAppletMode mode) {
std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
std::shared_ptr<Applet> caller_applet,
AppletId applet_id,
LibraryAppletMode mode) {
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
if (program_id == 0) {
// Unknown applet
@ -87,24 +117,18 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
// Set focus state
switch (mode) {
case LibraryAppletMode::AllForeground:
case LibraryAppletMode::NoUI:
applet->focus_state = FocusState::InFocus;
case LibraryAppletMode::NoUi:
case LibraryAppletMode::PartialForeground:
case LibraryAppletMode::PartialForegroundIndirectDisplay:
applet->hid_registration.EnableAppletToGetInput(true);
applet->focus_state = FocusState::InFocus;
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break;
case LibraryAppletMode::AllForegroundInitiallyHidden:
applet->system_buffer_manager.SetWindowVisibility(false);
applet->focus_state = FocusState::NotInFocus;
applet->hid_registration.EnableAppletToGetInput(false);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break;
case LibraryAppletMode::Background:
case LibraryAppletMode::BackgroundIndirectDisplay:
default:
applet->focus_state = FocusState::Background;
applet->hid_registration.EnableAppletToGetInput(true);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
applet->focus_state = FocusState::NotInFocus;
applet->system_buffer_manager.SetWindowVisibility(false);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoBackground);
break;
}
@ -117,9 +141,10 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
}
[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(
Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
LibraryAppletMode mode) {
std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system,
std::shared_ptr<Applet> caller_applet,
AppletId applet_id,
LibraryAppletMode mode) {
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
auto process = std::make_unique<Process>(system);
@ -163,7 +188,13 @@ void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
applet_mode);
auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode);
std::shared_ptr<ILibraryAppletAccessor> library_applet;
if (ShouldCreateGuestApplet(applet_id)) {
library_applet = CreateGuestApplet(system, applet, applet_id, applet_mode);
}
if (!library_applet) {
library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode);
}
if (!library_applet) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);

View File

@ -1,10 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/self_controller.h"
#include "core/hle/service/caps/caps_su.h"
#include "core/hle/service/hle_ipc.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
@ -47,7 +50,7 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
{51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
{61, nullptr, "SetMediaPlaybackState"},
{61, &ISelfController::SetMediaPlaybackState, "SetMediaPlaybackState"},
{62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
{63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
{64, nullptr, "SetInputDetectionSourceSet"},
@ -288,7 +291,8 @@ void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
}
Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) {
if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) {
if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id,
applet->library_applet_mode)) {
return ResultSuccess;
}
@ -323,6 +327,16 @@ void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
void ISelfController::SetMediaPlaybackState(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u8 state = rp.Pop<u8>();
LOG_WARNING(Service_AM, "(STUBBED) called, state={}", state);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};

View File

@ -3,6 +3,7 @@
#pragma once
#include "core/hle/service/hle_ipc.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
@ -38,6 +39,7 @@ private:
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
void SetHandlesRequestToDisplay(HLERequestContext& ctx);
void ApproveToDisplay(HLERequestContext& ctx);
void SetMediaPlaybackState(HLERequestContext& ctx);
void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
void ReportUserIsActive(HLERequestContext& ctx);

View File

@ -17,11 +17,12 @@ SystemBufferManager::~SystemBufferManager() {
// Clean up shared layers.
if (m_buffer_sharing_enabled) {
m_nvnflinger->GetSystemBufferManager().Finalize(m_process);
}
}
bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
AppletId applet_id) {
AppletId applet_id, LibraryAppletMode mode) {
if (m_nvnflinger) {
return m_buffer_sharing_enabled;
}
@ -36,9 +37,15 @@ bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel:
return false;
}
Nvnflinger::LayerBlending blending = Nvnflinger::LayerBlending::None;
if (mode == LibraryAppletMode::PartialForeground ||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay) {
blending = Nvnflinger::LayerBlending::Coverage;
}
const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
&m_system_shared_buffer_id, &m_system_shared_layer_id, display_id);
m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blending);
if (res.IsSuccess()) {
m_buffer_sharing_enabled = true;
@ -62,8 +69,12 @@ void SystemBufferManager::SetWindowVisibility(bool visible) {
Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
s32* out_fbshare_layer_index) {
// TODO
R_SUCCEED();
if (!m_buffer_sharing_enabled) {
return VI::ResultPermissionDenied;
}
return m_nvnflinger->GetSystemBufferManager().WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index);
}
} // namespace Service::AM

View File

@ -27,7 +27,8 @@ public:
SystemBufferManager();
~SystemBufferManager();
bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id);
bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id,
LibraryAppletMode mode);
void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
u64* out_system_shared_layer_id) {

View File

@ -62,12 +62,12 @@ void IWindowController::SetAppletWindowVisibility(HLERequestContext& ctx) {
applet->hid_registration.EnableAppletToGetInput(visible);
if (visible) {
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
applet->focus_state = FocusState::InFocus;
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
} else {
applet->focus_state = FocusState::NotInFocus;
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoBackground);
}
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);

View File

@ -115,6 +115,11 @@ struct ArgumentTraits {
static constexpr ArgumentType Type = ArgumentType::InData;
};
template <typename... Ts>
consteval bool ConstIfReference() {
return ((!std::is_reference_v<Ts> || std::is_const_v<std::remove_reference_t<Ts>>) && ... && true);
}
struct RequestLayout {
u32 copy_handle_count;
u32 move_handle_count;
@ -435,6 +440,7 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
}
const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false;
static_assert(ConstIfReference<A...>(), "Arguments taken by reference must be const");
using MethodArguments = std::tuple<std::remove_cvref_t<A>...>;
OutTemporaryBuffers buffers{};

View File

@ -4,10 +4,9 @@
#pragma once
#include <memory>
#include <span>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/service/hle_ipc.h"
namespace Service {
@ -22,8 +21,10 @@ class Out {
public:
using Type = T;
/* implicit */ Out(const Out& t) : raw(t.raw) {}
/* implicit */ Out(AutoOut<Type>& t) : raw(&t.raw) {}
/* implicit */ Out(Type* t) : raw(t) {}
Out& operator=(const Out&) = delete;
Type* Get() const {
return raw;
@ -37,6 +38,10 @@ public:
return raw;
}
operator Type*() const {
return raw;
}
private:
Type* raw;
};
@ -113,8 +118,10 @@ class OutCopyHandle {
public:
using Type = T*;
/* implicit */ OutCopyHandle(const OutCopyHandle& t) : raw(t.raw) {}
/* implicit */ OutCopyHandle(AutoOut<Type>& t) : raw(&t.raw) {}
/* implicit */ OutCopyHandle(Type* t) : raw(t) {}
OutCopyHandle& operator=(const OutCopyHandle&) = delete;
Type* Get() const {
return raw;
@ -128,6 +135,10 @@ public:
return raw;
}
operator Type*() const {
return raw;
}
private:
Type* raw;
};
@ -137,8 +148,10 @@ class OutMoveHandle {
public:
using Type = T*;
/* implicit */ OutMoveHandle(const OutMoveHandle& t) : raw(t.raw) {}
/* implicit */ OutMoveHandle(AutoOut<Type>& t) : raw(&t.raw) {}
/* implicit */ OutMoveHandle(Type* t) : raw(t) {}
OutMoveHandle& operator=(const OutMoveHandle&) = delete;
Type* Get() const {
return raw;
@ -152,6 +165,10 @@ public:
return raw;
}
operator Type*() const {
return raw;
}
private:
Type* raw;
};
@ -248,8 +265,10 @@ public:
static constexpr BufferAttr Attr = static_cast<BufferAttr>(A | BufferAttr_In | BufferAttr_FixedSize);
using Type = T;
/* implicit */ OutLargeData(const OutLargeData& t) : raw(t.raw) {}
/* implicit */ OutLargeData(Type* t) : raw(t) {}
/* implicit */ OutLargeData(AutoOut<T>& t) : raw(&t.raw) {}
OutLargeData& operator=(const OutLargeData&) = delete;
Type* Get() const {
return raw;
@ -263,6 +282,10 @@ public:
return raw;
}
operator Type*() const {
return raw;
}
private:
Type* raw;
};

View File

@ -115,6 +115,11 @@ private:
if (type->GetName() == "save") {
for (const auto& save_id : type->GetSubdirectories()) {
for (const auto& user_id : save_id->GetSubdirectories()) {
// Skip non user id subdirectories
if (user_id->GetName().size() != 0x20) {
continue;
}
const auto save_id_numeric = stoull_be(save_id->GetName());
auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
std::reverse(user_id_numeric.begin(), user_id_numeric.end());
@ -160,6 +165,10 @@ private:
} else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
// Temporary Storage
for (const auto& user_id : type->GetSubdirectories()) {
// Skip non user id subdirectories
if (user_id->GetName().size() != 0x20) {
continue;
}
for (const auto& title_id : user_id->GetSubdirectories()) {
if (!title_id->GetFiles().empty() ||
!title_id->GetSubdirectories().empty()) {

View File

@ -31,8 +31,11 @@ void LoopProcess(Core::System& system) {
// Error Context
server_manager->RegisterNamedService("ectx:aw", std::make_shared<ECTX_AW>(system));
// Notification Services for application
server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system));
// Notification Services
server_manager->RegisterNamedService(
"notif:a", std::make_shared<INotificationServicesForApplication>(system));
server_manager->RegisterNamedService("notif:s",
std::make_shared<INotificationServices>(system));
// Time
auto time = std::make_shared<Time::TimeManager>(system);

View File

@ -6,48 +6,31 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/glue/notif.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
namespace Service::Glue {
NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} {
// clang-format off
static const FunctionInfo functions[] = {
{500, &NOTIF_A::RegisterAlarmSetting, "RegisterAlarmSetting"},
{510, &NOTIF_A::UpdateAlarmSetting, "UpdateAlarmSetting"},
{520, &NOTIF_A::ListAlarmSettings, "ListAlarmSettings"},
{530, &NOTIF_A::LoadApplicationParameter, "LoadApplicationParameter"},
{540, &NOTIF_A::DeleteAlarmSetting, "DeleteAlarmSetting"},
{1000, &NOTIF_A::Initialize, "Initialize"},
};
// clang-format on
namespace {
constexpr inline std::size_t MaxAlarms = 8;
RegisterHandlers(functions);
}
NOTIF_A::~NOTIF_A() = default;
void NOTIF_A::RegisterAlarmSetting(HLERequestContext& ctx) {
const auto alarm_setting_buffer_size = ctx.GetReadBufferSize(0);
const auto application_parameter_size = ctx.GetReadBufferSize(1);
ASSERT_MSG(alarm_setting_buffer_size == sizeof(AlarmSetting),
"alarm_setting_buffer_size is not 0x40 bytes");
ASSERT_MSG(application_parameter_size <= sizeof(ApplicationParameter),
"application_parameter_size is bigger than 0x400 bytes");
AlarmSetting new_alarm{};
memcpy(&new_alarm, ctx.ReadBuffer(0).data(), sizeof(AlarmSetting));
// TODO: Count alarms per game id
if (alarms.size() >= max_alarms) {
Result NotificationServiceImpl::RegisterAlarmSetting(AlarmSettingId* out_alarm_setting_id,
const AlarmSetting& alarm_setting,
std::span<const u8> application_parameter) {
if (alarms.size() > MaxAlarms) {
LOG_ERROR(Service_NOTIF, "Alarm limit reached");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
R_THROW(ResultUnknown);
}
ASSERT_MSG(application_parameter.size() <= sizeof(ApplicationParameter),
"application_parameter_size is bigger than 0x400 bytes");
AlarmSetting new_alarm = alarm_setting;
new_alarm.alarm_setting_id = last_alarm_setting_id++;
alarms.push_back(new_alarm);
@ -55,100 +38,82 @@ void NOTIF_A::RegisterAlarmSetting(HLERequestContext& ctx) {
LOG_WARNING(Service_NOTIF,
"(STUBBED) called, application_parameter_size={}, setting_id={}, kind={}, muted={}",
application_parameter_size, new_alarm.alarm_setting_id, new_alarm.kind,
application_parameter.size(), new_alarm.alarm_setting_id, new_alarm.kind,
new_alarm.muted);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(new_alarm.alarm_setting_id);
*out_alarm_setting_id = new_alarm.alarm_setting_id;
R_SUCCEED();
}
void NOTIF_A::UpdateAlarmSetting(HLERequestContext& ctx) {
const auto alarm_setting_buffer_size = ctx.GetReadBufferSize(0);
const auto application_parameter_size = ctx.GetReadBufferSize(1);
ASSERT_MSG(alarm_setting_buffer_size == sizeof(AlarmSetting),
"alarm_setting_buffer_size is not 0x40 bytes");
ASSERT_MSG(application_parameter_size <= sizeof(ApplicationParameter),
Result NotificationServiceImpl::UpdateAlarmSetting(const AlarmSetting& alarm_setting,
std::span<const u8> application_parameter) {
ASSERT_MSG(application_parameter.size() <= sizeof(ApplicationParameter),
"application_parameter_size is bigger than 0x400 bytes");
AlarmSetting alarm_setting{};
memcpy(&alarm_setting, ctx.ReadBuffer(0).data(), sizeof(AlarmSetting));
const auto alarm_it = GetAlarmFromId(alarm_setting.alarm_setting_id);
if (alarm_it != alarms.end()) {
LOG_DEBUG(Service_NOTIF, "Alarm updated");
*alarm_it = alarm_setting;
// TODO: Save application parameter data
}
LOG_WARNING(Service_NOTIF,
"(STUBBED) called, application_parameter_size={}, setting_id={}, kind={}, muted={}",
application_parameter_size, alarm_setting.alarm_setting_id, alarm_setting.kind,
application_parameter.size(), alarm_setting.alarm_setting_id, alarm_setting.kind,
alarm_setting.muted);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_SUCCEED();
}
void NOTIF_A::ListAlarmSettings(HLERequestContext& ctx) {
Result NotificationServiceImpl::ListAlarmSettings(s32* out_count,
std::span<AlarmSetting> out_alarms) {
LOG_INFO(Service_NOTIF, "called, alarm_count={}", alarms.size());
// TODO: Only return alarms of this game id
ctx.WriteBuffer(alarms);
const auto count = std::min(out_alarms.size(), alarms.size());
for (size_t i = 0; i < count; i++) {
out_alarms[i] = alarms[i];
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(alarms.size()));
*out_count = static_cast<s32>(count);
R_SUCCEED();
}
void NOTIF_A::LoadApplicationParameter(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto alarm_setting_id{rp.Pop<AlarmSettingId>()};
Result NotificationServiceImpl::LoadApplicationParameter(u32* out_size,
std::span<u8> out_application_parameter,
AlarmSettingId alarm_setting_id) {
const auto alarm_it = GetAlarmFromId(alarm_setting_id);
if (alarm_it == alarms.end()) {
LOG_ERROR(Service_NOTIF, "Invalid alarm setting id={}", alarm_setting_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
R_THROW(ResultUnknown);
}
// TODO: Read application parameter related to this setting id
ApplicationParameter application_parameter{};
LOG_WARNING(Service_NOTIF, "(STUBBED) called, alarm_setting_id={}", alarm_setting_id);
std::memcpy(out_application_parameter.data(), application_parameter.data(),
std::min(sizeof(application_parameter), out_application_parameter.size()));
ctx.WriteBuffer(application_parameter);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(application_parameter.size()));
*out_size = static_cast<u32>(application_parameter.size());
R_SUCCEED();
}
void NOTIF_A::DeleteAlarmSetting(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto alarm_setting_id{rp.Pop<AlarmSettingId>()};
Result NotificationServiceImpl::DeleteAlarmSetting(AlarmSettingId alarm_setting_id) {
std::erase_if(alarms, [alarm_setting_id](const AlarmSetting& alarm) {
return alarm.alarm_setting_id == alarm_setting_id;
});
LOG_INFO(Service_NOTIF, "called, alarm_setting_id={}", alarm_setting_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_SUCCEED();
}
void NOTIF_A::Initialize(HLERequestContext& ctx) {
Result NotificationServiceImpl::Initialize(u64 aruid) {
// TODO: Load previous alarms from config
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_SUCCEED();
}
std::vector<NOTIF_A::AlarmSetting>::iterator NOTIF_A::GetAlarmFromId(
std::vector<AlarmSetting>::iterator NotificationServiceImpl::GetAlarmFromId(
AlarmSettingId alarm_setting_id) {
return std::find_if(alarms.begin(), alarms.end(),
[alarm_setting_id](const AlarmSetting& alarm) {
@ -156,4 +121,174 @@ std::vector<NOTIF_A::AlarmSetting>::iterator NOTIF_A::GetAlarmFromId(
});
}
INotificationServicesForApplication::INotificationServicesForApplication(Core::System& system_)
: ServiceFramework{system_, "notif:a"} {
// clang-format off
static const FunctionInfo functions[] = {
{500, D<&INotificationServicesForApplication::RegisterAlarmSetting>, "RegisterAlarmSetting"},
{510, D<&INotificationServicesForApplication::UpdateAlarmSetting>, "UpdateAlarmSetting"},
{520, D<&INotificationServicesForApplication::ListAlarmSettings>, "ListAlarmSettings"},
{530, D<&INotificationServicesForApplication::LoadApplicationParameter>, "LoadApplicationParameter"},
{540, D<&INotificationServicesForApplication::DeleteAlarmSetting>, "DeleteAlarmSetting"},
{1000, D<&INotificationServicesForApplication::Initialize>, "Initialize"},
};
// clang-format on
RegisterHandlers(functions);
}
INotificationServicesForApplication::~INotificationServicesForApplication() = default;
Result INotificationServicesForApplication::RegisterAlarmSetting(
Out<AlarmSettingId> out_alarm_setting_id,
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
InBuffer<BufferAttr_HipcMapAlias> application_parameter) {
R_RETURN(impl.RegisterAlarmSetting(out_alarm_setting_id.Get(), *alarm_setting,
application_parameter));
}
Result INotificationServicesForApplication::UpdateAlarmSetting(
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
InBuffer<BufferAttr_HipcMapAlias> application_parameter) {
R_RETURN(impl.UpdateAlarmSetting(*alarm_setting, application_parameter));
}
Result INotificationServicesForApplication::ListAlarmSettings(
Out<s32> out_count, OutArray<AlarmSetting, BufferAttr_HipcMapAlias> out_alarms) {
R_RETURN(impl.ListAlarmSettings(out_count.Get(), out_alarms));
}
Result INotificationServicesForApplication::LoadApplicationParameter(
Out<u32> out_size, OutBuffer<BufferAttr_HipcMapAlias> out_application_parameter,
AlarmSettingId alarm_setting_id) {
R_RETURN(
impl.LoadApplicationParameter(out_size.Get(), out_application_parameter, alarm_setting_id));
}
Result INotificationServicesForApplication::DeleteAlarmSetting(AlarmSettingId alarm_setting_id) {
R_RETURN(impl.DeleteAlarmSetting(alarm_setting_id));
}
Result INotificationServicesForApplication::Initialize(ClientAppletResourceUserId aruid) {
R_RETURN(impl.Initialize(*aruid));
}
class INotificationSystemEventAccessor final
: public ServiceFramework<INotificationSystemEventAccessor> {
public:
explicit INotificationSystemEventAccessor(Core::System& system_)
: ServiceFramework{system_, "INotificationSystemEventAccessor"},
service_context{system_, "INotificationSystemEventAccessor"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&INotificationSystemEventAccessor::GetSystemEvent>, "GetSystemEvent"},
};
// clang-format on
RegisterHandlers(functions);
notification_event =
service_context.CreateEvent("INotificationSystemEventAccessor:NotificationEvent");
}
~INotificationSystemEventAccessor() {
service_context.CloseEvent(notification_event);
}
private:
Result GetSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_readable_event) {
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
*out_readable_event = &notification_event->GetReadableEvent();
R_SUCCEED();
}
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* notification_event;
};
INotificationServices::INotificationServices(Core::System& system_)
: ServiceFramework{system_, "notif:s"} {
// clang-format off
static const FunctionInfo functions[] = {
{500, D<&INotificationServices::RegisterAlarmSetting>, "RegisterAlarmSetting"},
{510, D<&INotificationServices::UpdateAlarmSetting>, "UpdateAlarmSetting"},
{520, D<&INotificationServices::ListAlarmSettings>, "ListAlarmSettings"},
{530, D<&INotificationServices::LoadApplicationParameter>, "LoadApplicationParameter"},
{540, D<&INotificationServices::DeleteAlarmSetting>, "DeleteAlarmSetting"},
{1000, D<&INotificationServices::Initialize>, "Initialize"},
{1010, nullptr, "ListNotifications"},
{1020, nullptr, "DeleteNotification"},
{1030, nullptr, "ClearNotifications"},
{1040, D<&INotificationServices::OpenNotificationSystemEventAccessor>, "OpenNotificationSystemEventAccessor"},
{1500, nullptr, "SetNotificationPresentationSetting"},
{1510, D<&INotificationServices::GetNotificationPresentationSetting>, "GetNotificationPresentationSetting"},
{2000, nullptr, "GetAlarmSetting"},
{2001, nullptr, "GetAlarmSettingWithApplicationParameter"},
{2010, nullptr, "MuteAlarmSetting"},
{2020, nullptr, "IsAlarmSettingReady"},
{8000, nullptr, "RegisterAppletResourceUserId"},
{8010, nullptr, "UnregisterAppletResourceUserId"},
{8999, nullptr, "GetCurrentTime"},
{9000, nullptr, "GetAlarmSettingNextNotificationTime"},
};
// clang-format on
RegisterHandlers(functions);
}
INotificationServices::~INotificationServices() = default;
Result INotificationServices::RegisterAlarmSetting(
Out<AlarmSettingId> out_alarm_setting_id,
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
InBuffer<BufferAttr_HipcMapAlias> application_parameter) {
R_RETURN(impl.RegisterAlarmSetting(out_alarm_setting_id.Get(), *alarm_setting,
application_parameter));
}
Result INotificationServices::UpdateAlarmSetting(
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
InBuffer<BufferAttr_HipcMapAlias> application_parameter) {
R_RETURN(impl.UpdateAlarmSetting(*alarm_setting, application_parameter));
}
Result INotificationServices::ListAlarmSettings(
Out<s32> out_count, OutArray<AlarmSetting, BufferAttr_HipcMapAlias> out_alarms) {
R_RETURN(impl.ListAlarmSettings(out_count.Get(), out_alarms));
}
Result INotificationServices::LoadApplicationParameter(
Out<u32> out_size, OutBuffer<BufferAttr_HipcMapAlias> out_application_parameter,
AlarmSettingId alarm_setting_id) {
R_RETURN(
impl.LoadApplicationParameter(out_size.Get(), out_application_parameter, alarm_setting_id));
}
Result INotificationServices::DeleteAlarmSetting(AlarmSettingId alarm_setting_id) {
R_RETURN(impl.DeleteAlarmSetting(alarm_setting_id));
}
Result INotificationServices::Initialize(ClientAppletResourceUserId aruid) {
R_RETURN(impl.Initialize(*aruid));
}
Result INotificationServices::OpenNotificationSystemEventAccessor(
Out<SharedPointer<INotificationSystemEventAccessor>> out_notification_system_event_accessor) {
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
*out_notification_system_event_accessor =
std::make_shared<INotificationSystemEventAccessor>(system);
R_SUCCEED();
}
Result INotificationServices::GetNotificationPresentationSetting(
Out<NotificationPresentationSetting> out_notification_presentation_setting,
NotificationChannel notification_channel) {
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
*out_notification_presentation_setting = {};
R_SUCCEED();
}
} // namespace Service::Glue

View File

@ -7,6 +7,7 @@
#include <vector>
#include "common/uuid.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Core {
@ -15,58 +16,117 @@ class System;
namespace Service::Glue {
class NOTIF_A final : public ServiceFramework<NOTIF_A> {
// This is nn::notification::AlarmSettingId
using AlarmSettingId = u16;
static_assert(sizeof(AlarmSettingId) == 0x2, "AlarmSettingId is an invalid size");
using ApplicationParameter = std::array<u8, 0x400>;
static_assert(sizeof(ApplicationParameter) == 0x400, "ApplicationParameter is an invalid size");
struct DailyAlarmSetting {
s8 hour;
s8 minute;
};
static_assert(sizeof(DailyAlarmSetting) == 0x2, "DailyAlarmSetting is an invalid size");
struct WeeklyScheduleAlarmSetting {
INSERT_PADDING_BYTES_NOINIT(0xA);
std::array<DailyAlarmSetting, 0x7> day_of_week;
};
static_assert(sizeof(WeeklyScheduleAlarmSetting) == 0x18,
"WeeklyScheduleAlarmSetting is an invalid size");
// This is nn::notification::AlarmSetting
struct AlarmSetting {
AlarmSettingId alarm_setting_id;
u8 kind;
u8 muted;
INSERT_PADDING_BYTES_NOINIT(0x4);
Common::UUID account_id;
u64 application_id;
INSERT_PADDING_BYTES_NOINIT(0x8);
WeeklyScheduleAlarmSetting schedule;
};
static_assert(sizeof(AlarmSetting) == 0x40, "AlarmSetting is an invalid size");
enum class NotificationChannel : u8 {
Unknown0 = 0,
};
struct NotificationPresentationSetting {
INSERT_PADDING_BYTES_NOINIT(0x10);
};
static_assert(sizeof(NotificationPresentationSetting) == 0x10,
"NotificationPresentationSetting is an invalid size");
class NotificationServiceImpl {
public:
explicit NOTIF_A(Core::System& system_);
~NOTIF_A() override;
Result RegisterAlarmSetting(AlarmSettingId* out_alarm_setting_id,
const AlarmSetting& alarm_setting,
std::span<const u8> application_parameter);
Result UpdateAlarmSetting(const AlarmSetting& alarm_setting,
std::span<const u8> application_parameter);
Result ListAlarmSettings(s32* out_count, std::span<AlarmSetting> out_alarms);
Result LoadApplicationParameter(u32* out_size, std::span<u8> out_application_parameter,
AlarmSettingId alarm_setting_id);
Result DeleteAlarmSetting(AlarmSettingId alarm_setting_id);
Result Initialize(u64 aruid);
private:
static constexpr std::size_t max_alarms = 8;
// This is nn::notification::AlarmSettingId
using AlarmSettingId = u16;
static_assert(sizeof(AlarmSettingId) == 0x2, "AlarmSettingId is an invalid size");
using ApplicationParameter = std::array<u8, 0x400>;
static_assert(sizeof(ApplicationParameter) == 0x400, "ApplicationParameter is an invalid size");
struct DailyAlarmSetting {
s8 hour;
s8 minute;
};
static_assert(sizeof(DailyAlarmSetting) == 0x2, "DailyAlarmSetting is an invalid size");
struct WeeklyScheduleAlarmSetting {
INSERT_PADDING_BYTES(0xA);
std::array<DailyAlarmSetting, 0x7> day_of_week;
};
static_assert(sizeof(WeeklyScheduleAlarmSetting) == 0x18,
"WeeklyScheduleAlarmSetting is an invalid size");
// This is nn::notification::AlarmSetting
struct AlarmSetting {
AlarmSettingId alarm_setting_id;
u8 kind;
u8 muted;
INSERT_PADDING_BYTES(0x4);
Common::UUID account_id;
u64 application_id;
INSERT_PADDING_BYTES(0x8);
WeeklyScheduleAlarmSetting schedule;
};
static_assert(sizeof(AlarmSetting) == 0x40, "AlarmSetting is an invalid size");
void RegisterAlarmSetting(HLERequestContext& ctx);
void UpdateAlarmSetting(HLERequestContext& ctx);
void ListAlarmSettings(HLERequestContext& ctx);
void LoadApplicationParameter(HLERequestContext& ctx);
void DeleteAlarmSetting(HLERequestContext& ctx);
void Initialize(HLERequestContext& ctx);
std::vector<AlarmSetting>::iterator GetAlarmFromId(AlarmSettingId alarm_setting_id);
std::vector<AlarmSetting> alarms{};
AlarmSettingId last_alarm_setting_id{};
};
class INotificationServicesForApplication final
: public ServiceFramework<INotificationServicesForApplication> {
public:
explicit INotificationServicesForApplication(Core::System& system_);
~INotificationServicesForApplication() override;
private:
Result RegisterAlarmSetting(Out<AlarmSettingId> out_alarm_setting_id,
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
InBuffer<BufferAttr_HipcMapAlias> application_parameter);
Result UpdateAlarmSetting(InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
InBuffer<BufferAttr_HipcMapAlias> application_parameter);
Result ListAlarmSettings(Out<s32> out_count,
OutArray<AlarmSetting, BufferAttr_HipcMapAlias> out_alarms);
Result LoadApplicationParameter(Out<u32> out_size,
OutBuffer<BufferAttr_HipcMapAlias> out_application_parameter,
AlarmSettingId alarm_setting_id);
Result DeleteAlarmSetting(AlarmSettingId alarm_setting_id);
Result Initialize(ClientAppletResourceUserId aruid);
NotificationServiceImpl impl;
};
class INotificationSystemEventAccessor;
class INotificationServices final : public ServiceFramework<INotificationServices> {
public:
explicit INotificationServices(Core::System& system_);
~INotificationServices() override;
private:
Result RegisterAlarmSetting(Out<AlarmSettingId> out_alarm_setting_id,
InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
InBuffer<BufferAttr_HipcMapAlias> application_parameter);
Result UpdateAlarmSetting(InLargeData<AlarmSetting, BufferAttr_HipcMapAlias> alarm_setting,
InBuffer<BufferAttr_HipcMapAlias> application_parameter);
Result ListAlarmSettings(Out<s32> out_count,
OutArray<AlarmSetting, BufferAttr_HipcMapAlias> out_alarms);
Result LoadApplicationParameter(Out<u32> out_size,
OutBuffer<BufferAttr_HipcMapAlias> out_application_parameter,
AlarmSettingId alarm_setting_id);
Result DeleteAlarmSetting(AlarmSettingId alarm_setting_id);
Result Initialize(ClientAppletResourceUserId aruid);
Result OpenNotificationSystemEventAccessor(Out<SharedPointer<INotificationSystemEventAccessor>>
out_notification_system_event_accessor);
Result GetNotificationPresentationSetting(
Out<NotificationPresentationSetting> out_notification_presentation_setting,
NotificationChannel notification_channel);
NotificationServiceImpl impl;
};
} // namespace Service::Glue

View File

@ -200,7 +200,7 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
}
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
Out<s64> out_time, Service::PSC::Time::SystemClockContext& context) {
Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) {
SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); });
R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context));
@ -216,8 +216,8 @@ Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot,
Result StaticService::GetClockSnapshotFromSystemClockContext(
Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot,
Service::PSC::Time::SystemClockContext& user_context,
Service::PSC::Time::SystemClockContext& network_context) {
const Service::PSC::Time::SystemClockContext& user_context,
const Service::PSC::Time::SystemClockContext& network_context) {
SCOPE_EXIT({
LOG_DEBUG(Service_Time,
"called. type={} out_snapshot={} user_context={} network_context={}", type,

View File

@ -58,12 +58,12 @@ public:
Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point);
Result CalculateMonotonicSystemClockBaseTimePoint(
Out<s64> out_time, Service::PSC::Time::SystemClockContext& context);
Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context);
Result GetClockSnapshot(OutClockSnapshot out_snapshot, Service::PSC::Time::TimeType type);
Result GetClockSnapshotFromSystemClockContext(
Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot,
Service::PSC::Time::SystemClockContext& user_context,
Service::PSC::Time::SystemClockContext& network_context);
const Service::PSC::Time::SystemClockContext& user_context,
const Service::PSC::Time::SystemClockContext& network_context);
Result CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
InClockSnapshot a, InClockSnapshot b);
Result CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, InClockSnapshot b);

View File

@ -62,7 +62,8 @@ Result TimeZoneService::GetDeviceLocationName(
R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name));
}
Result TimeZoneService::SetDeviceLocationName(Service::PSC::Time::LocationName& location_name) {
Result TimeZoneService::SetDeviceLocationName(
const Service::PSC::Time::LocationName& location_name) {
LOG_DEBUG(Service_Time, "called. location_name={}", location_name);
R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
@ -110,7 +111,8 @@ Result TimeZoneService::LoadLocationNameList(
R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index));
}
Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, Service::PSC::Time::LocationName& name) {
Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule,
const Service::PSC::Time::LocationName& name) {
LOG_DEBUG(Service_Time, "called. name={}", name);
std::scoped_lock l{m_mutex};
@ -139,7 +141,8 @@ Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
}
Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(
Service::PSC::Time::LocationName& location_name, InBuffer<BufferAttr_HipcAutoSelect> binary) {
const Service::PSC::Time::LocationName& location_name,
InBuffer<BufferAttr_HipcAutoSelect> binary) {
LOG_DEBUG(Service_Time, "called. location_name={}", location_name);
R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);

View File

@ -46,18 +46,20 @@ public:
~TimeZoneService() override;
Result GetDeviceLocationName(Out<Service::PSC::Time::LocationName> out_location_name);
Result SetDeviceLocationName(Service::PSC::Time::LocationName& location_name);
Result SetDeviceLocationName(const Service::PSC::Time::LocationName& location_name);
Result GetTotalLocationNameCount(Out<u32> out_count);
Result LoadLocationNameList(
Out<u32> out_count,
OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index);
Result LoadTimeZoneRule(OutRule out_rule, Service::PSC::Time::LocationName& location_name);
Result LoadTimeZoneRule(OutRule out_rule,
const Service::PSC::Time::LocationName& location_name);
Result GetTimeZoneRuleVersion(Out<Service::PSC::Time::RuleVersion> out_rule_version);
Result GetDeviceLocationNameAndUpdatedTime(
Out<Service::PSC::Time::LocationName> location_name,
Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point);
Result SetDeviceLocationNameWithTimeZoneRule(Service::PSC::Time::LocationName& location_name,
InBuffer<BufferAttr_HipcAutoSelect> binary);
Result SetDeviceLocationNameWithTimeZoneRule(
const Service::PSC::Time::LocationName& location_name,
InBuffer<BufferAttr_HipcAutoSelect> binary);
Result ParseTimeZoneBinary(OutRule out_rule, InBuffer<BufferAttr_HipcAutoSelect> binary);
Result GetDeviceLocationNameOperationEventReadableHandle(
OutCopyHandle<Kernel::KReadableEvent> out_event);

View File

@ -65,6 +65,7 @@ Result MountTimeZoneBinary(Core::System& system) {
// Validate that the romfs is readable, using invalid firmware keys can cause this to get
// set but the files to be garbage. In that case, we want to hit the next path and
// synthesise them instead.
g_time_zone_binary_mount_result = ResultSuccess;
Service::PSC::Time::LocationName name{"Etc/GMT"};
if (!IsTimeZoneBinaryValid(name)) {
ResetTimeZoneBinary();
@ -98,7 +99,7 @@ void GetTimeZoneBinaryVersionPath(std::string& out_path) {
out_path = "/version.txt";
}
void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name) {
void GetTimeZoneZonePath(std::string& out_path, const Service::PSC::Time::LocationName& name) {
if (g_time_zone_binary_mount_result != ResultSuccess) {
return;
}
@ -106,7 +107,7 @@ void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName
out_path = fmt::format("/zoneinfo/{}", name.data());
}
bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) {
bool IsTimeZoneBinaryValid(const Service::PSC::Time::LocationName& name) {
std::string path{};
GetTimeZoneZonePath(path, name);
@ -155,7 +156,7 @@ Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version) {
}
Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
Service::PSC::Time::LocationName& name) {
const Service::PSC::Time::LocationName& name) {
std::string path{};
GetTimeZoneZonePath(path, name);

View File

@ -19,12 +19,12 @@ void ResetTimeZoneBinary();
Result MountTimeZoneBinary(Core::System& system);
void GetTimeZoneBinaryListPath(std::string& out_path);
void GetTimeZoneBinaryVersionPath(std::string& out_path);
void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name);
bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name);
void GetTimeZoneZonePath(std::string& out_path, const Service::PSC::Time::LocationName& name);
bool IsTimeZoneBinaryValid(const Service::PSC::Time::LocationName& name);
u32 GetTimeZoneCount();
Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version);
Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
Service::PSC::Time::LocationName& name);
const Service::PSC::Time::LocationName& name);
Result GetTimeZoneLocationList(u32& out_count,
std::span<Service::PSC::Time::LocationName> out_names,
size_t max_names, u32 index);

View File

@ -126,7 +126,7 @@ public:
R_THROW(ResultUnknown);
}
Result LoadPlugin(u64 tmem_size, InCopyHandle<Kernel::KTransferMemory>& tmem,
Result LoadPlugin(u64 tmem_size, InCopyHandle<Kernel::KTransferMemory> tmem,
InBuffer<BufferAttr_HipcMapAlias> nrr,
InBuffer<BufferAttr_HipcMapAlias> nro) {
if (!tmem) {
@ -268,9 +268,9 @@ public:
private:
Result CreateJitEnvironment(Out<SharedPointer<IJitEnvironment>> out_jit_environment,
u64 rx_size, u64 ro_size, InCopyHandle<Kernel::KProcess>& process,
InCopyHandle<Kernel::KCodeMemory>& rx_mem,
InCopyHandle<Kernel::KCodeMemory>& ro_mem) {
u64 rx_size, u64 ro_size, InCopyHandle<Kernel::KProcess> process,
InCopyHandle<Kernel::KCodeMemory> rx_mem,
InCopyHandle<Kernel::KCodeMemory> ro_mem) {
if (!process) {
LOG_ERROR(Service_JIT, "process is null");
R_THROW(ResultUnknown);

View File

@ -189,7 +189,7 @@ private:
R_RETURN(manager->Move(metadata, new_index, create_id));
}
Result AddOrReplace(StoreData& store_data) {
Result AddOrReplace(const StoreData& store_data) {
LOG_INFO(Service_Mii, "called");
R_UNLESS(is_system, ResultPermissionDenied);

View File

@ -49,6 +49,7 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
continue;
}
if (session.process == process) {
session.ref_count++;
return session.id;
}
}
@ -66,6 +67,7 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
}
auto& session = impl->sessions[new_id];
session.is_active = true;
session.ref_count = 1;
// Optimization
if (process->IsApplication()) {
auto& page_table = process->GetPageTable().GetBasePageTable();
@ -114,8 +116,11 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
void Container::CloseSession(SessionId session_id) {
std::scoped_lock lk(impl->session_guard);
impl->file.UnmapAllHandles(session_id);
auto& session = impl->sessions[session_id.id];
if (--session.ref_count > 0) {
return;
}
impl->file.UnmapAllHandles(session_id);
auto& smmu = impl->host1x.MemoryManager();
if (session.has_preallocated_area) {
const DAddr region_start = session.mapper->GetRegionStart();

View File

@ -46,6 +46,7 @@ struct Session {
bool has_preallocated_area{};
std::unique_ptr<HeapMapper> mapper{};
bool is_active{};
s32 ref_count{};
};
class Container {
@ -67,10 +68,7 @@ public:
const SyncpointManager& GetSyncpointManager() const;
struct Host1xDeviceFileData {
std::unordered_map<DeviceFD, u32> fd_to_id{};
std::deque<u32> syncpts_accumulated{};
u32 nvdec_next_id{};
u32 vic_next_id{};
};
Host1xDeviceFileData& Host1xDeviceFile();

View File

@ -333,9 +333,13 @@ void NvMap::UnmapAllHandles(NvCore::SessionId session_id) {
}();
for (auto& [id, handle] : handles_copy) {
if (handle->session_id.id == session_id.id) {
FreeHandle(id, false);
{
std::scoped_lock lk{handle->mutex};
if (handle->session_id.id != session_id.id || handle->dupes <= 0) {
continue;
}
}
FreeHandle(id, false);
}
}

View File

@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <boost/container/small_vector.hpp>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
@ -13,6 +15,22 @@
namespace Service::Nvidia::Devices {
namespace {
Tegra::BlendMode ConvertBlending(Service::Nvnflinger::LayerBlending blending) {
switch (blending) {
case Service::Nvnflinger::LayerBlending::None:
default:
return Tegra::BlendMode::Opaque;
case Service::Nvnflinger::LayerBlending::Premultiplied:
return Tegra::BlendMode::Premultiplied;
case Service::Nvnflinger::LayerBlending::Coverage:
return Tegra::BlendMode::Coverage;
}
}
} // namespace
nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core)
: nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {}
nvdisp_disp0::~nvdisp_disp0() = default;
@ -38,19 +56,31 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
void nvdisp_disp0::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
void nvdisp_disp0::OnClose(DeviceFD fd) {}
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width,
u32 height, u32 stride, android::BufferTransformFlags transform,
const Common::Rectangle<int>& crop_rect,
std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) {
const DAddr addr = nvmap.GetHandleAddress(buffer_handle);
LOG_TRACE(Service,
"Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
addr, offset, width, height, stride, format);
void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers) {
std::vector<Tegra::FramebufferConfig> output_layers;
std::vector<Service::Nvidia::NvFence> output_fences;
output_layers.reserve(sorted_layers.size());
output_fences.reserve(sorted_layers.size());
const Tegra::FramebufferConfig framebuffer{addr, offset, width, height,
stride, format, transform, crop_rect};
for (auto& layer : sorted_layers) {
output_layers.emplace_back(Tegra::FramebufferConfig{
.address = nvmap.GetHandleAddress(layer.buffer_handle),
.offset = layer.offset,
.width = layer.width,
.height = layer.height,
.stride = layer.stride,
.pixel_format = layer.format,
.transform_flags = layer.transform,
.crop_rect = layer.crop_rect,
.blending = ConvertBlending(layer.blending),
});
system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences);
for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) {
output_fences.push_back(layer.acquire_fence.fences[i]);
}
}
system.GPU().RequestComposite(std::move(output_layers), std::move(output_fences));
system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs());
system.GetPerfStats().EndSystemFrame();
system.GetPerfStats().BeginSystemFrame();

View File

@ -8,8 +8,7 @@
#include "common/common_types.h"
#include "common/math_util.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include "core/hle/service/nvnflinger/buffer_transform_flags.h"
#include "core/hle/service/nvnflinger/pixel_format.h"
#include "core/hle/service/nvnflinger/hwc_layer.h"
namespace Service::Nvidia::NvCore {
class Container;
@ -35,11 +34,8 @@ public:
void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
/// Performs a screen flip, drawing the buffer pointed to by the handle.
void flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height,
u32 stride, android::BufferTransformFlags transform,
const Common::Rectangle<int>& crop_rect,
std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences);
/// Performs a screen flip, compositing each buffer.
void Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers);
Kernel::KEvent* QueryEvent(u32 event_id) override;

View File

@ -8,6 +8,7 @@
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
#include "video_core/host1x/host1x.h"
#include "video_core/renderer_base.h"
namespace Service::Nvidia::Devices {
@ -21,13 +22,8 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
switch (command.group) {
case 0x0:
switch (command.cmd) {
case 0x1: {
auto& host1x_file = core.Host1xDeviceFile();
if (!host1x_file.fd_to_id.contains(fd)) {
host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++;
}
case 0x1:
return WrapFixedVariable(this, &nvhost_nvdec::Submit, input, output, fd);
}
case 0x2:
return WrapFixed(this, &nvhost_nvdec::GetSyncpoint, input, output);
case 0x3:
@ -72,15 +68,12 @@ void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started");
system.SetNVDECActive(true);
sessions[fd] = session_id;
host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint);
}
void nvhost_nvdec::OnClose(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
auto& host1x_file = core.Host1xDeviceFile();
const auto iter = host1x_file.fd_to_id.find(fd);
if (iter != host1x_file.fd_to_id.end()) {
system.GPU().ClearCdmaInstance(iter->second);
}
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec);
system.SetNVDECActive(false);
auto it = sessions.find(fd);
if (it != sessions.end()) {

View File

@ -55,8 +55,9 @@ std::size_t WriteVectors(std::span<u8> dst, const std::vector<T>& src, std::size
nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_,
NvCore::ChannelType channel_type_)
: nvdevice{system_}, core{core_}, syncpoint_manager{core.GetSyncpointManager()},
nvmap{core.GetNvMapFile()}, channel_type{channel_type_} {
: nvdevice{system_}, host1x{system_.Host1x()}, core{core_},
syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()},
channel_type{channel_type_} {
auto& syncpts_accumulated = core.Host1xDeviceFile().syncpts_accumulated;
if (syncpts_accumulated.empty()) {
channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false);
@ -95,24 +96,24 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De
offset += SliceVectors(data, syncpt_increments, params.syncpoint_count, offset);
offset += SliceVectors(data, fence_thresholds, params.fence_count, offset);
auto& gpu = system.GPU();
auto* session = core.GetSession(sessions[fd]);
if (gpu.UseNvdec()) {
for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
const SyncptIncr& syncpt_incr = syncpt_increments[i];
fence_thresholds[i] =
syncpoint_manager.IncrementSyncpointMaxExt(syncpt_incr.id, syncpt_incr.increments);
}
for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
const SyncptIncr& syncpt_incr = syncpt_increments[i];
fence_thresholds[i] =
syncpoint_manager.IncrementSyncpointMaxExt(syncpt_incr.id, syncpt_incr.increments);
}
for (const auto& cmd_buffer : command_buffers) {
const auto object = nvmap.GetHandle(cmd_buffer.memory_id);
ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
session->process->GetMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(),
cmdlist.size() * sizeof(u32));
gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist);
Core::Memory::CpuGuestMemory<Tegra::ChCommandHeader,
Core::Memory::GuestMemoryFlags::SafeRead>
cmdlist(session->process->GetMemory(), object->address + cmd_buffer.offset,
cmd_buffer.word_count);
host1x.PushEntries(fd, std::move(cmdlist));
}
// Some games expect command_buffers to be written back
offset = 0;
offset += WriteVectors(data, command_buffers, offset);

View File

@ -119,6 +119,7 @@ protected:
Kernel::KEvent* QueryEvent(u32 event_id) override;
Tegra::Host1x::Host1x& host1x;
u32 channel_syncpoint;
s32_le nvmap_fd{};
u32_le submit_timeout{};

View File

@ -7,6 +7,7 @@
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
#include "video_core/host1x/host1x.h"
#include "video_core/renderer_base.h"
namespace Service::Nvidia::Devices {
@ -21,13 +22,8 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
switch (command.group) {
case 0x0:
switch (command.cmd) {
case 0x1: {
auto& host1x_file = core.Host1xDeviceFile();
if (!host1x_file.fd_to_id.contains(fd)) {
host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++;
}
case 0x1:
return WrapFixedVariable(this, &nvhost_vic::Submit, input, output, fd);
}
case 0x2:
return WrapFixed(this, &nvhost_vic::GetSyncpoint, input, output);
case 0x3:
@ -70,14 +66,11 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
void nvhost_vic::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
sessions[fd] = session_id;
host1x.StartDevice(fd, Tegra::Host1x::ChannelType::VIC, channel_syncpoint);
}
void nvhost_vic::OnClose(DeviceFD fd) {
auto& host1x_file = core.Host1xDeviceFile();
const auto iter = host1x_file.fd_to_id.find(fd);
if (iter != host1x_file.fd_to_id.end()) {
system.GPU().ClearCdmaInstance(iter->second);
}
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::VIC);
sessions.erase(fd);
}

View File

@ -14,24 +14,20 @@
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
#include "core/hle/service/vi/layer/vi_layer.h"
#include "core/hle/service/vi/vi_results.h"
#include "video_core/gpu.h"
#include "video_core/host1x/host1x.h"
namespace Service::Nvnflinger {
namespace {
Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
std::unique_ptr<Kernel::KPageGroup>* out_page_group,
Core::System& system, u32 size) {
Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_group,
Core::System& system, u32 size) {
using Core::Memory::YUZU_PAGESIZE;
// Allocate memory for the system shared buffer.
// FIXME: Because the gmmu can only point to cpu addresses, we need
// to map this in the application space to allow it to be used.
// FIXME: Add proper smmu emulation.
// FIXME: This memory belongs to vi's .data section.
auto& kernel = system.Kernel();
auto* process = system.ApplicationProcess();
auto& page_table = process->GetPageTable();
// Hold a temporary page group reference while we try to map it.
auto pg = std::make_unique<Kernel::KPageGroup>(
@ -43,6 +39,30 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure,
Kernel::KMemoryManager::Direction::FromBack)));
// Fill the output data with red.
for (auto& block : *pg) {
u32* start = system.DeviceMemory().GetPointer<u32>(block.GetAddress());
u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
for (; start < end; start++) {
*start = 0xFF0000FF;
}
}
// Return the mapped page group.
*out_page_group = std::move(pg);
// We succeeded.
R_SUCCEED();
}
Result MapSharedBufferIntoProcessAddressSpace(Common::ProcessAddress* out_map_address,
std::unique_ptr<Kernel::KPageGroup>& pg,
Kernel::KProcess* process, Core::System& system) {
using Core::Memory::YUZU_PAGESIZE;
auto& page_table = process->GetPageTable();
// Get bounds of where mapping is possible.
const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart());
const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE;
@ -64,9 +84,6 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
// Return failure, if necessary
R_UNLESS(i < 64, res);
// Return the mapped page group.
*out_page_group = std::move(pg);
// We succeeded.
R_SUCCEED();
}
@ -135,6 +152,13 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::D
R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd));
}
void FreeHandle(u32 handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd) {
auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
ASSERT(nvmap != nullptr);
R_ASSERT(FreeNvMapHandle(*nvmap, handle, nvmap_fd));
}
constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888;
constexpr u32 SharedBufferBlockLinearBpp = 4;
@ -186,53 +210,97 @@ FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& fli
FbShareBufferManager::~FbShareBufferManager() = default;
Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u64 display_id) {
Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id,
u64* out_layer_handle, u64 display_id,
LayerBlending blending) {
std::scoped_lock lk{m_guard};
// Ensure we have not already created a buffer.
R_UNLESS(m_buffer_id == 0, VI::ResultOperationFailed);
// Ensure we haven't already created.
const u64 aruid = owner_process->GetProcessId();
R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
// Allocate memory and space for the shared buffer.
Common::ProcessAddress map_address;
R_TRY(AllocateIoForProcessAddressSpace(std::addressof(map_address),
std::addressof(m_buffer_page_group), m_system,
SharedBufferSize));
// Allocate memory for the shared buffer if needed.
if (!m_buffer_page_group) {
R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system,
SharedBufferSize));
// Record buffer id.
m_buffer_id = m_next_buffer_id++;
// Record display id.
m_display_id = display_id;
}
// Map into process.
Common::ProcessAddress map_address{};
R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group,
owner_process, m_system));
// Create new session.
auto [it, was_emplaced] = m_sessions.emplace(aruid, FbShareSession{});
auto& session = it->second;
auto& container = m_nvdrv->GetContainer();
m_session_id = container.OpenSession(m_system.ApplicationProcess());
m_nvmap_fd = m_nvdrv->Open("/dev/nvmap", m_session_id);
session.session_id = container.OpenSession(owner_process);
session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id);
// Create an nvmap handle for the buffer and assign the memory to it.
R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd,
map_address, SharedBufferSize));
// Record the display id.
m_display_id = display_id;
R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv,
session.nvmap_fd, map_address, SharedBufferSize));
// Create and open a layer for the display.
m_layer_id = m_flinger.CreateLayer(m_display_id).value();
m_flinger.OpenLayer(m_layer_id);
// Set up the buffer.
m_buffer_id = m_next_buffer_id++;
session.layer_id = m_flinger.CreateLayer(m_display_id, blending).value();
m_flinger.OpenLayer(session.layer_id);
// Get the layer.
VI::Layer* layer = m_flinger.FindLayer(m_display_id, m_layer_id);
VI::Layer* layer = m_flinger.FindLayer(m_display_id, session.layer_id);
ASSERT(layer != nullptr);
// Get the producer and set preallocated buffers.
auto& producer = layer->GetBufferQueue();
MakeGraphicBuffer(producer, 0, m_buffer_nvmap_handle);
MakeGraphicBuffer(producer, 1, m_buffer_nvmap_handle);
MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle);
MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle);
// Assign outputs.
*out_buffer_id = m_buffer_id;
*out_layer_id = m_layer_id;
*out_layer_handle = session.layer_id;
// We succeeded.
R_SUCCEED();
}
void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) {
std::scoped_lock lk{m_guard};
if (m_buffer_id == 0) {
return;
}
const u64 aruid = owner_process->GetProcessId();
const auto it = m_sessions.find(aruid);
if (it == m_sessions.end()) {
return;
}
auto& session = it->second;
// Destroy the layer.
m_flinger.DestroyLayer(session.layer_id);
// Close nvmap handle.
FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
// Close nvmap device.
m_nvdrv->Close(session.nvmap_fd);
// Close session.
auto& container = m_nvdrv->GetContainer();
container.CloseSession(session.session_id);
// Erase.
m_sessions.erase(it);
}
Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
s32* out_nvmap_handle,
SharedMemoryPoolLayout* out_pool_layout,
@ -242,17 +310,18 @@ Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound);
R_UNLESS(m_sessions.contains(applet_resource_user_id), VI::ResultNotFound);
*out_pool_layout = SharedBufferPoolLayout;
*out_buffer_size = SharedBufferSize;
*out_nvmap_handle = m_buffer_nvmap_handle;
*out_nvmap_handle = m_sessions[applet_resource_user_id].buffer_nvmap_handle;
R_SUCCEED();
}
Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) {
// Ensure the layer id is valid.
R_UNLESS(m_layer_id > 0 && layer_id == m_layer_id, VI::ResultNotFound);
R_UNLESS(layer_id > 0, VI::ResultNotFound);
// Get the layer.
VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id);
@ -309,6 +378,10 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
android::Status::NoError,
VI::ResultOperationFailed);
ON_RESULT_FAILURE {
producer.CancelBuffer(static_cast<s32>(slot), fence);
};
// Queue the buffer to the producer.
android::QueueBufferInput input{};
android::QueueBufferOutput output{};
@ -342,4 +415,33 @@ Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadab
R_SUCCEED();
}
Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
Common::ScratchBuffer<u32> scratch;
// TODO: this could be optimized
s64 e = -1280 * 768 * 4;
for (auto& block : *m_buffer_page_group) {
u8* start = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress());
u8* end = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress() + block.GetSize());
for (; start < end; start++) {
*start = 0;
if (e >= 0 && e < static_cast<s64>(capture_buffer.size())) {
*start = capture_buffer[e];
}
e++;
}
m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) {
m_system.GPU().InvalidateRegion(addr, end - start);
});
}
*out_was_written = true;
*out_layer_index = 1;
R_SUCCEED();
}
} // namespace Service::Nvnflinger

View File

@ -3,9 +3,12 @@
#pragma once
#include <map>
#include "common/math_util.h"
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/nvnflinger/ui/fence.h"
@ -29,13 +32,18 @@ struct SharedMemoryPoolLayout {
};
static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
struct FbShareSession;
class FbShareBufferManager final {
public:
explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
std::shared_ptr<Nvidia::Module> nvdrv);
~FbShareBufferManager();
Result Initialize(u64* out_buffer_id, u64* out_layer_handle, u64 display_id);
Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle,
u64 display_id, LayerBlending blending);
void Finalize(Kernel::KProcess* owner_process);
Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
u64 applet_resource_user_id);
@ -45,6 +53,8 @@ public:
u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
private:
Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
@ -52,11 +62,8 @@ private:
u64 m_next_buffer_id = 1;
u64 m_display_id = 0;
u64 m_buffer_id = 0;
u64 m_layer_id = 0;
u32 m_buffer_nvmap_handle = 0;
SharedMemoryPoolLayout m_pool_layout = {};
Nvidia::DeviceFD m_nvmap_fd = {};
Nvidia::NvCore::SessionId m_session_id = {};
std::map<u64, FbShareSession> m_sessions;
std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
std::mutex m_guard;
@ -65,4 +72,11 @@ private:
std::shared_ptr<Nvidia::Module> m_nvdrv;
};
struct FbShareSession {
Nvidia::DeviceFD nvmap_fd = {};
Nvidia::NvCore::SessionId session_id = {};
u64 layer_id = {};
u32 buffer_nvmap_handle = 0;
};
} // namespace Service::Nvnflinger

View File

@ -0,0 +1,216 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <boost/container/small_vector.hpp>
#include "common/microprofile.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvnflinger/buffer_item.h"
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
#include "core/hle/service/nvnflinger/hardware_composer.h"
#include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
#include "core/hle/service/vi/display/vi_display.h"
#include "core/hle/service/vi/layer/vi_layer.h"
namespace Service::Nvnflinger {
namespace {
s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) {
if (swap_interval <= 0) {
// As an extension, treat nonpositive swap interval as speed multiplier.
if (out_speed_scale) {
*out_speed_scale = 2.f * static_cast<f32>(1 - swap_interval);
}
swap_interval = 1;
}
if (swap_interval >= 5) {
// As an extension, treat high swap interval as precise speed control.
if (out_speed_scale) {
*out_speed_scale = static_cast<f32>(swap_interval) / 100.f;
}
swap_interval = 1;
}
return swap_interval;
}
} // namespace
HardwareComposer::HardwareComposer() = default;
HardwareComposer::~HardwareComposer() = default;
u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
Nvidia::Devices::nvdisp_disp0& nvdisp) {
boost::container::small_vector<HwcLayer, 2> composition_stack;
// Set default speed limit to 100%.
*out_speed_scale = 1.0f;
// Determine the number of vsync periods to wait before composing again.
std::optional<s32> swap_interval{};
bool has_acquired_buffer{};
// Acquire all necessary framebuffers.
for (size_t i = 0; i < display.GetNumLayers(); i++) {
auto& layer = display.GetLayer(i);
auto layer_id = layer.GetLayerId();
// Try to fetch the framebuffer (either new or stale).
const auto result = this->CacheFramebufferLocked(layer, layer_id);
// If we failed, skip this layer.
if (result == CacheStatus::NoBufferAvailable) {
continue;
}
// If we acquired a new buffer, we need to present.
if (result == CacheStatus::BufferAcquired) {
has_acquired_buffer = true;
}
const auto& buffer = m_framebuffers[layer_id];
const auto& item = buffer.item;
const auto& igbp_buffer = *item.graphic_buffer;
// TODO: get proper Z-index from layer
composition_stack.emplace_back(HwcLayer{
.buffer_handle = igbp_buffer.BufferId(),
.offset = igbp_buffer.Offset(),
.format = igbp_buffer.ExternalFormat(),
.width = igbp_buffer.Width(),
.height = igbp_buffer.Height(),
.stride = igbp_buffer.Stride(),
.z_index = 0,
.blending = layer.GetBlending(),
.transform = static_cast<android::BufferTransformFlags>(item.transform),
.crop_rect = item.crop,
.acquire_fence = item.fence,
});
// We need to compose again either before this frame is supposed to
// be released, or exactly on the vsync period it should be released.
const s32 item_swap_interval = NormalizeSwapInterval(out_speed_scale, item.swap_interval);
// TODO: handle cases where swap intervals are relatively prime. So far,
// only swap intervals of 0, 1 and 2 have been observed, but if 3 were
// to be introduced, this would cause an issue.
if (swap_interval) {
swap_interval = std::min(*swap_interval, item_swap_interval);
} else {
swap_interval = item_swap_interval;
}
}
// If any new buffers were acquired, we can present.
if (has_acquired_buffer) {
// Sort by Z-index.
std::stable_sort(composition_stack.begin(), composition_stack.end(),
[&](auto& l, auto& r) { return l.z_index < r.z_index; });
// Composite.
nvdisp.Composite(composition_stack);
}
// Render MicroProfile.
MicroProfileFlip();
// Advance by at least one frame.
const u32 frame_advance = swap_interval.value_or(1);
m_frame_number += frame_advance;
// Release any necessary framebuffers.
for (auto& [layer_id, framebuffer] : m_framebuffers) {
if (framebuffer.release_frame_number > m_frame_number) {
// Not yet ready to release this framebuffer.
continue;
}
if (!framebuffer.is_acquired) {
// Already released.
continue;
}
if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
// TODO: support release fence
// This is needed to prevent screen tearing
layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
framebuffer.is_acquired = false;
}
}
return frame_advance;
}
void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) {
// Check if we are tracking a slot with this layer_id.
const auto it = m_framebuffers.find(layer_id);
if (it == m_framebuffers.end()) {
return;
}
// Try to release the buffer item.
auto* const layer = display.FindLayer(layer_id);
if (layer && it->second.is_acquired) {
layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence());
}
// Erase the slot.
m_framebuffers.erase(it);
}
bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) {
// Attempt the update.
const auto status = layer.GetConsumer().AcquireBuffer(&framebuffer.item, {}, false);
if (status != android::Status::NoError) {
return false;
}
// We succeeded, so set the new release frame info.
framebuffer.release_frame_number =
NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval);
framebuffer.is_acquired = true;
return true;
}
HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer& layer,
LayerId layer_id) {
// Check if this framebuffer is already present.
const auto it = m_framebuffers.find(layer_id);
if (it != m_framebuffers.end()) {
// If it's currently still acquired, we are done.
if (it->second.is_acquired) {
return CacheStatus::CachedBufferReused;
}
// Try to acquire a new item.
if (this->TryAcquireFramebufferLocked(layer, it->second)) {
// We got a new item.
return CacheStatus::BufferAcquired;
} else {
// We didn't acquire a new item, but we can reuse the slot.
return CacheStatus::CachedBufferReused;
}
}
// Framebuffer is not present, so try to create it.
Framebuffer framebuffer{};
if (this->TryAcquireFramebufferLocked(layer, framebuffer)) {
// Move the buffer item into a new slot.
m_framebuffers.emplace(layer_id, std::move(framebuffer));
// We succeeded.
return CacheStatus::BufferAcquired;
}
// We couldn't acquire the buffer item, so don't create a slot.
return CacheStatus::NoBufferAvailable;
}
} // namespace Service::Nvnflinger

View File

@ -0,0 +1,59 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <memory>
#include <boost/container/flat_map.hpp>
#include "core/hle/service/nvnflinger/buffer_item.h"
namespace Service::Nvidia::Devices {
class nvdisp_disp0;
}
namespace Service::VI {
class Display;
class Layer;
} // namespace Service::VI
namespace Service::Nvnflinger {
using LayerId = u64;
class HardwareComposer {
public:
explicit HardwareComposer();
~HardwareComposer();
u32 ComposeLocked(f32* out_speed_scale, VI::Display& display,
Nvidia::Devices::nvdisp_disp0& nvdisp);
void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
private:
// TODO: do we want to track frame number in vi instead?
u64 m_frame_number{0};
private:
using ReleaseFrameNumber = u64;
struct Framebuffer {
android::BufferItem item{};
ReleaseFrameNumber release_frame_number{};
bool is_acquired{false};
};
enum class CacheStatus : u32 {
NoBufferAvailable,
BufferAcquired,
CachedBufferReused,
};
boost::container::flat_map<LayerId, Framebuffer> m_framebuffers{};
private:
bool TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer);
CacheStatus CacheFramebufferLocked(VI::Layer& layer, LayerId layer_id);
};
} // namespace Service::Nvnflinger

View File

@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "common/math_util.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvnflinger/buffer_transform_flags.h"
#include "core/hle/service/nvnflinger/pixel_format.h"
#include "core/hle/service/nvnflinger/ui/fence.h"
namespace Service::Nvnflinger {
// hwc_layer_t::blending values
enum class LayerBlending : u32 {
// No blending
None = 0x100,
// ONE / ONE_MINUS_SRC_ALPHA
Premultiplied = 0x105,
// SRC_ALPHA / ONE_MINUS_SRC_ALPHA
Coverage = 0x405,
};
struct HwcLayer {
u32 buffer_handle;
u32 offset;
android::PixelFormat format;
u32 width;
u32 height;
u32 stride;
s32 z_index;
LayerBlending blending;
android::BufferTransformFlags transform;
Common::Rectangle<int> crop_rect;
android::Fence acquire_fence;
};
} // namespace Service::Nvnflinger

View File

@ -18,6 +18,7 @@
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
#include "core/hle/service/nvnflinger/hardware_composer.h"
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
@ -156,7 +157,7 @@ bool Nvnflinger::CloseDisplay(u64 display_id) {
return true;
}
std::optional<u64> Nvnflinger::CreateLayer(u64 display_id) {
std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) {
const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id);
@ -165,13 +166,14 @@ std::optional<u64> Nvnflinger::CreateLayer(u64 display_id) {
}
const u64 layer_id = next_layer_id++;
CreateLayerAtId(*display, layer_id);
CreateLayerAtId(*display, layer_id, blending);
return layer_id;
}
void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending) {
const auto buffer_id = next_buffer_queue_id++;
display.CreateLayer(layer_id, buffer_id, nvdrv->container);
display.FindLayer(layer_id)->SetBlending(blending);
}
bool Nvnflinger::OpenLayer(u64 layer_id) {
@ -279,45 +281,18 @@ void Nvnflinger::Compose() {
SCOPE_EXIT({ display.SignalVSyncEvent(); });
// Don't do anything for displays without layers.
if (!display.HasLayers())
continue;
// TODO(Subv): Support more than 1 layer.
VI::Layer& layer = display.GetLayer(0);
android::BufferItem buffer{};
const auto status = layer.GetConsumer().AcquireBuffer(&buffer, {}, false);
if (status != android::Status::NoError) {
if (!display.HasLayers()) {
continue;
}
const auto& igbp_buffer = *buffer.graphic_buffer;
if (!system.IsPoweredOn()) {
return; // We are likely shutting down
}
// Now send the buffer to the GPU for drawing.
// TODO(Subv): Support more than just disp0. The display device selection is probably based
// on which display we're drawing (Default, Internal, External, etc)
auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
ASSERT(nvdisp);
Common::Rectangle<int> crop_rect{
static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()),
static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())};
nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(),
igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(),
static_cast<android::BufferTransformFlags>(buffer.transform), crop_rect,
buffer.fence.fences, buffer.fence.num_fences);
MicroProfileFlip();
swap_interval = buffer.swap_interval;
layer.GetConsumer().ReleaseBuffer(buffer, android::Fence::NoFence());
swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp);
}
}
@ -334,15 +309,16 @@ s64 Nvnflinger::GetNextTicks() const {
speed_scale = 0.01f;
}
}
// Adjust by speed limit determined during composition.
speed_scale /= compose_speed_scale;
if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
// Run at intended presentation rate during video playback.
speed_scale = 1.f;
}
// As an extension, treat nonpositive swap interval as framerate multiplier.
const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval)
: 60.f / static_cast<f32>(swap_interval);
const f32 effective_fps = 60.f / static_cast<f32>(swap_interval);
return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
}

View File

@ -15,6 +15,7 @@
#include "common/thread.h"
#include "core/hle/result.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nvnflinger/hwc_layer.h"
namespace Common {
class Event;
@ -46,6 +47,7 @@ class BufferQueueProducer;
namespace Service::Nvnflinger {
class FbShareBufferManager;
class HardwareComposer;
class HosBinderDriverServer;
class Nvnflinger final {
@ -71,7 +73,8 @@ public:
/// Creates a layer on the specified display and returns the layer ID.
///
/// If an invalid display ID is specified, then an empty optional is returned.
[[nodiscard]] std::optional<u64> CreateLayer(u64 display_id);
[[nodiscard]] std::optional<u64> CreateLayer(u64 display_id,
LayerBlending blending = LayerBlending::None);
/// Opens a layer on all displays for the given layer ID.
bool OpenLayer(u64 layer_id);
@ -127,7 +130,7 @@ private:
[[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
/// Creates a layer with the specified layer ID in the desired display.
void CreateLayerAtId(VI::Display& display, u64 layer_id);
void CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending);
void SplitVSync(std::stop_token stop_token);
@ -143,6 +146,7 @@ private:
u32 next_buffer_queue_id = 1;
s32 swap_interval = 1;
f32 compose_speed_scale = 1.0f;
bool is_abandoned = false;

View File

@ -22,7 +22,7 @@ LocalSystemClockContextWriter::LocalSystemClockContextWriter(Core::System& syste
SharedMemory& shared_memory)
: m_system{system}, m_shared_memory{shared_memory} {}
Result LocalSystemClockContextWriter::Write(SystemClockContext& context) {
Result LocalSystemClockContextWriter::Write(const SystemClockContext& context) {
if (m_in_use) {
R_SUCCEED_IF(context == m_context);
m_context = context;
@ -43,7 +43,7 @@ NetworkSystemClockContextWriter::NetworkSystemClockContextWriter(Core::System& s
SystemClockCore& system_clock)
: m_system{system}, m_shared_memory{shared_memory}, m_system_clock{system_clock} {}
Result NetworkSystemClockContextWriter::Write(SystemClockContext& context) {
Result NetworkSystemClockContextWriter::Write(const SystemClockContext& context) {
s64 time{};
[[maybe_unused]] auto res = m_system_clock.GetCurrentTime(&time);
@ -66,7 +66,7 @@ EphemeralNetworkSystemClockContextWriter::EphemeralNetworkSystemClockContextWrit
Core::System& system)
: m_system{system} {}
Result EphemeralNetworkSystemClockContextWriter::Write(SystemClockContext& context) {
Result EphemeralNetworkSystemClockContextWriter::Write(const SystemClockContext& context) {
if (m_in_use) {
R_SUCCEED_IF(context == m_context);
m_context = context;

View File

@ -24,7 +24,7 @@ private:
public:
virtual ~ContextWriter() = default;
virtual Result Write(SystemClockContext& context) = 0;
virtual Result Write(const SystemClockContext& context) = 0;
void SignalAllNodes();
void Link(OperationEvent& operation_event);
@ -37,7 +37,7 @@ class LocalSystemClockContextWriter : public ContextWriter {
public:
explicit LocalSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory);
Result Write(SystemClockContext& context) override;
Result Write(const SystemClockContext& context) override;
private:
Core::System& m_system;
@ -52,7 +52,7 @@ public:
explicit NetworkSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory,
SystemClockCore& system_clock);
Result Write(SystemClockContext& context) override;
Result Write(const SystemClockContext& context) override;
private:
Core::System& m_system;
@ -67,7 +67,7 @@ class EphemeralNetworkSystemClockContextWriter : public ContextWriter {
public:
EphemeralNetworkSystemClockContextWriter(Core::System& system);
Result Write(SystemClockContext& context) override;
Result Write(const SystemClockContext& context) override;
private:
Core::System& m_system;

View File

@ -5,7 +5,7 @@
namespace Service::PSC::Time {
void StandardLocalSystemClockCore::Initialize(SystemClockContext& context, s64 time) {
void StandardLocalSystemClockCore::Initialize(const SystemClockContext& context, s64 time) {
SteadyClockTimePoint time_point{};
if (GetCurrentTimePoint(time_point) == ResultSuccess &&
context.steady_time_point.IdMatches(time_point)) {

View File

@ -17,7 +17,7 @@ public:
: SystemClockCore{steady_clock} {}
~StandardLocalSystemClockCore() override = default;
void Initialize(SystemClockContext& context, s64 time);
void Initialize(const SystemClockContext& context, s64 time);
};
} // namespace Service::PSC::Time

View File

@ -5,7 +5,7 @@
namespace Service::PSC::Time {
void StandardNetworkSystemClockCore::Initialize(SystemClockContext& context, s64 accuracy) {
void StandardNetworkSystemClockCore::Initialize(const SystemClockContext& context, s64 accuracy) {
if (SetContextAndWrite(context) != ResultSuccess) {
LOG_ERROR(Service_Time, "Failed to SetContext");
}

View File

@ -19,7 +19,7 @@ public:
: SystemClockCore{steady_clock} {}
~StandardNetworkSystemClockCore() override = default;
void Initialize(SystemClockContext& context, s64 accuracy);
void Initialize(const SystemClockContext& context, s64 accuracy);
bool IsAccuracySufficient();
private:

View File

@ -46,7 +46,7 @@ Result StandardUserSystemClockCore::GetContext(SystemClockContext& out_context)
R_RETURN(m_local_system_clock.GetContext(out_context));
}
Result StandardUserSystemClockCore::SetContext(SystemClockContext& context) {
Result StandardUserSystemClockCore::SetContext(const SystemClockContext& context) {
R_RETURN(ResultNotImplemented);
}

View File

@ -36,7 +36,7 @@ public:
Result SetAutomaticCorrection(bool automatic_correction);
Result GetContext(SystemClockContext& out_context) const override;
Result SetContext(SystemClockContext& context) override;
Result SetContext(const SystemClockContext& context) override;
Result GetTimePoint(SteadyClockTimePoint& out_time_point);
void SetTimePointAndSignal(SteadyClockTimePoint& time_point);

View File

@ -51,12 +51,12 @@ Result SystemClockCore::GetContext(SystemClockContext& out_context) const {
R_SUCCEED();
}
Result SystemClockCore::SetContext(SystemClockContext& context) {
Result SystemClockCore::SetContext(const SystemClockContext& context) {
m_context = context;
R_SUCCEED();
}
Result SystemClockCore::SetContextAndWrite(SystemClockContext& context) {
Result SystemClockCore::SetContextAndWrite(const SystemClockContext& context) {
R_TRY(SetContext(context));
if (m_context_writer) {

View File

@ -41,8 +41,8 @@ public:
}
virtual Result GetContext(SystemClockContext& out_context) const;
virtual Result SetContext(SystemClockContext& context);
Result SetContextAndWrite(SystemClockContext& context);
virtual Result SetContext(const SystemClockContext& context);
Result SetContextAndWrite(const SystemClockContext& context);
void LinkOperationEvent(OperationEvent& operation_event);

View File

@ -78,8 +78,9 @@ Result ServiceManager::GetStaticServiceAsServiceManager(OutInterface<StaticServi
}
Result ServiceManager::SetupStandardSteadyClockCore(bool is_rtc_reset_detected,
Common::UUID& clock_source_id, s64 rtc_offset,
s64 internal_offset, s64 test_offset) {
const Common::UUID& clock_source_id,
s64 rtc_offset, s64 internal_offset,
s64 test_offset) {
LOG_DEBUG(Service_Time,
"called. is_rtc_reset_detected={} clock_source_id={} rtc_offset={} "
"internal_offset={} test_offset={}",
@ -102,7 +103,8 @@ Result ServiceManager::SetupStandardSteadyClockCore(bool is_rtc_reset_detected,
R_SUCCEED();
}
Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time) {
Result ServiceManager::SetupStandardLocalSystemClockCore(const SystemClockContext& context,
s64 time) {
LOG_DEBUG(Service_Time,
"called. context={} context.steady_time_point.clock_source_id={} time={}", context,
context.steady_time_point.clock_source_id.RawString(), time);
@ -114,7 +116,7 @@ Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& con
R_SUCCEED();
}
Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& context,
Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext context,
s64 accuracy) {
LOG_DEBUG(Service_Time, "called. context={} steady_time_point.clock_source_id={} accuracy={}",
context, context.steady_time_point.clock_source_id.RawString(), accuracy);
@ -131,7 +133,7 @@ Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& c
}
Result ServiceManager::SetupStandardUserSystemClockCore(bool automatic_correction,
SteadyClockTimePoint& time_point) {
SteadyClockTimePoint time_point) {
LOG_DEBUG(Service_Time, "called. automatic_correction={} time_point={} clock_source_id={}",
automatic_correction, time_point, time_point.clock_source_id.RawString());
@ -144,9 +146,9 @@ Result ServiceManager::SetupStandardUserSystemClockCore(bool automatic_correctio
R_SUCCEED();
}
Result ServiceManager::SetupTimeZoneServiceCore(LocationName& name, RuleVersion& rule_version,
u32 location_count,
SteadyClockTimePoint& time_point,
Result ServiceManager::SetupTimeZoneServiceCore(const LocationName& name,
const RuleVersion& rule_version, u32 location_count,
const SteadyClockTimePoint& time_point,
InBuffer<BufferAttr_HipcAutoSelect> rule_buffer) {
LOG_DEBUG(Service_Time,
"called. name={} rule_version={} location_count={} time_point={} "

View File

@ -34,14 +34,15 @@ public:
Result GetStaticServiceAsAdmin(OutInterface<StaticService> out_service);
Result GetStaticServiceAsRepair(OutInterface<StaticService> out_service);
Result GetStaticServiceAsServiceManager(OutInterface<StaticService> out_service);
Result SetupStandardSteadyClockCore(bool is_rtc_reset_detected, Common::UUID& clock_source_id,
s64 rtc_offset, s64 internal_offset, s64 test_offset);
Result SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time);
Result SetupStandardNetworkSystemClockCore(SystemClockContext& context, s64 accuracy);
Result SetupStandardSteadyClockCore(bool is_rtc_reset_detected,
const Common::UUID& clock_source_id, s64 rtc_offset,
s64 internal_offset, s64 test_offset);
Result SetupStandardLocalSystemClockCore(const SystemClockContext& context, s64 time);
Result SetupStandardNetworkSystemClockCore(SystemClockContext context, s64 accuracy);
Result SetupStandardUserSystemClockCore(bool automatic_correction,
SteadyClockTimePoint& time_point);
Result SetupTimeZoneServiceCore(LocationName& name, RuleVersion& rule_version,
u32 location_count, SteadyClockTimePoint& time_point,
SteadyClockTimePoint time_point);
Result SetupTimeZoneServiceCore(const LocationName& name, const RuleVersion& rule_version,
u32 location_count, const SteadyClockTimePoint& time_point,
InBuffer<BufferAttr_HipcAutoSelect> rule_buffer);
Result SetupEphemeralNetworkSystemClockCore();
Result GetStandardLocalClockOperationEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);

View File

@ -51,11 +51,11 @@ SharedMemory::SharedMemory(Core::System& system)
std::memset(m_shared_memory_ptr, 0, sizeof(*m_shared_memory_ptr));
}
void SharedMemory::SetLocalSystemContext(SystemClockContext& context) {
void SharedMemory::SetLocalSystemContext(const SystemClockContext& context) {
WriteToLockFreeAtomicType(&m_shared_memory_ptr->local_system_clock_contexts, context);
}
void SharedMemory::SetNetworkSystemContext(SystemClockContext& context) {
void SharedMemory::SetNetworkSystemContext(const SystemClockContext& context) {
WriteToLockFreeAtomicType(&m_shared_memory_ptr->network_system_clock_contexts, context);
}
@ -64,7 +64,7 @@ void SharedMemory::SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 ti
{time_point, clock_source_id});
}
void SharedMemory::SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point) {
void SharedMemory::SetContinuousAdjustment(const ContinuousAdjustmentTimePoint& time_point) {
WriteToLockFreeAtomicType(&m_shared_memory_ptr->continuous_adjustment_time_points, time_point);
}

View File

@ -54,10 +54,10 @@ public:
return m_k_shared_memory;
}
void SetLocalSystemContext(SystemClockContext& context);
void SetNetworkSystemContext(SystemClockContext& context);
void SetLocalSystemContext(const SystemClockContext& context);
void SetNetworkSystemContext(const SystemClockContext& context);
void SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_diff);
void SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point);
void SetContinuousAdjustment(const ContinuousAdjustmentTimePoint& time_point);
void SetAutomaticCorrection(bool automatic_correction);
void UpdateBaseTime(s64 time);

View File

@ -198,8 +198,8 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
R_SUCCEED();
}
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(Out<s64> out_time,
SystemClockContext& context) {
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
Out<s64> out_time, const SystemClockContext& context) {
SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); });
R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized);
@ -231,10 +231,9 @@ Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType t
R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
}
Result StaticService::GetClockSnapshotFromSystemClockContext(TimeType type,
OutClockSnapshot out_snapshot,
SystemClockContext& user_context,
SystemClockContext& network_context) {
Result StaticService::GetClockSnapshotFromSystemClockContext(
TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context,
const SystemClockContext& network_context) {
SCOPE_EXIT({
LOG_DEBUG(Service_Time,
"called. type={} user_context={} network_context={} out_snapshot={}", type,
@ -294,8 +293,9 @@ Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
}
Result StaticService::GetClockSnapshotImpl(OutClockSnapshot out_snapshot,
SystemClockContext& user_context,
SystemClockContext& network_context, TimeType type) {
const SystemClockContext& user_context,
const SystemClockContext& network_context,
TimeType type) {
out_snapshot->user_context = user_context;
out_snapshot->network_context = network_context;

View File

@ -55,18 +55,19 @@ public:
Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
Out<SteadyClockTimePoint> out_time_point);
Result CalculateMonotonicSystemClockBaseTimePoint(Out<s64> out_time,
SystemClockContext& context);
const SystemClockContext& context);
Result GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type);
Result GetClockSnapshotFromSystemClockContext(TimeType type, OutClockSnapshot out_snapshot,
SystemClockContext& user_context,
SystemClockContext& network_context);
const SystemClockContext& user_context,
const SystemClockContext& network_context);
Result CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
InClockSnapshot a, InClockSnapshot b);
Result CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, InClockSnapshot b);
private:
Result GetClockSnapshotImpl(OutClockSnapshot out_snapshot, SystemClockContext& user_context,
SystemClockContext& network_context, TimeType type);
Result GetClockSnapshotImpl(OutClockSnapshot out_snapshot,
const SystemClockContext& user_context,
const SystemClockContext& network_context, TimeType type);
Core::System& m_system;
StaticServiceSetupInfo m_setup_info;

View File

@ -53,7 +53,7 @@ Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) {
R_RETURN(m_clock_core.GetContext(*out_context));
}
Result SystemClock::SetSystemClockContext(SystemClockContext& context) {
Result SystemClock::SetSystemClockContext(const SystemClockContext& context) {
LOG_DEBUG(Service_Time, "called. context={}", context);
R_UNLESS(m_can_write_clock, ResultPermissionDenied);

View File

@ -26,7 +26,7 @@ public:
Result GetCurrentTime(Out<s64> out_time);
Result SetCurrentTime(s64 time);
Result GetSystemClockContext(Out<SystemClockContext> out_context);
Result SetSystemClockContext(SystemClockContext& context);
Result SetSystemClockContext(const SystemClockContext& context);
Result GetOperationEventReadableHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
private:

View File

@ -55,7 +55,7 @@ constexpr bool GetTimeZoneTime(s64& out_time, const Tz::Rule& rule, s64 time, s3
}
} // namespace
void TimeZone::SetTimePoint(SteadyClockTimePoint& time_point) {
void TimeZone::SetTimePoint(const SteadyClockTimePoint& time_point) {
std::scoped_lock l{m_mutex};
m_steady_clock_time_point = time_point;
}
@ -65,7 +65,7 @@ void TimeZone::SetTotalLocationNameCount(u32 count) {
m_total_location_name_count = count;
}
void TimeZone::SetRuleVersion(RuleVersion& rule_version) {
void TimeZone::SetRuleVersion(const RuleVersion& rule_version) {
std::scoped_lock l{m_mutex};
m_rule_version = rule_version;
}
@ -123,7 +123,7 @@ Result TimeZone::ToCalendarTimeWithMyRule(CalendarTime& calendar_time,
R_RETURN(ToCalendarTimeImpl(calendar_time, calendar_additional, time, m_my_rule));
}
Result TimeZone::ParseBinary(LocationName& name, std::span<const u8> binary) {
Result TimeZone::ParseBinary(const LocationName& name, std::span<const u8> binary) {
std::scoped_lock l{m_mutex};
Tz::Rule tmp_rule{};

View File

@ -23,9 +23,9 @@ public:
m_initialized = true;
}
void SetTimePoint(SteadyClockTimePoint& time_point);
void SetTimePoint(const SteadyClockTimePoint& time_point);
void SetTotalLocationNameCount(u32 count);
void SetRuleVersion(RuleVersion& rule_version);
void SetRuleVersion(const RuleVersion& rule_version);
Result GetLocationName(LocationName& out_name);
Result GetTotalLocationCount(u32& out_count);
Result GetRuleVersion(RuleVersion& out_rule_version);
@ -36,7 +36,7 @@ public:
const Tz::Rule& rule);
Result ToCalendarTimeWithMyRule(CalendarTime& calendar_time,
CalendarAdditionalInfo& calendar_additional, s64 time);
Result ParseBinary(LocationName& name, std::span<const u8> binary);
Result ParseBinary(const LocationName& name, std::span<const u8> binary);
Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary);
Result ToPosixTime(u32& out_count, std::span<s64> out_times, size_t out_times_max_count,
const CalendarTime& calendar, const Tz::Rule& rule);

View File

@ -42,7 +42,7 @@ Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_nam
R_RETURN(m_time_zone.GetLocationName(*out_location_name));
}
Result TimeZoneService::SetDeviceLocationName(LocationName& location_name) {
Result TimeZoneService::SetDeviceLocationName(const LocationName& location_name) {
LOG_DEBUG(Service_Time, "called. This function is not implemented!");
R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied);
@ -62,7 +62,7 @@ Result TimeZoneService::LoadLocationNameList(
R_RETURN(ResultNotImplemented);
}
Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, LocationName& location_name) {
Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, const LocationName& location_name) {
LOG_DEBUG(Service_Time, "called. This function is not implemented!");
R_RETURN(ResultNotImplemented);
@ -86,7 +86,7 @@ Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
}
Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(
LocationName& location_name, InBuffer<BufferAttr_HipcAutoSelect> binary) {
const LocationName& location_name, InBuffer<BufferAttr_HipcAutoSelect> binary) {
LOG_DEBUG(Service_Time, "called. location_name={}", location_name);
R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied);

View File

@ -31,16 +31,16 @@ public:
~TimeZoneService() override = default;
Result GetDeviceLocationName(Out<LocationName> out_location_name);
Result SetDeviceLocationName(LocationName& location_name);
Result SetDeviceLocationName(const LocationName& location_name);
Result GetTotalLocationNameCount(Out<u32> out_count);
Result LoadLocationNameList(Out<u32> out_count,
OutArray<LocationName, BufferAttr_HipcMapAlias> out_names,
u32 index);
Result LoadTimeZoneRule(OutRule out_rule, LocationName& location_name);
Result LoadTimeZoneRule(OutRule out_rule, const LocationName& location_name);
Result GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version);
Result GetDeviceLocationNameAndUpdatedTime(Out<LocationName> location_name,
Out<SteadyClockTimePoint> out_time_point);
Result SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name,
Result SetDeviceLocationNameWithTimeZoneRule(const LocationName& location_name,
InBuffer<BufferAttr_HipcAutoSelect> binary);
Result ParseTimeZoneBinary(OutRule out_rule, InBuffer<BufferAttr_HipcAutoSelect> binary);
Result GetDeviceLocationNameOperationEventReadableHandle(

View File

@ -549,13 +549,13 @@ public:
}
Result RegisterProcessHandle(ClientProcessId client_pid,
InCopyHandle<Kernel::KProcess>& process) {
InCopyHandle<Kernel::KProcess> process) {
// Register the process.
R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process.Get(), *client_pid));
}
Result RegisterProcessModuleInfo(ClientProcessId client_pid, u64 nrr_address, u64 nrr_size,
InCopyHandle<Kernel::KProcess>& process) {
InCopyHandle<Kernel::KProcess> process) {
// Validate the process.
R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));

View File

@ -16,6 +16,7 @@
#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
#include "core/hle/service/nvnflinger/hardware_composer.h"
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
#include "core/hle/service/vi/display/vi_display.h"
#include "core/hle/service/vi/layer/vi_layer.h"
@ -43,6 +44,7 @@ Display::Display(u64 id, std::string name_,
KernelHelpers::ServiceContext& service_context_, Core::System& system_)
: display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_},
service_context{service_context_} {
hardware_composer = std::make_unique<Nvnflinger::HardwareComposer>();
vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id));
}
@ -81,8 +83,6 @@ void Display::SignalVSyncEvent() {
void Display::CreateLayer(u64 layer_id, u32 binder_id,
Service::Nvidia::NvCore::Container& nv_core) {
ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment");
auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile());
auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer));

View File

@ -11,9 +11,14 @@
#include "common/common_types.h"
#include "core/hle/result.h"
namespace Core {
class System;
}
namespace Kernel {
class KEvent;
}
class KReadableEvent;
} // namespace Kernel
namespace Service::android {
class BufferQueueProducer;
@ -24,8 +29,9 @@ class ServiceContext;
}
namespace Service::Nvnflinger {
class HardwareComposer;
class HosBinderDriverServer;
}
} // namespace Service::Nvnflinger
namespace Service::Nvidia::NvCore {
class Container;
@ -118,6 +124,10 @@ public:
///
const Layer* FindLayer(u64 layer_id) const;
Nvnflinger::HardwareComposer& GetComposer() const {
return *hardware_composer;
}
private:
u64 display_id;
std::string name;
@ -125,6 +135,7 @@ private:
KernelHelpers::ServiceContext& service_context;
std::vector<std::unique_ptr<Layer>> layers;
std::unique_ptr<Nvnflinger::HardwareComposer> hardware_composer;
Kernel::KEvent* vsync_event{};
bool is_abandoned{};
};

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/vi/layer/vi_layer.h"
namespace Service::VI {
@ -8,8 +9,9 @@ namespace Service::VI {
Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
android::BufferQueueProducer& binder_,
std::shared_ptr<android::BufferItemConsumer>&& consumer_)
: layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_},
consumer{std::move(consumer_)}, open{false}, visible{true} {}
: layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
consumer_)},
blending{Nvnflinger::LayerBlending::None}, open{false}, visible{true} {}
Layer::~Layer() = default;

View File

@ -14,6 +14,10 @@ class BufferQueueCore;
class BufferQueueProducer;
} // namespace Service::android
namespace Service::Nvnflinger {
enum class LayerBlending : u32;
}
namespace Service::VI {
/// Represents a single display layer.
@ -92,12 +96,21 @@ public:
return !std::exchange(open, true);
}
Nvnflinger::LayerBlending GetBlending() {
return blending;
}
void SetBlending(Nvnflinger::LayerBlending b) {
blending = b;
}
private:
const u64 layer_id;
const u32 binder_id;
android::BufferQueueCore& core;
android::BufferQueueProducer& binder;
std::shared_ptr<android::BufferItemConsumer> consumer;
Service::Nvnflinger::LayerBlending blending;
bool open;
bool visible;
};

View File

@ -195,8 +195,9 @@ private:
void GetSharedBufferMemoryHandleId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 buffer_id = rp.PopRaw<u64>();
const u64 aruid = ctx.GetPID();
LOG_INFO(Service_VI, "called. buffer_id={:#x}", buffer_id);
LOG_INFO(Service_VI, "called. buffer_id={:#x}, aruid={:#x}", buffer_id, aruid);
struct OutputParameters {
s32 nvmap_handle;
@ -206,7 +207,7 @@ private:
OutputParameters out{};
Nvnflinger::SharedMemoryPoolLayout layout{};
const auto result = nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId(
&out.size, &out.nvmap_handle, &layout, buffer_id, 0);
&out.size, &out.nvmap_handle, &layout, buffer_id, aruid);
ctx.WriteBuffer(&layout, sizeof(layout));

View File

@ -64,6 +64,8 @@ public:
Memory(Memory&&) = default;
Memory& operator=(Memory&&) = delete;
static constexpr bool HAS_FLUSH_INVALIDATION = false;
/**
* Resets the state of the Memory system.
*/

View File

@ -9,6 +9,7 @@
#include "core/core_timing.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_process_page_table.h"
#include "core/hle/service/hid/hid_server.h"
#include "core/hle/service/sm/sm.h"
#include "core/memory.h"
@ -85,8 +86,12 @@ VAddr StandardVmCallbacks::SanitizeAddress(VAddr in) const {
if ((in < metadata.main_nso_extents.base ||
in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) &&
(in < metadata.heap_extents.base ||
in >= metadata.heap_extents.base + metadata.heap_extents.size)) {
LOG_ERROR(CheatEngine,
in >= metadata.heap_extents.base + metadata.heap_extents.size) &&
(in < metadata.alias_extents.base ||
in >= metadata.heap_extents.base + metadata.alias_extents.size) &&
(in < metadata.aslr_extents.base ||
in >= metadata.heap_extents.base + metadata.aslr_extents.size)) {
LOG_DEBUG(CheatEngine,
"Cheat attempting to access memory at invalid address={:016X}, if this "
"persists, "
"the cheat may be incorrect. However, this may be normal early in execution if "
@ -211,16 +216,14 @@ void CheatEngine::Initialize() {
.base = GetInteger(page_table.GetHeapRegionStart()),
.size = page_table.GetHeapRegionSize(),
};
metadata.address_space_extents = {
.base = GetInteger(page_table.GetAddressSpaceStart()),
.size = page_table.GetAddressSpaceSize(),
};
metadata.alias_extents = {
metadata.aslr_extents = {
.base = GetInteger(page_table.GetAliasCodeRegionStart()),
.size = page_table.GetAliasCodeRegionSize(),
};
metadata.alias_extents = {
.base = GetInteger(page_table.GetAliasRegionStart()),
.size = page_table.GetAliasRegionSize(),
};
is_pending_reload.exchange(true);
}

View File

@ -37,7 +37,7 @@ private:
VAddr SanitizeAddress(VAddr address) const;
const CheatProcessMetadata& metadata;
System& system;
Core::System& system;
};
// Intermediary class that parses a text file or other disk format for storing cheats into a

View File

@ -18,7 +18,7 @@ struct CheatProcessMetadata {
MemoryRegionExtents main_nso_extents{};
MemoryRegionExtents heap_extents{};
MemoryRegionExtents alias_extents{};
MemoryRegionExtents address_space_extents{};
MemoryRegionExtents aslr_extents{};
std::array<u8, 0x20> main_nso_build_id{};
};

View File

@ -322,8 +322,9 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
} break;
case CheatVmOpcodeType::EndConditionalBlock: {
// 20000000
// There's actually nothing left to process here!
opcode.opcode = EndConditionalOpcode{};
opcode.opcode = EndConditionalOpcode{
.is_else = ((first_dword >> 24) & 0xf) == 1,
};
} break;
case CheatVmOpcodeType::ControlLoop: {
// 300R0000 VVVVVVVV
@ -555,6 +556,18 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
.idx = first_dword & 0xF,
};
} break;
case CheatVmOpcodeType::PauseProcess: {
/* FF0????? */
/* FF0 = opcode 0xFF0 */
/* Pauses the current process. */
opcode.opcode = PauseProcessOpcode{};
} break;
case CheatVmOpcodeType::ResumeProcess: {
/* FF0????? */
/* FF0 = opcode 0xFF0 */
/* Pauses the current process. */
opcode.opcode = ResumeProcessOpcode{};
} break;
case CheatVmOpcodeType::DebugLog: {
// FFFTIX##
// FFFTI0Ma aaaaaaaa
@ -621,7 +634,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
return valid;
}
void DmntCheatVm::SkipConditionalBlock() {
void DmntCheatVm::SkipConditionalBlock(bool is_if) {
if (condition_depth > 0) {
// We want to continue until we're out of the current block.
const std::size_t desired_depth = condition_depth - 1;
@ -637,8 +650,12 @@ void DmntCheatVm::SkipConditionalBlock() {
// We also support nesting of conditional blocks, and Gateway does not.
if (skip_opcode.begin_conditional_block) {
condition_depth++;
} else if (std::holds_alternative<EndConditionalOpcode>(skip_opcode.opcode)) {
condition_depth--;
} else if (auto end_cond = std::get_if<EndConditionalOpcode>(&skip_opcode.opcode)) {
if (!end_cond->is_else) {
condition_depth--;
} else if (is_if && condition_depth - 1 == desired_depth) {
break;
}
}
}
} else {
@ -675,6 +692,10 @@ u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata,
return metadata.main_nso_extents.base + rel_address;
case MemoryAccessType::Heap:
return metadata.heap_extents.base + rel_address;
case MemoryAccessType::Alias:
return metadata.alias_extents.base + rel_address;
case MemoryAccessType::Aslr:
return metadata.aslr_extents.base + rel_address;
}
}
@ -682,7 +703,6 @@ void DmntCheatVm::ResetState() {
registers.fill(0);
saved_values.fill(0);
loop_tops.fill(0);
static_registers.fill(0);
instruction_ptr = 0;
condition_depth = 0;
decode_success = true;
@ -794,13 +814,18 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
}
// Skip conditional block if condition not met.
if (!cond_met) {
SkipConditionalBlock();
SkipConditionalBlock(true);
}
} else if (std::holds_alternative<EndConditionalOpcode>(cur_opcode.opcode)) {
// Decrement the condition depth.
// We will assume, graciously, that mismatched conditional block ends are a nop.
if (condition_depth > 0) {
condition_depth--;
} else if (auto end_cond = std::get_if<EndConditionalOpcode>(&cur_opcode.opcode)) {
if (end_cond->is_else) {
/* Skip to the end of the conditional block. */
this->SkipConditionalBlock(false);
} else {
/* Decrement the condition depth. */
/* We will assume, graciously, that mismatched conditional block ends are a nop. */
if (condition_depth > 0) {
condition_depth--;
}
}
} else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) {
if (ctrl_loop->start_loop) {
@ -908,7 +933,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
// Check for keypress.
if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) {
// Keys not pressed. Skip conditional block.
SkipConditionalBlock();
SkipConditionalBlock(true);
}
} else if (auto perform_math_reg =
std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) {
@ -1116,7 +1141,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
// Skip conditional block if condition not met.
if (!cond_met) {
SkipConditionalBlock();
SkipConditionalBlock(true);
}
} else if (auto save_restore_reg =
std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) {
@ -1178,6 +1203,10 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
// Store a register to a static register.
static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx];
}
} else if (std::holds_alternative<PauseProcessOpcode>(cur_opcode.opcode)) {
// TODO: Pause cheat process
} else if (std::holds_alternative<ResumeProcessOpcode>(cur_opcode.opcode)) {
// TODO: Resume cheat process
} else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) {
// Read value from memory.
u64 log_value = 0;

View File

@ -42,12 +42,16 @@ enum class CheatVmOpcodeType : u32 {
DoubleExtendedWidth = 0xF0,
// Double-extended width opcodes.
PauseProcess = 0xFF0,
ResumeProcess = 0xFF1,
DebugLog = 0xFFF,
};
enum class MemoryAccessType : u32 {
MainNso = 0,
Heap = 1,
Alias = 2,
Aslr = 3,
};
enum class ConditionalComparisonType : u32 {
@ -131,7 +135,9 @@ struct BeginConditionalOpcode {
VmInt value{};
};
struct EndConditionalOpcode {};
struct EndConditionalOpcode {
bool is_else;
};
struct ControlLoopOpcode {
bool start_loop{};
@ -222,6 +228,10 @@ struct ReadWriteStaticRegisterOpcode {
u32 idx{};
};
struct PauseProcessOpcode {};
struct ResumeProcessOpcode {};
struct DebugLogOpcode {
u32 bit_width{};
u32 log_id{};
@ -244,8 +254,8 @@ struct CheatVmOpcode {
PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode,
UnrecognizedInstruction>
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode,
ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction>
opcode{};
};
@ -296,7 +306,7 @@ private:
std::array<std::size_t, NumRegisters> loop_tops{};
bool DecodeNextOpcode(CheatVmOpcode& out);
void SkipConditionalBlock();
void SkipConditionalBlock(bool is_if);
void ResetState();
// For implementing the DebugLog opcode.

View File

@ -401,6 +401,14 @@ void Config::ReadNetworkValues() {
EndGroup();
}
void Config::ReadLibraryAppletValues() {
BeginGroup(Settings::TranslateCategory(Settings::Category::LibraryApplet));
ReadCategory(Settings::Category::LibraryApplet);
EndGroup();
}
void Config::ReadValues() {
if (global) {
ReadDataStorageValues();
@ -410,6 +418,7 @@ void Config::ReadValues() {
ReadServiceValues();
ReadWebServiceValues();
ReadMiscellaneousValues();
ReadLibraryAppletValues();
}
ReadControlValues();
ReadCoreValues();
@ -511,6 +520,7 @@ void Config::SaveValues() {
SaveNetworkValues();
SaveWebServiceValues();
SaveMiscellaneousValues();
SaveLibraryAppletValues();
} else {
LOG_DEBUG(Config, "Saving only generic configuration values");
}
@ -691,6 +701,14 @@ void Config::SaveWebServiceValues() {
EndGroup();
}
void Config::SaveLibraryAppletValues() {
BeginGroup(Settings::TranslateCategory(Settings::Category::LibraryApplet));
WriteCategory(Settings::Category::LibraryApplet);
EndGroup();
}
bool Config::ReadBooleanSetting(const std::string& key, const std::optional<bool> default_value) {
std::string full_key = GetFullKey(key, false);
if (!default_value.has_value()) {

View File

@ -88,6 +88,7 @@ protected:
void ReadSystemValues();
void ReadWebServiceValues();
void ReadNetworkValues();
void ReadLibraryAppletValues();
// Read platform specific sections
virtual void ReadHidbusValues() = 0;
@ -121,6 +122,7 @@ protected:
void SaveScreenshotValues();
void SaveSystemValues();
void SaveWebServiceValues();
void SaveLibraryAppletValues();
// Save platform specific sections
virtual void SaveHidbusValues() = 0;

View File

@ -52,9 +52,42 @@ ResourceManager::ResourceManager(Core::System& system_,
std::shared_ptr<HidFirmwareSettings> settings)
: firmware_settings{settings}, system{system_}, service_context{system_, "hid"} {
applet_resource = std::make_shared<AppletResource>(system);
// Register update callbacks
npad_update_event = Core::Timing::CreateEvent("HID::UpdatePadCallback",
[this](s64 time, std::chrono::nanoseconds ns_late)
-> std::optional<std::chrono::nanoseconds> {
UpdateNpad(ns_late);
return std::nullopt;
});
default_update_event = Core::Timing::CreateEvent(
"HID::UpdateDefaultCallback",
[this](s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
UpdateControllers(ns_late);
return std::nullopt;
});
mouse_keyboard_update_event = Core::Timing::CreateEvent(
"HID::UpdateMouseKeyboardCallback",
[this](s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
UpdateMouseKeyboard(ns_late);
return std::nullopt;
});
motion_update_event = Core::Timing::CreateEvent(
"HID::UpdateMotionCallback",
[this](s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
UpdateMotion(ns_late);
return std::nullopt;
});
}
ResourceManager::~ResourceManager() {
system.CoreTiming().UnscheduleEvent(npad_update_event);
system.CoreTiming().UnscheduleEvent(default_update_event);
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event);
system.CoreTiming().UnscheduleEvent(motion_update_event);
system.CoreTiming().UnscheduleEvent(touch_update_event);
input_event->Finalize();
};
@ -201,6 +234,7 @@ void ResourceManager::InitializeHidCommonSampler() {
debug_pad->SetAppletResource(applet_resource, &shared_mutex);
digitizer->SetAppletResource(applet_resource, &shared_mutex);
unique_pad->SetAppletResource(applet_resource, &shared_mutex);
keyboard->SetAppletResource(applet_resource, &shared_mutex);
const auto settings =
@ -214,6 +248,14 @@ void ResourceManager::InitializeHidCommonSampler() {
home_button->SetAppletResource(applet_resource, &shared_mutex);
sleep_button->SetAppletResource(applet_resource, &shared_mutex);
capture_button->SetAppletResource(applet_resource, &shared_mutex);
system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
default_update_event);
system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
mouse_keyboard_update_event);
system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
motion_update_event);
}
void ResourceManager::InitializeTouchScreenSampler() {
@ -465,55 +507,9 @@ IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<Resource
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
};
RegisterHandlers(functions);
// Register update callbacks
npad_update_event = Core::Timing::CreateEvent(
"HID::UpdatePadCallback",
[this, resource](
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
resource->UpdateNpad(ns_late);
return std::nullopt;
});
default_update_event = Core::Timing::CreateEvent(
"HID::UpdateDefaultCallback",
[this, resource](
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
resource->UpdateControllers(ns_late);
return std::nullopt;
});
mouse_keyboard_update_event = Core::Timing::CreateEvent(
"HID::UpdateMouseKeyboardCallback",
[this, resource](
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
resource->UpdateMouseKeyboard(ns_late);
return std::nullopt;
});
motion_update_event = Core::Timing::CreateEvent(
"HID::UpdateMotionCallback",
[this, resource](
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
resource->UpdateMotion(ns_late);
return std::nullopt;
});
system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
default_update_event);
system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
mouse_keyboard_update_event);
system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
motion_update_event);
}
IAppletResource::~IAppletResource() {
system.CoreTiming().UnscheduleEvent(npad_update_event);
system.CoreTiming().UnscheduleEvent(default_update_event);
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event);
system.CoreTiming().UnscheduleEvent(motion_update_event);
resource_manager->FreeAppletResourceId(aruid);
}

View File

@ -147,6 +147,10 @@ private:
std::shared_ptr<SixAxis> six_axis{nullptr};
std::shared_ptr<SleepButton> sleep_button{nullptr};
std::shared_ptr<UniquePad> unique_pad{nullptr};
std::shared_ptr<Core::Timing::EventType> npad_update_event;
std::shared_ptr<Core::Timing::EventType> default_update_event;
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
std::shared_ptr<Core::Timing::EventType> motion_update_event;
// TODO: Create these resources
// std::shared_ptr<AudioControl> audio_control{nullptr};
@ -179,11 +183,6 @@ public:
private:
void GetSharedMemoryHandle(HLERequestContext& ctx);
std::shared_ptr<Core::Timing::EventType> npad_update_event{nullptr};
std::shared_ptr<Core::Timing::EventType> default_update_event{nullptr};
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event{nullptr};
std::shared_ptr<Core::Timing::EventType> motion_update_event{nullptr};
u64 aruid{};
std::shared_ptr<ResourceManager> resource_manager;
};

View File

@ -17,10 +17,6 @@ void Digitizer::OnInit() {}
void Digitizer::OnRelease() {}
void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!smart_update) {
return;
}
std::scoped_lock shared_lock{*shared_mutex};
const u64 aruid = applet_resource->GetActiveAruid();
auto* data = applet_resource->GetAruidData(aruid);

View File

@ -20,8 +20,5 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
bool smart_update{};
};
} // namespace Service::HID

View File

@ -102,6 +102,8 @@ Result NPad::Activate(u64 aruid) {
for (std::size_t i = 0; i < 19; ++i) {
WriteEmptyEntry(npad);
}
controller.is_active = true;
}
return ResultSuccess;
@ -467,6 +469,13 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
continue;
}
bool is_set{};
npad_resource.IsSupportedNpadStyleSet(is_set, aruid);
// Wait until style is defined
if (!is_set) {
continue;
}
for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) {
auto& controller = controller_data[aruid_index][i];
controller.shared_memory =
@ -484,6 +493,10 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
continue;
}
if (!controller.is_active) {
continue;
}
RequestPadStateUpdate(aruid, controller.device->GetNpadIdType());
auto& pad_state = controller.npad_pad_state;
auto& libnx_state = controller.npad_libnx_state;
@ -592,7 +605,9 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw;
libnx_state.l_stick = pad_state.l_stick;
libnx_state.r_stick = pad_state.r_stick;
npad->system_ext_lifo.WriteNextEntry(pad_state);
libnx_state.sampling_number =
npad->system_ext_lifo.ReadCurrentEntry().state.sampling_number + 1;
npad->system_ext_lifo.WriteNextEntry(libnx_state);
press_state |= static_cast<u64>(pad_state.npad_buttons.raw);
}
@ -1060,6 +1075,7 @@ void NPad::UnregisterAppletResourceUserId(u64 aruid) {
// TODO: Remove this once abstract pad is emulated properly
const auto aruid_index = npad_resource.GetIndexFromAruid(aruid);
for (auto& controller : controller_data[aruid_index]) {
controller.is_active = false;
controller.is_connected = false;
controller.shared_memory = nullptr;
}

View File

@ -164,6 +164,7 @@ private:
NpadInternalState* shared_memory = nullptr;
Core::HID::EmulatedController* device = nullptr;
bool is_active{};
bool is_connected{};
// Dual joycons can have only one side connected

View File

@ -17,10 +17,6 @@ void UniquePad::OnInit() {}
void UniquePad::OnRelease() {}
void UniquePad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!smart_update) {
return;
}
const u64 aruid = applet_resource->GetActiveAruid();
auto* data = applet_resource->GetAruidData(aruid);

View File

@ -20,8 +20,5 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
bool smart_update{};
};
} // namespace Service::HID

View File

@ -60,7 +60,8 @@ public:
Add(spv::ImageOperandsMask::ConstOffsets, offsets);
}
explicit ImageOperands(Id lod, Id ms) {
explicit ImageOperands(EmitContext& ctx, const IR::Value& offset, Id lod, Id ms) {
AddOffset(ctx, offset, ImageFetchOffsetAllowed);
if (Sirit::ValidId(lod)) {
Add(spv::ImageOperandsMask::Lod, lod);
}
@ -311,37 +312,6 @@ Id ImageGatherSubpixelOffset(EmitContext& ctx, const IR::TextureInstInfo& info,
return coords;
}
}
void AddOffsetToCoordinates(EmitContext& ctx, const IR::TextureInstInfo& info, Id& coords,
Id offset) {
if (!Sirit::ValidId(offset)) {
return;
}
Id result_type{};
switch (info.type) {
case TextureType::Buffer:
case TextureType::Color1D:
case TextureType::ColorArray1D: {
result_type = ctx.U32[1];
break;
}
case TextureType::Color2D:
case TextureType::Color2DRect:
case TextureType::ColorArray2D: {
result_type = ctx.U32[2];
break;
}
case TextureType::Color3D: {
result_type = ctx.U32[3];
break;
}
case TextureType::ColorCube:
case TextureType::ColorArrayCube:
return;
}
coords = ctx.OpIAdd(result_type, coords, offset);
}
} // Anonymous namespace
Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
@ -524,10 +494,9 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
operands.Span());
}
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
Id lod, Id ms) {
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
const IR::Value& offset, Id lod, Id ms) {
const auto info{inst->Flags<IR::TextureInstInfo>()};
AddOffsetToCoordinates(ctx, info, coords, offset);
if (info.type == TextureType::Buffer) {
lod = Id{};
}
@ -535,7 +504,7 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
// This image is multisampled, lod must be implicit
lod = Id{};
}
const ImageOperands operands(lod, ms);
const ImageOperands operands(ctx, offset, lod, ms);
return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4],
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
}

View File

@ -537,8 +537,8 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id
const IR::Value& offset, const IR::Value& offset2);
Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
const IR::Value& offset, const IR::Value& offset2, Id dref);
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
Id lod, Id ms);
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
const IR::Value& offset, Id lod, Id ms);
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
const IR::Value& skip_mips);
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);

View File

@ -18,6 +18,7 @@ add_library(video_core STATIC
buffer_cache/usage_tracker.h
buffer_cache/word_manager.h
cache_types.h
capture.h
cdma_pusher.cpp
cdma_pusher.h
compatible_formats.cpp
@ -55,11 +56,12 @@ add_library(video_core STATIC
engines/maxwell_dma.h
engines/puller.cpp
engines/puller.h
framebuffer_config.cpp
framebuffer_config.h
fsr.cpp
fsr.h
host1x/codecs/codec.cpp
host1x/codecs/codec.h
host1x/codecs/decoder.cpp
host1x/codecs/decoder.h
host1x/codecs/h264.cpp
host1x/codecs/h264.h
host1x/codecs/vp8.cpp
@ -78,8 +80,6 @@ add_library(video_core STATIC
host1x/nvdec.cpp
host1x/nvdec.h
host1x/nvdec_common.h
host1x/sync_manager.cpp
host1x/sync_manager.h
host1x/syncpoint_manager.cpp
host1x/syncpoint_manager.h
host1x/vic.cpp
@ -100,6 +100,7 @@ add_library(video_core STATIC
memory_manager.cpp
memory_manager.h
precompiled_headers.h
present.h
pte_kind.h
query_cache/bank_base.h
query_cache/query_base.h
@ -115,8 +116,24 @@ add_library(video_core STATIC
renderer_null/null_rasterizer.h
renderer_null/renderer_null.cpp
renderer_null/renderer_null.h
renderer_opengl/present/filters.cpp
renderer_opengl/present/filters.h
renderer_opengl/present/fsr.cpp
renderer_opengl/present/fsr.h
renderer_opengl/present/fxaa.cpp
renderer_opengl/present/fxaa.h
renderer_opengl/present/layer.cpp
renderer_opengl/present/layer.h
renderer_opengl/present/present_uniforms.h
renderer_opengl/present/smaa.cpp
renderer_opengl/present/smaa.h
renderer_opengl/present/util.h
renderer_opengl/present/window_adapt_pass.cpp
renderer_opengl/present/window_adapt_pass.h
renderer_opengl/blit_image.cpp
renderer_opengl/blit_image.h
renderer_opengl/gl_blit_screen.cpp
renderer_opengl/gl_blit_screen.h
renderer_opengl/gl_buffer_cache_base.cpp
renderer_opengl/gl_buffer_cache.cpp
renderer_opengl/gl_buffer_cache.h
@ -126,8 +143,6 @@ add_library(video_core STATIC
renderer_opengl/gl_device.h
renderer_opengl/gl_fence_manager.cpp
renderer_opengl/gl_fence_manager.h
renderer_opengl/gl_fsr.cpp
renderer_opengl/gl_fsr.h
renderer_opengl/gl_graphics_pipeline.cpp
renderer_opengl/gl_graphics_pipeline.h
renderer_opengl/gl_rasterizer.cpp
@ -155,6 +170,22 @@ add_library(video_core STATIC
renderer_opengl/renderer_opengl.h
renderer_opengl/util_shaders.cpp
renderer_opengl/util_shaders.h
renderer_vulkan/present/anti_alias_pass.h
renderer_vulkan/present/filters.cpp
renderer_vulkan/present/filters.h
renderer_vulkan/present/fsr.cpp
renderer_vulkan/present/fsr.h
renderer_vulkan/present/fxaa.cpp
renderer_vulkan/present/fxaa.h
renderer_vulkan/present/layer.cpp
renderer_vulkan/present/layer.h
renderer_vulkan/present/present_push_constants.h
renderer_vulkan/present/smaa.cpp
renderer_vulkan/present/smaa.h
renderer_vulkan/present/util.cpp
renderer_vulkan/present/util.h
renderer_vulkan/present/window_adapt_pass.cpp
renderer_vulkan/present/window_adapt_pass.h
renderer_vulkan/blit_image.cpp
renderer_vulkan/blit_image.h
renderer_vulkan/fixed_pipeline_state.cpp
@ -181,8 +212,6 @@ add_library(video_core STATIC
renderer_vulkan/vk_descriptor_pool.h
renderer_vulkan/vk_fence_manager.cpp
renderer_vulkan/vk_fence_manager.h
renderer_vulkan/vk_fsr.cpp
renderer_vulkan/vk_fsr.h
renderer_vulkan/vk_graphics_pipeline.cpp
renderer_vulkan/vk_graphics_pipeline.h
renderer_vulkan/vk_master_semaphore.cpp
@ -203,8 +232,6 @@ add_library(video_core STATIC
renderer_vulkan/vk_scheduler.h
renderer_vulkan/vk_shader_util.cpp
renderer_vulkan/vk_shader_util.h
renderer_vulkan/vk_smaa.cpp
renderer_vulkan/vk_smaa.h
renderer_vulkan/vk_staging_buffer_pool.cpp
renderer_vulkan/vk_staging_buffer_pool.h
renderer_vulkan/vk_state_tracker.cpp

View File

@ -1546,7 +1546,10 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
std::span<const u8> upload_span;
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
if (IsRangeGranular(device_addr, copy.size)) {
upload_span = std::span(device_memory.GetPointer<u8>(device_addr), copy.size);
auto* const ptr = device_memory.GetPointer<u8>(device_addr);
if (ptr != nullptr) {
upload_span = std::span(ptr, copy.size);
}
} else {
if (immediate_buffer.empty()) {
immediate_buffer = ImmediateBuffer(largest_copy);

36
src/video_core/capture.h Normal file
View File

@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/alignment.h"
#include "common/bit_util.h"
#include "common/common_types.h"
#include "core/frontend/framebuffer_layout.h"
#include "video_core/surface.h"
namespace VideoCore::Capture {
constexpr u32 BlockHeight = 4;
constexpr u32 BlockDepth = 0;
constexpr u32 BppLog2 = 2;
constexpr auto PixelFormat = Surface::PixelFormat::B8G8R8A8_UNORM;
constexpr auto LinearWidth = Layout::ScreenUndocked::Width;
constexpr auto LinearHeight = Layout::ScreenUndocked::Height;
constexpr auto LinearDepth = 1U;
constexpr auto BytesPerPixel = 4U;
constexpr auto TiledWidth = LinearWidth;
constexpr auto TiledHeight = Common::AlignUpLog2(LinearHeight, BlockHeight + BlockDepth + BppLog2);
constexpr auto TiledSize = TiledWidth * TiledHeight * (1 << BppLog2);
constexpr Layout::FramebufferLayout Layout{
.width = LinearWidth,
.height = LinearHeight,
.screen = {0, 0, LinearWidth, LinearHeight},
.is_srgb = false,
};
} // namespace VideoCore::Capture

Some files were not shown because too many files have changed in this diff Show More