From a782bbb5c325c81866dcea9fbd0d01590503b86c Mon Sep 17 00:00:00 2001 From: PavelBARABANOV Date: Sat, 5 Sep 2026 18:48:29 +0300 Subject: [PATCH] return ClearAppletCaptureBuffer etc. --- .../hle/service/am/display_layer_manager.cpp | 11 +- .../hle/service/am/display_layer_manager.h | 5 +- .../service/am/service/display_controller.cpp | 25 ++--- .../hle/service/vi/shared_buffer_manager.cpp | 102 ++++++++++++++---- .../hle/service/vi/shared_buffer_manager.h | 10 +- 5 files changed, 116 insertions(+), 37 deletions(-) diff --git a/src/core/hle/service/am/display_layer_manager.cpp b/src/core/hle/service/am/display_layer_manager.cpp index 58c45a3852..3c50edd45a 100644 --- a/src/core/hle/service/am/display_layer_manager.cpp +++ b/src/core/hle/service/am/display_layer_manager.cpp @@ -221,10 +221,17 @@ void DisplayLayerManager::SetOverlayZIndex(s32 z_index) { } Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written, - s32* out_fbshare_layer_index) { + s32* out_fbshare_layer_index, + VI::CaptureKind kind) { R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied); R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer( - out_was_written, out_fbshare_layer_index)); + out_was_written, out_fbshare_layer_index, kind)); +} + +Result DisplayLayerManager::ClearAppletCaptureBuffer(s32 fbshare_layer_index, u32 color) { + R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied); + R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->ClearAppletCaptureBuffer( + fbshare_layer_index, color)); } } // namespace Service::AM diff --git a/src/core/hle/service/am/display_layer_manager.h b/src/core/hle/service/am/display_layer_manager.h index 1469ca08f8..e9f48476d2 100644 --- a/src/core/hle/service/am/display_layer_manager.h +++ b/src/core/hle/service/am/display_layer_manager.h @@ -23,6 +23,7 @@ class KProcess; namespace Service::VI { class IApplicationDisplayService; class IManagerDisplayService; +enum class CaptureKind : u32; } // namespace Service::VI namespace Service::AM { @@ -48,7 +49,9 @@ public: void SetOverlayZIndex(s32 z_index); - Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index); + Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index, + VI::CaptureKind kind); + Result ClearAppletCaptureBuffer(s32 fbshare_layer_index, u32 color); private: u32 GetLayerStackMask() const; diff --git a/src/core/hle/service/am/service/display_controller.cpp b/src/core/hle/service/am/service/display_controller.cpp index 228c455935..8f87327b17 100644 --- a/src/core/hle/service/am/service/display_controller.cpp +++ b/src/core/hle/service/am/service/display_controller.cpp @@ -8,6 +8,7 @@ #include "core/hle/service/am/applet.h" #include "core/hle/service/am/service/display_controller.h" #include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/vi/shared_buffer_manager.h" namespace Service::AM { @@ -71,16 +72,16 @@ Result IDisplayController::TakeScreenShotOfOwnLayer(bool unknown0, s32 fbshare_l } Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color) { - LOG_WARNING(Service_AM, "(STUBBED) called, unknown0={} fbshare_layer_index={} color={:#x}", - unknown0, fbshare_layer_index, color); - R_SUCCEED(); + LOG_DEBUG(Service_AM, "called, unknown0={} fbshare_layer_index={} color={:#x}", unknown0, + fbshare_layer_index, color); + R_RETURN(applet->display_layer_manager.ClearAppletCaptureBuffer(fbshare_layer_index, color)); } Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer( Out out_was_written, Out out_fbshare_layer_index) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written, - out_fbshare_layer_index)); + LOG_DEBUG(Service_AM, "called"); + R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer( + out_was_written, out_fbshare_layer_index, VI::CaptureKind::LastForeground)); } Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() { @@ -90,9 +91,9 @@ Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() { Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer( Out out_was_written, Out out_fbshare_layer_index) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written, - out_fbshare_layer_index)); + LOG_DEBUG(Service_AM, "called"); + R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer( + out_was_written, out_fbshare_layer_index, VI::CaptureKind::CallerApplet)); } Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() { @@ -102,9 +103,9 @@ Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() { Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer( Out out_was_written, Out out_fbshare_layer_index) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written, - out_fbshare_layer_index)); + LOG_DEBUG(Service_AM, "called"); + R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer( + out_was_written, out_fbshare_layer_index, VI::CaptureKind::LastApplication)); } Result IDisplayController::ReleaseLastApplicationCaptureSharedBuffer() { diff --git a/src/core/hle/service/vi/shared_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp index 21e42e2094..90b0de5cc4 100644 --- a/src/core/hle/service/vi/shared_buffer_manager.cpp +++ b/src/core/hle/service/vi/shared_buffer_manager.cpp @@ -168,7 +168,14 @@ constexpr u32 SharedBufferBlockLinearWidth = 1280; constexpr u32 SharedBufferBlockLinearHeight = 768; constexpr u32 SharedBufferBlockLinearStride = SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp; -constexpr u32 SharedBufferNumSlots = 7; + +constexpr u32 SharedBufferNumCaptureSlots = 3; +constexpr u32 SharedBufferSlotsPerSession = 2; +constexpr u32 SharedBufferMaxSessions = 2; + +constexpr u32 SharedBufferNumSlots = + SharedBufferNumCaptureSlots + SharedBufferSlotsPerSession * SharedBufferMaxSessions; +static_assert(SharedBufferNumSlots <= 16, "Shared buffer pool exceeds the maximum texture count"); constexpr u32 SharedBufferWidth = 1280; constexpr u32 SharedBufferHeight = 720; @@ -192,6 +199,43 @@ constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] { return layout; }(); +constexpr u32 GetCaptureSlot(CaptureKind kind) { + return static_cast(kind); +} + +template +void ForEachPoolChunk(Core::System& system, Kernel::KPageGroup& page_group, u64 offset, u64 size, + F&& writer) { + Common::ScratchBuffer scratch; + const u64 range_end = offset + size; + u64 pool_pos = 0; + + for (auto& block : page_group) { + const u64 block_begin = pool_pos; + const u64 block_end = block_begin + block.GetSize(); + pool_pos = block_end; + + if (block_end <= offset) { + continue; + } + if (block_begin >= range_end) { + break; + } + + const u64 chunk_begin = (std::max)(block_begin, offset); + const u64 chunk_end = (std::min)(block_end, range_end); + const u64 chunk_size = chunk_end - chunk_begin; + + u8* const dst = + system.DeviceMemory().GetPointer(block.GetAddress()) + (chunk_begin - block_begin); + + writer(dst, chunk_begin - offset, chunk_size); + + system.GPU().Host1x().MemoryManager().ApplyOpOnPointer( + dst, scratch, [&](DAddr addr) { system.GPU().InvalidateRegion(addr, chunk_size); }); + } +} + void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) { auto buffer = std::make_shared(); buffer->width = SharedBufferWidth; @@ -404,31 +448,47 @@ Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadabl R_SUCCEED(); } -Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { - std::vector capture_buffer(m_system.GPU().GetAppletCaptureBuffer()); - Common::ScratchBuffer scratch; +Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index, CaptureKind kind) { + std::scoped_lock lk{m_guard}; + R_UNLESS(m_buffer_page_group != nullptr, VI::ResultNotFound); - // TODO: this could be optimized - s64 e = -1280 * 768 * 4; - for (auto& block : *m_buffer_page_group) { - u8* start = m_system.DeviceMemory().GetPointer(block.GetAddress()); - u8* end = m_system.DeviceMemory().GetPointer(block.GetAddress() + block.GetSize()); + const std::vector capture = m_system.GPU().GetAppletCaptureBuffer(); + const u32 slot = GetCaptureSlot(kind); - for (; start < end; start++) { - *start = 0; - if (e >= 0 && e < static_cast(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); - }); + if (capture.size() < SharedBufferSlotSize) { + //LOG_WARNING(Service_VI, "Capture buffer is {} bytes, expected at least {}; not writing", + // capture.size(), SharedBufferSlotSize); + *out_was_written = false; + *out_layer_index = static_cast(slot); + R_SUCCEED(); } + ForEachPoolChunk(m_system, *m_buffer_page_group, u64{slot} * SharedBufferSlotSize, + SharedBufferSlotSize, + [&](u8* dst, u64 src_offset, u64 length) { + std::memcpy(dst, capture.data() + src_offset, length); + }); + *out_was_written = true; - *out_layer_index = 1; + *out_layer_index = static_cast(slot); + R_SUCCEED(); +} + +Result SharedBufferManager::ClearAppletCaptureBuffer(s32 layer_index, u32 color) { + std::scoped_lock lk{m_guard}; + R_UNLESS(m_buffer_page_group != nullptr, VI::ResultNotFound); + + if (layer_index < 0 || layer_index >= static_cast(SharedBufferNumCaptureSlots)) { + LOG_WARNING(Service_VI, "Couldnt clear non-capture slot {}", layer_index); + R_SUCCEED(); + } + + ForEachPoolChunk(m_system, *m_buffer_page_group, u64{static_cast(layer_index)} * SharedBufferSlotSize, + SharedBufferSlotSize, [&](u8* dst, u64 src_offset, u64 length) { + ASSERT(src_offset % sizeof(u32) == 0 && length % sizeof(u32) == 0); + std::fill_n(reinterpret_cast(dst), length / sizeof(u32), color); + }); + R_SUCCEED(); } diff --git a/src/core/hle/service/vi/shared_buffer_manager.h b/src/core/hle/service/vi/shared_buffer_manager.h index 5ef2d3a077..6e931bee45 100644 --- a/src/core/hle/service/vi/shared_buffer_manager.h +++ b/src/core/hle/service/vi/shared_buffer_manager.h @@ -48,6 +48,12 @@ static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout h struct SharedBufferSession; +enum class CaptureKind : u32 { + LastApplication, + LastForeground, + CallerApplet, +}; + class SharedBufferManager final { public: explicit SharedBufferManager(Core::System& system, Container& container, @@ -68,7 +74,8 @@ public: Result CancelSharedFrameBuffer(u64 layer_id, s64 slot); Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id); - Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index); + Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index, CaptureKind kind); + Result ClearAppletCaptureBuffer(s32 layer_index, u32 color); private: u64 m_next_buffer_id = 1; @@ -89,6 +96,7 @@ struct SharedBufferSession { Nvidia::NvCore::SessionId session_id = {}; u64 layer_id = {}; u32 buffer_nvmap_handle = 0; + u32 presentation_slot_base = 0; }; } // namespace Service::VI