From 962c82540c304f909957776908aabcd261f2a7ba Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 22 Jan 2024 12:40:50 -0500 Subject: nvnflinger/gpu: implement blending --- .../service/nvnflinger/fb_share_buffer_manager.cpp | 154 ++++++++++++++++----- .../service/nvnflinger/fb_share_buffer_manager.h | 24 +++- .../hle/service/nvnflinger/hardware_composer.cpp | 1 + src/core/hle/service/nvnflinger/hwc_layer.h | 13 ++ src/core/hle/service/nvnflinger/nvnflinger.cpp | 7 +- src/core/hle/service/nvnflinger/nvnflinger.h | 6 +- 6 files changed, 158 insertions(+), 47 deletions(-) (limited to 'src/core/hle/service/nvnflinger') diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index e71652cdf..6a7da0cae 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -14,24 +14,19 @@ #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" namespace Service::Nvnflinger { namespace { -Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address, - std::unique_ptr* out_page_group, - Core::System& system, u32 size) { +Result AllocateSharedBufferMemory(std::unique_ptr* 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( @@ -43,6 +38,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(block.GetAddress()); + u32* end = system.DeviceMemory().GetPointer(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& 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 +83,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 +151,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(nvmap_fd); + ASSERT(nvmap != nullptr); + + R_ASSERT(FreeNvMapHandle(*nvmap, handle, nvmap_fd)); +} + constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888; constexpr u32 SharedBufferBlockLinearBpp = 4; @@ -186,53 +209,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 for the shared buffer if needed. + if (!m_buffer_page_group) { + R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system, + SharedBufferSize)); - // 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)); + // 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 +309,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 +377,10 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence, android::Status::NoError, VI::ResultOperationFailed); + ON_RESULT_FAILURE { + producer.CancelBuffer(static_cast(slot), fence); + }; + // Queue the buffer to the producer. android::QueueBufferInput input{}; android::QueueBufferOutput output{}; @@ -342,4 +414,12 @@ Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadab R_SUCCEED(); } +Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, + s32* out_layer_index) { + // TODO + *out_was_written = true; + *out_layer_index = 1; + R_SUCCEED(); +} + } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h index 033bf4bbe..b79a7d23a 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h @@ -3,9 +3,12 @@ #pragma once +#include + #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 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 m_sessions; std::unique_ptr m_buffer_page_group; std::mutex m_guard; @@ -65,4 +72,11 @@ private: std::shared_ptr m_nvdrv; }; +struct FbShareSession { + Nvidia::DeviceFD nvmap_fd = {}; + Nvidia::NvCore::SessionId session_id = {}; + u64 layer_id = {}; + u32 buffer_nvmap_handle = 0; +}; + } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp index ba2b5c28c..be7eb97a3 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.cpp +++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp @@ -86,6 +86,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, .height = igbp_buffer.Height(), .stride = igbp_buffer.Stride(), .z_index = 0, + .blending = layer.GetBlending(), .transform = static_cast(item.transform), .crop_rect = item.crop, .acquire_fence = item.fence, diff --git a/src/core/hle/service/nvnflinger/hwc_layer.h b/src/core/hle/service/nvnflinger/hwc_layer.h index 3af668a25..f71a5d822 100644 --- a/src/core/hle/service/nvnflinger/hwc_layer.h +++ b/src/core/hle/service/nvnflinger/hwc_layer.h @@ -11,6 +11,18 @@ 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; @@ -19,6 +31,7 @@ struct HwcLayer { u32 height; u32 stride; s32 z_index; + LayerBlending blending; android::BufferTransformFlags transform; Common::Rectangle crop_rect; android::Fence acquire_fence; diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index d8ba89d43..687ccc9f9 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -157,7 +157,7 @@ bool Nvnflinger::CloseDisplay(u64 display_id) { return true; } -std::optional Nvnflinger::CreateLayer(u64 display_id) { +std::optional Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) { const auto lock_guard = Lock(); auto* const display = FindDisplay(display_id); @@ -166,13 +166,14 @@ std::optional 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) { diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index c984d55a0..4cf4f069d 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -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; @@ -72,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 CreateLayer(u64 display_id); + [[nodiscard]] std::optional CreateLayer(u64 display_id, + LayerBlending blending = LayerBlending::None); /// Opens a layer on all displays for the given layer ID. bool OpenLayer(u64 layer_id); @@ -128,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); -- cgit v1.2.3 From 0cb413c3d31b93ce347e997b9674c304094dab09 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 26 Jan 2024 16:10:21 -0500 Subject: nvnflinger/gpu: implement applet capture --- src/core/hle/service/am/system_buffer_manager.cpp | 8 +- .../service/nvnflinger/fb_share_buffer_manager.cpp | 28 +++++- src/video_core/CMakeLists.txt | 1 + src/video_core/capture.h | 36 +++++++ src/video_core/gpu.cpp | 15 +++ src/video_core/gpu.h | 2 + src/video_core/renderer_base.h | 3 + src/video_core/renderer_null/renderer_null.cpp | 5 + src/video_core/renderer_null/renderer_null.h | 2 + src/video_core/renderer_opengl/gl_blit_screen.cpp | 4 +- src/video_core/renderer_opengl/gl_blit_screen.h | 2 +- src/video_core/renderer_opengl/present/layer.cpp | 15 ++- src/video_core/renderer_opengl/present/layer.h | 2 +- .../renderer_opengl/present/window_adapt_pass.cpp | 4 +- .../renderer_opengl/present/window_adapt_pass.h | 2 +- src/video_core/renderer_opengl/renderer_opengl.cpp | 85 +++++++++++++--- src/video_core/renderer_opengl/renderer_opengl.h | 9 ++ src/video_core/renderer_vulkan/renderer_vulkan.cpp | 108 ++++++++++++++++----- src/video_core/renderer_vulkan/renderer_vulkan.h | 12 ++- 19 files changed, 288 insertions(+), 55 deletions(-) create mode 100644 src/video_core/capture.h (limited to 'src/core/hle/service/nvnflinger') diff --git a/src/core/hle/service/am/system_buffer_manager.cpp b/src/core/hle/service/am/system_buffer_manager.cpp index 3cccc5388..7fb9e3a75 100644 --- a/src/core/hle/service/am/system_buffer_manager.cpp +++ b/src/core/hle/service/am/system_buffer_manager.cpp @@ -68,8 +68,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 diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index 6a7da0cae..90f7248a0 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -15,6 +15,7 @@ #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 { @@ -414,9 +415,30 @@ Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadab R_SUCCEED(); } -Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, - s32* out_layer_index) { - // TODO +Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { + std::vector capture_buffer(m_system.GPU().GetAppletCaptureBuffer()); + Common::ScratchBuffer scratch; + + // 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()); + + 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); + }); + } + *out_was_written = true; *out_layer_index = 1; R_SUCCEED(); diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 55180f4b5..dbed976ad 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -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 diff --git a/src/video_core/capture.h b/src/video_core/capture.h new file mode 100644 index 000000000..8db14a8ec --- /dev/null +++ b/src/video_core/capture.h @@ -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 diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index f4a5d831c..8e663f2a8 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -347,6 +347,17 @@ struct GPU::Impl { WaitForSyncOperation(wait_fence); } + std::vector GetAppletCaptureBuffer() { + std::vector out; + + const auto wait_fence = + RequestSyncOperation([&] { out = renderer->GetAppletCaptureBuffer(); }); + gpu_thread.TickGPU(); + WaitForSyncOperation(wait_fence); + + return out; + } + GPU& gpu; Core::System& system; Host1x::Host1x& host1x; @@ -505,6 +516,10 @@ void GPU::RequestComposite(std::vector&& layers, impl->RequestComposite(std::move(layers), std::move(fences)); } +std::vector GPU::GetAppletCaptureBuffer() { + return impl->GetAppletCaptureBuffer(); +} + u64 GPU::GetTicks() const { return impl->GetTicks(); } diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index c4602ca37..ad535512c 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -215,6 +215,8 @@ public: void RequestComposite(std::vector&& layers, std::vector&& fences); + std::vector GetAppletCaptureBuffer(); + /// Performs any additional setup necessary in order to begin GPU emulation. /// This can be used to launch any necessary threads and register any necessary /// core timing events. diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 3ad180f67..67427f937 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -40,6 +40,9 @@ public: /// Finalize rendering the guest frame and draw into the presentation texture virtual void Composite(std::span layers) = 0; + /// Get the tiled applet layer capture buffer + virtual std::vector GetAppletCaptureBuffer() = 0; + [[nodiscard]] virtual RasterizerInterface* ReadRasterizer() = 0; [[nodiscard]] virtual std::string GetDeviceVendor() const = 0; diff --git a/src/video_core/renderer_null/renderer_null.cpp b/src/video_core/renderer_null/renderer_null.cpp index c89daff53..e6147d66c 100644 --- a/src/video_core/renderer_null/renderer_null.cpp +++ b/src/video_core/renderer_null/renderer_null.cpp @@ -3,6 +3,7 @@ #include "core/frontend/emu_window.h" #include "core/frontend/graphics_context.h" +#include "video_core/capture.h" #include "video_core/renderer_null/renderer_null.h" namespace Null { @@ -22,4 +23,8 @@ void RendererNull::Composite(std::span framebuff render_window.OnFrameDisplayed(); } +std::vector RendererNull::GetAppletCaptureBuffer() { + return std::vector(VideoCore::Capture::TiledSize); +} + } // namespace Null diff --git a/src/video_core/renderer_null/renderer_null.h b/src/video_core/renderer_null/renderer_null.h index 063b476bb..34dbe1e4f 100644 --- a/src/video_core/renderer_null/renderer_null.h +++ b/src/video_core/renderer_null/renderer_null.h @@ -19,6 +19,8 @@ public: void Composite(std::span framebuffer) override; + std::vector GetAppletCaptureBuffer() override; + VideoCore::RasterizerInterface* ReadRasterizer() override { return &m_rasterizer; } diff --git a/src/video_core/renderer_opengl/gl_blit_screen.cpp b/src/video_core/renderer_opengl/gl_blit_screen.cpp index 6ba8b214b..0282905ee 100644 --- a/src/video_core/renderer_opengl/gl_blit_screen.cpp +++ b/src/video_core/renderer_opengl/gl_blit_screen.cpp @@ -20,7 +20,7 @@ BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, BlitScreen::~BlitScreen() = default; void BlitScreen::DrawScreen(std::span framebuffers, - const Layout::FramebufferLayout& layout) { + const Layout::FramebufferLayout& layout, bool invert_y) { // TODO: Signal state tracker about these changes state_tracker.NotifyScreenDrawVertexArray(); state_tracker.NotifyPolygonModes(); @@ -60,7 +60,7 @@ void BlitScreen::DrawScreen(std::span framebuffe } CreateWindowAdapt(); - window_adapt->DrawToFramebuffer(program_manager, layers, framebuffers, layout); + window_adapt->DrawToFramebuffer(program_manager, layers, framebuffers, layout, invert_y); // TODO // program_manager.RestoreGuestPipeline(); diff --git a/src/video_core/renderer_opengl/gl_blit_screen.h b/src/video_core/renderer_opengl/gl_blit_screen.h index 0c3d838f1..4e261d333 100644 --- a/src/video_core/renderer_opengl/gl_blit_screen.h +++ b/src/video_core/renderer_opengl/gl_blit_screen.h @@ -51,7 +51,7 @@ public: /// Draws the emulated screens to the emulator window. void DrawScreen(std::span framebuffers, - const Layout::FramebufferLayout& layout); + const Layout::FramebufferLayout& layout, bool invert_y); private: void CreateWindowAdapt(); diff --git a/src/video_core/renderer_opengl/present/layer.cpp b/src/video_core/renderer_opengl/present/layer.cpp index e3fffaa06..3e4377db4 100644 --- a/src/video_core/renderer_opengl/present/layer.cpp +++ b/src/video_core/renderer_opengl/present/layer.cpp @@ -34,7 +34,7 @@ GLuint Layer::ConfigureDraw(std::array& out_matrix, std::array& out_vertices, ProgramManager& program_manager, const Tegra::FramebufferConfig& framebuffer, - const Layout::FramebufferLayout& layout) { + const Layout::FramebufferLayout& layout, bool invert_y) { FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); GLuint texture = info.display_texture; @@ -83,10 +83,15 @@ GLuint Layer::ConfigureDraw(std::array& out_matrix, const auto w = screen.GetWidth(); const auto h = screen.GetHeight(); - out_vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top); - out_vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top); - out_vertices[2] = ScreenRectVertex(x, y + h, crop.left, crop.bottom); - out_vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom); + const auto left = crop.left; + const auto right = crop.right; + const auto top = invert_y ? crop.bottom : crop.top; + const auto bottom = invert_y ? crop.top : crop.bottom; + + out_vertices[0] = ScreenRectVertex(x, y, left, top); + out_vertices[1] = ScreenRectVertex(x + w, y, right, top); + out_vertices[2] = ScreenRectVertex(x, y + h, left, bottom); + out_vertices[3] = ScreenRectVertex(x + w, y + h, right, bottom); return texture; } diff --git a/src/video_core/renderer_opengl/present/layer.h b/src/video_core/renderer_opengl/present/layer.h index ef1055abf..77bb97f4f 100644 --- a/src/video_core/renderer_opengl/present/layer.h +++ b/src/video_core/renderer_opengl/present/layer.h @@ -51,7 +51,7 @@ public: std::array& out_vertices, ProgramManager& program_manager, const Tegra::FramebufferConfig& framebuffer, - const Layout::FramebufferLayout& layout); + const Layout::FramebufferLayout& layout, bool invert_y); private: /// Loads framebuffer from emulated memory into the active OpenGL texture. diff --git a/src/video_core/renderer_opengl/present/window_adapt_pass.cpp b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp index 0328abd70..d8b6a11cb 100644 --- a/src/video_core/renderer_opengl/present/window_adapt_pass.cpp +++ b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp @@ -37,7 +37,7 @@ WindowAdaptPass::~WindowAdaptPass() = default; void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::list& layers, std::span framebuffers, - const Layout::FramebufferLayout& layout) { + const Layout::FramebufferLayout& layout, bool invert_y) { GLint old_read_fb; GLint old_draw_fb; glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); @@ -51,7 +51,7 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li auto layer_it = layers.begin(); for (size_t i = 0; i < layer_count; i++) { textures[i] = layer_it->ConfigureDraw(matrices[i], vertices[i], program_manager, - framebuffers[i], layout); + framebuffers[i], layout, invert_y); layer_it++; } diff --git a/src/video_core/renderer_opengl/present/window_adapt_pass.h b/src/video_core/renderer_opengl/present/window_adapt_pass.h index 00975a9c6..0a8bcef2f 100644 --- a/src/video_core/renderer_opengl/present/window_adapt_pass.h +++ b/src/video_core/renderer_opengl/present/window_adapt_pass.h @@ -31,7 +31,7 @@ public: void DrawToFramebuffer(ProgramManager& program_manager, std::list& layers, std::span framebuffers, - const Layout::FramebufferLayout& layout); + const Layout::FramebufferLayout& layout, bool invert_y); private: const Device& device; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index e33a32592..a1a8491e5 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -16,6 +16,7 @@ #include "core/core_timing.h" #include "core/frontend/emu_window.h" #include "core/telemetry_session.h" +#include "video_core/capture.h" #include "video_core/renderer_opengl/gl_blit_screen.h" #include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/gl_shader_manager.h" @@ -121,6 +122,13 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, } blit_screen = std::make_unique(rasterizer, device_memory, state_tracker, program_manager, device); + blit_applet = std::make_unique(rasterizer, device_memory, state_tracker, + program_manager, device); + capture_framebuffer.Create(); + capture_renderbuffer.Create(); + glBindRenderbuffer(GL_RENDERBUFFER, capture_renderbuffer.handle); + glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, VideoCore::Capture::LinearWidth, + VideoCore::Capture::LinearHeight); } RendererOpenGL::~RendererOpenGL() = default; @@ -130,10 +138,11 @@ void RendererOpenGL::Composite(std::span framebu return; } + RenderAppletCaptureLayer(framebuffers); RenderScreenshot(framebuffers); state_tracker.BindFramebuffer(0); - blit_screen->DrawScreen(framebuffers, emu_window.GetFramebufferLayout()); + blit_screen->DrawScreen(framebuffers, emu_window.GetFramebufferLayout(), false); ++m_current_frame; @@ -159,11 +168,8 @@ void RendererOpenGL::AddTelemetryFields() { telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version)); } -void RendererOpenGL::RenderScreenshot(std::span framebuffers) { - if (!renderer_settings.screenshot_requested) { - return; - } - +void RendererOpenGL::RenderToBuffer(std::span framebuffers, + const Layout::FramebufferLayout& layout, void* dst) { GLint old_read_fb; GLint old_draw_fb; glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); @@ -173,29 +179,86 @@ void RendererOpenGL::RenderScreenshot(std::span screenshot_framebuffer.Create(); glBindFramebuffer(GL_FRAMEBUFFER, screenshot_framebuffer.handle); - const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; - GLuint renderbuffer; glGenRenderbuffers(1, &renderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); - blit_screen->DrawScreen(framebuffers, layout); + blit_screen->DrawScreen(framebuffers, layout, false); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glPixelStorei(GL_PACK_ROW_LENGTH, 0); - glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - renderer_settings.screenshot_bits); + glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, dst); screenshot_framebuffer.Release(); glDeleteRenderbuffers(1, &renderbuffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); +} + +void RendererOpenGL::RenderScreenshot(std::span framebuffers) { + if (!renderer_settings.screenshot_requested) { + return; + } + + RenderToBuffer(framebuffers, renderer_settings.screenshot_framebuffer_layout, + renderer_settings.screenshot_bits); renderer_settings.screenshot_complete_callback(true); renderer_settings.screenshot_requested = false; } +void RendererOpenGL::RenderAppletCaptureLayer( + std::span framebuffers) { + GLint old_read_fb; + GLint old_draw_fb; + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); + + glBindFramebuffer(GL_FRAMEBUFFER, capture_framebuffer.handle); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + capture_renderbuffer.handle); + + blit_applet->DrawScreen(framebuffers, VideoCore::Capture::Layout, true); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); +} + +std::vector RendererOpenGL::GetAppletCaptureBuffer() { + using namespace VideoCore::Capture; + + std::vector linear(TiledSize); + std::vector out(TiledSize); + + GLint old_read_fb; + GLint old_draw_fb; + GLint old_pixel_pack_buffer; + GLint old_pack_row_length; + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); + glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &old_pixel_pack_buffer); + glGetIntegerv(GL_PACK_ROW_LENGTH, &old_pack_row_length); + + glBindFramebuffer(GL_FRAMEBUFFER, capture_framebuffer.handle); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + capture_renderbuffer.handle); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glReadPixels(0, 0, LinearWidth, LinearHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, + linear.data()); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); + glBindBuffer(GL_PIXEL_PACK_BUFFER, old_pixel_pack_buffer); + glPixelStorei(GL_PACK_ROW_LENGTH, old_pack_row_length); + + Tegra::Texture::SwizzleTexture(out, linear, BytesPerPixel, LinearWidth, LinearHeight, + LinearDepth, BlockHeight, BlockDepth); + + return out; +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index c4625c96e..60d6a1477 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -42,6 +42,8 @@ public: void Composite(std::span framebuffers) override; + std::vector GetAppletCaptureBuffer() override; + VideoCore::RasterizerInterface* ReadRasterizer() override { return &rasterizer; } @@ -52,7 +54,11 @@ public: private: void AddTelemetryFields(); + + void RenderToBuffer(std::span framebuffers, + const Layout::FramebufferLayout& layout, void* dst); void RenderScreenshot(std::span framebuffers); + void RenderAppletCaptureLayer(std::span framebuffers); Core::TelemetrySession& telemetry_session; Core::Frontend::EmuWindow& emu_window; @@ -64,8 +70,11 @@ private: ProgramManager program_manager; RasterizerOpenGL rasterizer; OGLFramebuffer screenshot_framebuffer; + OGLFramebuffer capture_framebuffer; + OGLRenderbuffer capture_renderbuffer; std::unique_ptr blit_screen; + std::unique_ptr blit_applet; }; } // namespace OpenGL diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index c7c234fd8..c148efef2 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -19,6 +19,7 @@ #include "core/core_timing.h" #include "core/frontend/graphics_context.h" #include "core/telemetry_session.h" +#include "video_core/capture.h" #include "video_core/gpu.h" #include "video_core/renderer_vulkan/present/util.h" #include "video_core/renderer_vulkan/renderer_vulkan.h" @@ -38,6 +39,20 @@ namespace Vulkan { namespace { + +constexpr VkExtent2D CaptureImageSize{ + .width = VideoCore::Capture::LinearWidth, + .height = VideoCore::Capture::LinearHeight, +}; + +constexpr VkExtent3D CaptureImageExtent{ + .width = VideoCore::Capture::LinearWidth, + .height = VideoCore::Capture::LinearHeight, + .depth = VideoCore::Capture::LinearDepth, +}; + +constexpr VkFormat CaptureFormat = VK_FORMAT_A8B8G8R8_UNORM_PACK32; + std::string GetReadableVersion(u32 version) { return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), VK_VERSION_PATCH(version)); @@ -100,11 +115,11 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, surface), blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler), - blit_screenshot(device_memory, device, memory_allocator, present_manager, scheduler), - blit_application_layer(device_memory, device, memory_allocator, present_manager, scheduler), + blit_capture(device_memory, device, memory_allocator, present_manager, scheduler), + blit_applet(device_memory, device, memory_allocator, present_manager, scheduler), rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, scheduler), - application_frame() { + applet_frame() { if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { turbo_mode.emplace(instance, dld); scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); @@ -127,6 +142,8 @@ void RendererVulkan::Composite(std::span framebu SCOPE_EXIT({ render_window.OnFrameDisplayed(); }); + RenderAppletCaptureLayer(framebuffers); + if (!render_window.IsShown()) { return; } @@ -169,30 +186,20 @@ void RendererVulkan::Report() const { telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); } -void Vulkan::RendererVulkan::RenderScreenshot( - std::span framebuffers) { - if (!renderer_settings.screenshot_requested) { - return; - } - - constexpr VkFormat ScreenshotFormat{VK_FORMAT_B8G8R8A8_UNORM}; - const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; - +vk::Buffer RendererVulkan::RenderToBuffer(std::span framebuffers, + const Layout::FramebufferLayout& layout, VkFormat format, + VkDeviceSize buffer_size) { auto frame = [&]() { Frame f{}; - f.image = CreateWrappedImage(memory_allocator, VkExtent2D{layout.width, layout.height}, - ScreenshotFormat); - f.image_view = CreateWrappedImageView(device, f.image, ScreenshotFormat); - f.framebuffer = blit_screenshot.CreateFramebuffer(layout, *f.image_view, ScreenshotFormat); + f.image = + CreateWrappedImage(memory_allocator, VkExtent2D{layout.width, layout.height}, format); + f.image_view = CreateWrappedImageView(device, f.image, format); + f.framebuffer = blit_capture.CreateFramebuffer(layout, *f.image_view, format); return f; }(); - blit_screenshot.DrawToFrame(rasterizer, &frame, framebuffers, layout, 1, - VK_FORMAT_B8G8R8A8_UNORM); - - const auto dst_buffer = CreateWrappedBuffer( - memory_allocator, static_cast(layout.width * layout.height * 4), - MemoryUsage::Download); + auto dst_buffer = CreateWrappedBuffer(memory_allocator, buffer_size, MemoryUsage::Download); + blit_capture.DrawToFrame(rasterizer, &frame, framebuffers, layout, 1, format); scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([&](vk::CommandBuffer cmdbuf) { @@ -200,15 +207,68 @@ void Vulkan::RendererVulkan::RenderScreenshot( VkExtent3D{layout.width, layout.height, 1}); }); - // Ensure the copy is fully completed before saving the screenshot + // Ensure the copy is fully completed before saving the capture scheduler.Finish(); - // Copy backing image data to the QImage screenshot buffer + // Copy backing image data to the capture buffer dst_buffer.Invalidate(); + return dst_buffer; +} + +void RendererVulkan::RenderScreenshot(std::span framebuffers) { + if (!renderer_settings.screenshot_requested) { + return; + } + + const auto& layout{renderer_settings.screenshot_framebuffer_layout}; + const auto dst_buffer = RenderToBuffer(framebuffers, layout, VK_FORMAT_B8G8R8A8_UNORM, + layout.width * layout.height * 4); + std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(), dst_buffer.Mapped().size()); renderer_settings.screenshot_complete_callback(false); renderer_settings.screenshot_requested = false; } +std::vector RendererVulkan::GetAppletCaptureBuffer() { + using namespace VideoCore::Capture; + + std::vector out(VideoCore::Capture::TiledSize); + + if (!applet_frame.image) { + return out; + } + + const auto dst_buffer = + CreateWrappedBuffer(memory_allocator, VideoCore::Capture::TiledSize, MemoryUsage::Download); + + scheduler.RequestOutsideRenderPassOperationContext(); + scheduler.Record([&](vk::CommandBuffer cmdbuf) { + DownloadColorImage(cmdbuf, *applet_frame.image, *dst_buffer, CaptureImageExtent); + }); + + // Ensure the copy is fully completed before writing the capture + scheduler.Finish(); + + // Swizzle image data to the capture buffer + dst_buffer.Invalidate(); + Tegra::Texture::SwizzleTexture(out, dst_buffer.Mapped(), BytesPerPixel, LinearWidth, + LinearHeight, LinearDepth, BlockHeight, BlockDepth); + + return out; +} + +void RendererVulkan::RenderAppletCaptureLayer( + std::span framebuffers) { + if (!applet_frame.image) { + applet_frame.image = CreateWrappedImage(memory_allocator, CaptureImageSize, CaptureFormat); + applet_frame.image_view = CreateWrappedImageView(device, applet_frame.image, CaptureFormat); + applet_frame.framebuffer = blit_applet.CreateFramebuffer( + VideoCore::Capture::Layout, *applet_frame.image_view, CaptureFormat); + } + + blit_applet.DrawToFrame(rasterizer, &applet_frame, framebuffers, VideoCore::Capture::Layout, 1, + CaptureFormat); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index ed9c7af7f..fb9d83412 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -48,6 +48,8 @@ public: void Composite(std::span framebuffers) override; + std::vector GetAppletCaptureBuffer() override; + VideoCore::RasterizerInterface* ReadRasterizer() override { return &rasterizer; } @@ -59,7 +61,11 @@ public: private: void Report() const; + vk::Buffer RenderToBuffer(std::span framebuffers, + const Layout::FramebufferLayout& layout, VkFormat format, + VkDeviceSize buffer_size); void RenderScreenshot(std::span framebuffers); + void RenderAppletCaptureLayer(std::span framebuffers); Core::TelemetrySession& telemetry_session; Tegra::MaxwellDeviceMemoryManager& device_memory; @@ -79,12 +85,12 @@ private: Swapchain swapchain; PresentManager present_manager; BlitScreen blit_swapchain; - BlitScreen blit_screenshot; - BlitScreen blit_application_layer; + BlitScreen blit_capture; + BlitScreen blit_applet; RasterizerVulkan rasterizer; std::optional turbo_mode; - Frame application_frame; + Frame applet_frame; }; } // namespace Vulkan -- cgit v1.2.3