diff options
| author | Narr the Reg <juangerman-13@hotmail.com> | 2023-09-28 23:45:49 -0600 | 
|---|---|---|
| committer | Narr the Reg <juangerman-13@hotmail.com> | 2023-10-01 11:38:30 -0600 | 
| commit | 35f25882e027fd3c466edd44db1fc1c5bec75bde (patch) | |
| tree | 8f7be0d40cc8ebb2bbbb8fec4113293bc72f5071 | |
| parent | f1f3d490efb0cbe0d0014a0879b9d1bab7dd196b (diff) | |
service: nvnflinger: Implement shared buffer
Co-authored-by: Liam <byteslice@airmail.cc>
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvmap.h | 14 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/buffer_item.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/buffer_slot.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp | 351 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/fb_share_buffer_manager.h | 65 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/graphic_buffer_producer.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/nvnflinger.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/nvnflinger.h | 9 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/ui/fence.h | 3 | ||||
| -rw-r--r-- | src/core/hle/service/nvnflinger/ui/graphic_buffer.h | 4 | ||||
| -rw-r--r-- | src/core/hle/service/vi/vi.cpp | 129 | 
12 files changed, 572 insertions, 22 deletions
| diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d0f76e57e..e02ededfc 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -698,6 +698,8 @@ add_library(core STATIC      hle/service/nvnflinger/consumer_base.cpp      hle/service/nvnflinger/consumer_base.h      hle/service/nvnflinger/consumer_listener.h +    hle/service/nvnflinger/fb_share_buffer_manager.cpp +    hle/service/nvnflinger/fb_share_buffer_manager.h      hle/service/nvnflinger/graphic_buffer_producer.cpp      hle/service/nvnflinger/graphic_buffer_producer.h      hle/service/nvnflinger/hos_binder_driver_server.cpp diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 40c65b430..4c0cc71cd 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -45,13 +45,6 @@ public:          IsSharedMemMapped = 6      }; -private: -    /// Id to use for the next handle that is created. -    u32 next_handle = 0; - -    /// Id to use for the next object that is created. -    u32 next_id = 0; -      struct IocCreateParams {          // Input          u32_le size{}; @@ -113,6 +106,13 @@ private:      NvResult IocParam(std::span<const u8> input, std::span<u8> output);      NvResult IocFree(std::span<const u8> input, std::span<u8> output); +private: +    /// Id to use for the next handle that is created. +    u32 next_handle = 0; + +    /// Id to use for the next object that is created. +    u32 next_id = 0; +      NvCore::Container& container;      NvCore::NvMap& file;  }; diff --git a/src/core/hle/service/nvnflinger/buffer_item.h b/src/core/hle/service/nvnflinger/buffer_item.h index 7fd808f54..3da8cc3aa 100644 --- a/src/core/hle/service/nvnflinger/buffer_item.h +++ b/src/core/hle/service/nvnflinger/buffer_item.h @@ -15,7 +15,7 @@  namespace Service::android { -class GraphicBuffer; +struct GraphicBuffer;  class BufferItem final {  public: diff --git a/src/core/hle/service/nvnflinger/buffer_slot.h b/src/core/hle/service/nvnflinger/buffer_slot.h index d25bca049..d8c9dec3b 100644 --- a/src/core/hle/service/nvnflinger/buffer_slot.h +++ b/src/core/hle/service/nvnflinger/buffer_slot.h @@ -13,7 +13,7 @@  namespace Service::android { -class GraphicBuffer; +struct GraphicBuffer;  enum class BufferState : u32 {      Free = 0, diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp new file mode 100644 index 000000000..469a53244 --- /dev/null +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -0,0 +1,351 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <random> + +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_system_resource.h" +#include "core/hle/service/nvdrv/devices/nvmap.h" +#include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvnflinger/buffer_queue_producer.h" +#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" +#include "core/hle/service/nvnflinger/pixel_format.h" +#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" + +namespace Service::Nvnflinger { + +namespace { + +Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address, +                                        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>( +        kernel, std::addressof(kernel.GetSystemSystemResource().GetBlockInfoManager())); + +    // Allocate memory from secure pool. +    R_TRY(kernel.MemoryManager().AllocateAndOpen( +        pg.get(), size / YUZU_PAGESIZE, +        Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure, +                                             Kernel::KMemoryManager::Direction::FromBack))); + +    // 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; +    const auto state = Kernel::KMemoryState::Io; +    const auto perm = Kernel::KMemoryPermission::UserReadWrite; +    std::mt19937_64 rng{process->GetRandomEntropy(0)}; + +    // Retry up to 64 times to map into alias code range. +    Result res = ResultSuccess; +    int i; +    for (i = 0; i < 64; i++) { +        *out_map_address = alias_code_begin + ((rng() % alias_code_size) * YUZU_PAGESIZE); +        res = page_table.MapPageGroup(*out_map_address, *pg, state, perm); +        if (R_SUCCEEDED(res)) { +            break; +        } +    } + +    // Return failure, if necessary +    R_UNLESS(i < 64, res); + +    // Return the mapped page group. +    *out_page_group = std::move(pg); + +    // We succeeded. +    R_SUCCEED(); +} + +template <typename T> +std::span<u8> SerializeIoc(T& params) { +    return std::span(reinterpret_cast<u8*>(std::addressof(params)), sizeof(T)); +} + +Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) { +    // Create a handle. +    Nvidia::Devices::nvmap::IocCreateParams create_in_params{ +        .size = size, +        .handle = 0, +    }; +    Nvidia::Devices::nvmap::IocCreateParams create_out_params{}; +    R_UNLESS(nvmap.IocCreate(SerializeIoc(create_in_params), SerializeIoc(create_out_params)) == +                 Nvidia::NvResult::Success, +             VI::ResultOperationFailed); + +    // Assign the output handle. +    *out_nv_map_handle = create_out_params.handle; + +    // We succeeded. +    R_SUCCEED(); +} + +Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) { +    // Free the handle. +    Nvidia::Devices::nvmap::IocFreeParams free_in_params{ +        .handle = handle, +    }; +    Nvidia::Devices::nvmap::IocFreeParams free_out_params{}; +    R_UNLESS(nvmap.IocFree(SerializeIoc(free_in_params), SerializeIoc(free_out_params)) == +                 Nvidia::NvResult::Success, +             VI::ResultOperationFailed); + +    // We succeeded. +    R_SUCCEED(); +} + +Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer, +                        u32 size) { +    // Assign the allocated memory to the handle. +    Nvidia::Devices::nvmap::IocAllocParams alloc_in_params{ +        .handle = handle, +        .heap_mask = 0, +        .flags = {}, +        .align = 0, +        .kind = 0, +        .address = GetInteger(buffer), +    }; +    Nvidia::Devices::nvmap::IocAllocParams alloc_out_params{}; +    R_UNLESS(nvmap.IocAlloc(SerializeIoc(alloc_in_params), SerializeIoc(alloc_out_params)) == +                 Nvidia::NvResult::Success, +             VI::ResultOperationFailed); + +    // We succeeded. +    R_SUCCEED(); +} + +Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, +                               Common::ProcessAddress buffer, u32 size) { +    // Get the nvmap device. +    auto nvmap_fd = nvdrv.Open("/dev/nvmap"); +    auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd); +    ASSERT(nvmap != nullptr); + +    // Create a handle. +    R_TRY(CreateNvMapHandle(out_handle, *nvmap, size)); + +    // Ensure we maintain a clean state on failure. +    ON_RESULT_FAILURE { +        ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle))); +    }; + +    // Assign the allocated memory to the handle. +    R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size)); +} + +constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888; +constexpr u32 SharedBufferBlockLinearBpp = 4; + +constexpr u32 SharedBufferBlockLinearWidth = 1280; +constexpr u32 SharedBufferBlockLinearHeight = 768; +constexpr u32 SharedBufferBlockLinearStride = +    SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp; +constexpr u32 SharedBufferNumSlots = 7; + +constexpr u32 SharedBufferWidth = 1280; +constexpr u32 SharedBufferHeight = 720; +constexpr u32 SharedBufferAsync = false; + +constexpr u32 SharedBufferSlotSize = +    SharedBufferBlockLinearWidth * SharedBufferBlockLinearHeight * SharedBufferBlockLinearBpp; +constexpr u32 SharedBufferSize = SharedBufferSlotSize * SharedBufferNumSlots; + +constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] { +    SharedMemoryPoolLayout layout{}; +    layout.num_slots = SharedBufferNumSlots; + +    for (u32 i = 0; i < SharedBufferNumSlots; i++) { +        layout.slots[i].buffer_offset = i * SharedBufferSlotSize; +        layout.slots[i].size = SharedBufferSlotSize; +        layout.slots[i].width = SharedBufferWidth; +        layout.slots[i].height = SharedBufferHeight; +    } + +    return layout; +}(); + +void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) { +    auto buffer = std::make_shared<android::GraphicBuffer>(); +    buffer->width = SharedBufferWidth; +    buffer->height = SharedBufferHeight; +    buffer->stride = SharedBufferBlockLinearStride; +    buffer->format = SharedBufferBlockLinearFormat; +    buffer->buffer_id = handle; +    buffer->offset = slot * SharedBufferSlotSize; +    ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError); +} + +} // namespace + +FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& flinger, +                                           std::shared_ptr<Nvidia::Module> nvdrv) +    : m_system(system), m_flinger(flinger), m_nvdrv(std::move(nvdrv)) {} + +FbShareBufferManager::~FbShareBufferManager() = default; + +Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u64 display_id) { +    std::scoped_lock lk{m_guard}; + +    // Ensure we have not already created a buffer. +    R_UNLESS(m_buffer_id == 0, VI::ResultOperationFailed); + +    // 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)); + +    // Create an nvmap handle for the buffer and assign the memory to it. +    R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, map_address, +                                  SharedBufferSize)); + +    // Record the display id. +    m_display_id = display_id; + +    // Create a layer for the display. +    m_layer_id = m_flinger.CreateLayer(m_display_id).value(); + +    // Set up the buffer. +    m_buffer_id = m_next_buffer_id++; + +    // Get the layer. +    VI::Layer* layer = m_flinger.FindLayer(m_display_id, m_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); + +    // Assign outputs. +    *out_buffer_id = m_buffer_id; +    *out_layer_id = m_layer_id; + +    // We succeeded. +    R_SUCCEED(); +} + +Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, +                                                           s32* out_nvmap_handle, +                                                           SharedMemoryPoolLayout* out_pool_layout, +                                                           u64 buffer_id, +                                                           u64 applet_resource_user_id) { +    std::scoped_lock lk{m_guard}; + +    R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); +    R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound); + +    *out_pool_layout = SharedBufferPoolLayout; +    *out_buffer_size = SharedBufferSize; +    *out_nvmap_handle = m_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); + +    // Get the layer. +    VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id); +    R_UNLESS(layer != nullptr, VI::ResultNotFound); + +    // We succeeded. +    *out_layer = layer; +    R_SUCCEED(); +} + +Result FbShareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, +                                                      std::array<s32, 4>& out_slot_indexes, +                                                      s64* out_target_slot, u64 layer_id) { +    std::scoped_lock lk{m_guard}; + +    // Get the layer. +    VI::Layer* layer; +    R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); + +    // Get the producer. +    auto& producer = layer->GetBufferQueue(); + +    // Get the next buffer from the producer. +    s32 slot; +    R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, +                                    SharedBufferWidth, SharedBufferHeight, +                                    SharedBufferBlockLinearFormat, 0) == android::Status::NoError, +             VI::ResultOperationFailed); + +    // Assign remaining outputs. +    *out_target_slot = slot; +    out_slot_indexes = {0, 1, -1, -1}; + +    // We succeeded. +    R_SUCCEED(); +} + +Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence, +                                                      Common::Rectangle<s32> crop_region, +                                                      u32 transform, s32 swap_interval, +                                                      u64 layer_id, s64 slot) { +    std::scoped_lock lk{m_guard}; + +    // Get the layer. +    VI::Layer* layer; +    R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); + +    // Get the producer. +    auto& producer = layer->GetBufferQueue(); + +    // Request to queue the buffer. +    std::shared_ptr<android::GraphicBuffer> buffer; +    R_UNLESS(producer.RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) == +                 android::Status::NoError, +             VI::ResultOperationFailed); + +    // Queue the buffer to the producer. +    android::QueueBufferInput input{}; +    android::QueueBufferOutput output{}; +    input.crop = crop_region; +    input.fence = fence; +    input.transform = static_cast<android::NativeWindowTransform>(transform); +    input.swap_interval = swap_interval; +    R_UNLESS(producer.QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) == +                 android::Status::NoError, +             VI::ResultOperationFailed); + +    // We succeeded. +    R_SUCCEED(); +} + +Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, +                                                                 u64 layer_id) { +    std::scoped_lock lk{m_guard}; + +    // Get the layer. +    VI::Layer* layer; +    R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); + +    // Get the producer. +    auto& producer = layer->GetBufferQueue(); + +    // Set the event. +    *out_event = std::addressof(producer.GetNativeHandle()); + +    // We succeeded. +    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 new file mode 100644 index 000000000..c809c01b4 --- /dev/null +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/math_util.h" +#include "core/hle/service/nvnflinger/nvnflinger.h" +#include "core/hle/service/nvnflinger/ui/fence.h" + +namespace Kernel { +class KPageGroup; +} + +namespace Service::Nvnflinger { + +struct SharedMemorySlot { +    u64 buffer_offset; +    u64 size; +    s32 width; +    s32 height; +}; +static_assert(sizeof(SharedMemorySlot) == 0x18, "SharedMemorySlot has wrong size"); + +struct SharedMemoryPoolLayout { +    s32 num_slots; +    std::array<SharedMemorySlot, 0x10> slots; +}; +static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); + +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 GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle, +                                         SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, +                                         u64 applet_resource_user_id); +    Result AcquireSharedFrameBuffer(android::Fence* out_fence, std::array<s32, 4>& out_slots, +                                    s64* out_target_slot, u64 layer_id); +    Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, +                                    u32 transform, s32 swap_interval, u64 layer_id, s64 slot); +    Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id); + +private: +    Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id); + +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 = {}; + +    std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; + +    std::mutex m_guard; +    Core::System& m_system; +    Nvnflinger& m_flinger; +    std::shared_ptr<Nvidia::Module> m_nvdrv; +}; + +} // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/graphic_buffer_producer.h b/src/core/hle/service/nvnflinger/graphic_buffer_producer.h index 21d7b31f3..5d7cff7d3 100644 --- a/src/core/hle/service/nvnflinger/graphic_buffer_producer.h +++ b/src/core/hle/service/nvnflinger/graphic_buffer_producer.h @@ -19,6 +19,7 @@ class InputParcel;  #pragma pack(push, 1)  struct QueueBufferInput final {      explicit QueueBufferInput(InputParcel& parcel); +    explicit QueueBufferInput() = default;      void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_,                   NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_, @@ -34,7 +35,6 @@ struct QueueBufferInput final {          *fence_ = fence;      } -private:      s64 timestamp{};      s32 is_auto_timestamp{};      Common::Rectangle<s32> crop{}; diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index 21f31f7a0..a07c621d9 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -17,6 +17,7 @@  #include "core/hle/service/nvdrv/nvdrv.h"  #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/hos_binder_driver_server.h"  #include "core/hle/service/nvnflinger/nvnflinger.h"  #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" @@ -331,4 +332,14 @@ s64 Nvnflinger::GetNextTicks() const {      return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));  } +FbShareBufferManager& Nvnflinger::GetSystemBufferManager() { +    const auto lock_guard = Lock(); + +    if (!system_buffer_manager) { +        system_buffer_manager = std::make_unique<FbShareBufferManager>(system, *this, nvdrv); +    } + +    return *system_buffer_manager; +} +  } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index f478c2bc6..14c783582 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -45,6 +45,9 @@ class BufferQueueProducer;  namespace Service::Nvnflinger { +class FbShareBufferManager; +class HosBinderDriverServer; +  class Nvnflinger final {  public:      explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_); @@ -90,12 +93,16 @@ public:      [[nodiscard]] s64 GetNextTicks() const; +    FbShareBufferManager& GetSystemBufferManager(); +  private:      struct Layer {          std::unique_ptr<android::BufferQueueCore> core;          std::unique_ptr<android::BufferQueueProducer> producer;      }; +    friend class FbShareBufferManager; +  private:      [[nodiscard]] std::unique_lock<std::mutex> Lock() const {          return std::unique_lock{*guard}; @@ -140,6 +147,8 @@ private:      std::shared_ptr<Core::Timing::EventType> multi_composition_event;      std::shared_ptr<Core::Timing::EventType> single_composition_event; +    std::unique_ptr<FbShareBufferManager> system_buffer_manager; +      std::shared_ptr<std::mutex> guard;      Core::System& system; diff --git a/src/core/hle/service/nvnflinger/ui/fence.h b/src/core/hle/service/nvnflinger/ui/fence.h index 536e8156d..177aed758 100644 --- a/src/core/hle/service/nvnflinger/ui/fence.h +++ b/src/core/hle/service/nvnflinger/ui/fence.h @@ -20,6 +20,9 @@ public:      static constexpr Fence NoFence() {          Fence fence;          fence.fences[0].id = -1; +        fence.fences[1].id = -1; +        fence.fences[2].id = -1; +        fence.fences[3].id = -1;          return fence;      } diff --git a/src/core/hle/service/nvnflinger/ui/graphic_buffer.h b/src/core/hle/service/nvnflinger/ui/graphic_buffer.h index 75d1705a8..3eac5cedd 100644 --- a/src/core/hle/service/nvnflinger/ui/graphic_buffer.h +++ b/src/core/hle/service/nvnflinger/ui/graphic_buffer.h @@ -12,8 +12,7 @@  namespace Service::android { -class GraphicBuffer final { -public: +struct GraphicBuffer final {      constexpr GraphicBuffer() = default;      constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_) @@ -77,7 +76,6 @@ public:          return false;      } -private:      u32 magic{};      s32 width{};      s32 height{}; diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 2eb978379..b1bfb9898 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -20,9 +20,12 @@  #include "core/hle/kernel/k_readable_event.h"  #include "core/hle/kernel/k_thread.h"  #include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/nvdrv/devices/nvmap.h"  #include "core/hle/service/nvdrv/nvdata.h" +#include "core/hle/service/nvdrv/nvdrv.h"  #include "core/hle/service/nvnflinger/binder.h"  #include "core/hle/service/nvnflinger/buffer_queue_producer.h" +#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"  #include "core/hle/service/nvnflinger/hos_binder_driver_server.h"  #include "core/hle/service/nvnflinger/nvnflinger.h"  #include "core/hle/service/nvnflinger/parcel.h" @@ -131,8 +134,9 @@ private:  class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {  public: -    explicit ISystemDisplayService(Core::System& system_) -        : ServiceFramework{system_, "ISystemDisplayService"} { +    explicit ISystemDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_) +        : ServiceFramework{system_, "ISystemDisplayService"}, nvnflinger{nvnflinger_} { +        // clang-format off          static const FunctionInfo functions[] = {              {1200, nullptr, "GetZOrderCountMin"},              {1202, nullptr, "GetZOrderCountMax"}, @@ -170,22 +174,126 @@ public:              {3217, nullptr, "SetDisplayCmuLuma"},              {3218, nullptr, "SetDisplayCrcMode"},              {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"}, -            {8225, nullptr, "GetSharedBufferMemoryHandleId"}, -            {8250, nullptr, "OpenSharedLayer"}, +            {8225, &ISystemDisplayService::GetSharedBufferMemoryHandleId, "GetSharedBufferMemoryHandleId"}, +            {8250, &ISystemDisplayService::OpenSharedLayer, "OpenSharedLayer"},              {8251, nullptr, "CloseSharedLayer"}, -            {8252, nullptr, "ConnectSharedLayer"}, +            {8252, &ISystemDisplayService::ConnectSharedLayer, "ConnectSharedLayer"},              {8253, nullptr, "DisconnectSharedLayer"}, -            {8254, nullptr, "AcquireSharedFrameBuffer"}, -            {8255, nullptr, "PresentSharedFrameBuffer"}, -            {8256, nullptr, "GetSharedFrameBufferAcquirableEvent"}, +            {8254, &ISystemDisplayService::AcquireSharedFrameBuffer, "AcquireSharedFrameBuffer"}, +            {8255, &ISystemDisplayService::PresentSharedFrameBuffer, "PresentSharedFrameBuffer"}, +            {8256, &ISystemDisplayService::GetSharedFrameBufferAcquirableEvent, "GetSharedFrameBufferAcquirableEvent"},              {8257, nullptr, "FillSharedFrameBufferColor"},              {8258, nullptr, "CancelSharedFrameBuffer"},              {9000, nullptr, "GetDp2hdmiController"},          }; +        // clang-format on          RegisterHandlers(functions);      }  private: +    void GetSharedBufferMemoryHandleId(HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        const u64 buffer_id = rp.PopRaw<u64>(); + +        LOG_INFO(Service_VI, "called. buffer_id={:#x}", buffer_id); + +        struct OutputParameters { +            s32 nvmap_handle; +            u64 size; +        }; + +        OutputParameters out{}; +        Nvnflinger::SharedMemoryPoolLayout layout{}; +        const auto result = nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId( +            &out.size, &out.nvmap_handle, &layout, buffer_id, 0); + +        ctx.WriteBuffer(&layout, sizeof(layout)); + +        IPC::ResponseBuilder rb{ctx, 6}; +        rb.Push(result); +        rb.PushRaw(out); +    } + +    void OpenSharedLayer(HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        const u64 layer_id = rp.PopRaw<u64>(); + +        LOG_INFO(Service_VI, "(STUBBED) called. layer_id={:#x}", layer_id); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(ResultSuccess); +    } + +    void ConnectSharedLayer(HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        const u64 layer_id = rp.PopRaw<u64>(); + +        LOG_INFO(Service_VI, "(STUBBED) called. layer_id={:#x}", layer_id); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(ResultSuccess); +    } + +    void GetSharedFrameBufferAcquirableEvent(HLERequestContext& ctx) { +        LOG_DEBUG(Service_VI, "called"); + +        IPC::RequestParser rp{ctx}; +        const u64 layer_id = rp.PopRaw<u64>(); + +        Kernel::KReadableEvent* event{}; +        const auto result = nvnflinger.GetSystemBufferManager().GetSharedFrameBufferAcquirableEvent( +            &event, layer_id); + +        IPC::ResponseBuilder rb{ctx, 2, 1}; +        rb.Push(result); +        rb.PushCopyObjects(event); +    } + +    void AcquireSharedFrameBuffer(HLERequestContext& ctx) { +        LOG_DEBUG(Service_VI, "called"); + +        IPC::RequestParser rp{ctx}; +        const u64 layer_id = rp.PopRaw<u64>(); + +        struct OutputParameters { +            android::Fence fence; +            std::array<s32, 4> slots; +            s64 target_slot; +        }; +        static_assert(sizeof(OutputParameters) == 0x40, "OutputParameters has wrong size"); + +        OutputParameters out{}; +        const auto result = nvnflinger.GetSystemBufferManager().AcquireSharedFrameBuffer( +            &out.fence, out.slots, &out.target_slot, layer_id); + +        IPC::ResponseBuilder rb{ctx, 18}; +        rb.Push(result); +        rb.PushRaw(out); +    } + +    void PresentSharedFrameBuffer(HLERequestContext& ctx) { +        LOG_DEBUG(Service_VI, "called"); + +        struct InputParameters { +            android::Fence fence; +            Common::Rectangle<s32> crop_region; +            u32 window_transform; +            s32 swap_interval; +            u64 layer_id; +            s64 surface_id; +        }; +        static_assert(sizeof(InputParameters) == 0x50, "InputParameters has wrong size"); + +        IPC::RequestParser rp{ctx}; +        auto input = rp.PopRaw<InputParameters>(); + +        const auto result = nvnflinger.GetSystemBufferManager().PresentSharedFrameBuffer( +            input.fence, input.crop_region, input.window_transform, input.swap_interval, +            input.layer_id, input.surface_id); +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(result); +    } +      void SetLayerZ(HLERequestContext& ctx) {          IPC::RequestParser rp{ctx};          const u64 layer_id = rp.Pop<u64>(); @@ -228,6 +336,9 @@ private:          rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.          rb.Push<u32>(0);      } + +private: +    Nvnflinger::Nvnflinger& nvnflinger;  };  class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { @@ -453,7 +564,7 @@ private:          IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(ResultSuccess); -        rb.PushIpcInterface<ISystemDisplayService>(system); +        rb.PushIpcInterface<ISystemDisplayService>(system, nv_flinger);      }      void GetManagerDisplayService(HLERequestContext& ctx) { | 
