// Copyright 2018 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include "core/hle/kernel/event.h" #include "core/hle/service/service.h" namespace CoreTiming { struct EventType; } namespace Service { namespace VI { struct IGBPBuffer { u32_le magic; u32_le width; u32_le height; u32_le stride; u32_le format; u32_le usage; INSERT_PADDING_WORDS(1); u32_le index; INSERT_PADDING_WORDS(3); u32_le gpu_buffer_id; INSERT_PADDING_WORDS(17); u32_le nvmap_handle; u32_le offset; INSERT_PADDING_WORDS(60); }; static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size"); class BufferQueue { public: BufferQueue(u32 id, u64 layer_id); ~BufferQueue() = default; struct Buffer { enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 }; u32 slot; Status status = Status::Free; IGBPBuffer igbp_buffer; }; void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height); const IGBPBuffer& RequestBuffer(u32 slot) const; void QueueBuffer(u32 slot); boost::optional AcquireBuffer(); void ReleaseBuffer(u32 slot); u32 GetId() const { return id; } private: u32 id; u64 layer_id; std::vector queue; }; struct Layer { Layer(u64 id, std::shared_ptr queue); ~Layer() = default; u64 id; std::shared_ptr buffer_queue; }; struct Display { Display(u64 id, std::string name); ~Display() = default; u64 id; std::string name; std::vector layers; Kernel::SharedPtr vsync_event; }; class NVFlinger { public: NVFlinger(); ~NVFlinger(); /// Opens the specified display and returns the id. u64 OpenDisplay(const std::string& name); /// Creates a layer on the specified display and returns the layer id. u64 CreateLayer(u64 display_id); /// Gets the buffer queue id of the specified layer in the specified display. u32 GetBufferQueueId(u64 display_id, u64 layer_id); /// Gets the vsync event for the specified display. Kernel::SharedPtr GetVsyncEvent(u64 display_id); /// Obtains a buffer queue identified by the id. std::shared_ptr GetBufferQueue(u32 id) const; /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when /// finished. void Compose(); private: /// Returns the display identified by the specified id. Display& GetDisplay(u64 display_id); /// Returns the layer identified by the specified id in the desired display. Layer& GetLayer(u64 display_id, u64 layer_id); std::vector displays; std::vector> buffer_queues; /// Id to use for the next layer that is created, this counter is shared among all displays. u64 next_layer_id = 1; /// Id to use for the next buffer queue that is created, this counter is shared among all /// layers. u32 next_buffer_queue_id = 1; /// CoreTiming event that handles screen composition. CoreTiming::EventType* composition_event; }; class IApplicationDisplayService final : public ServiceFramework { public: IApplicationDisplayService(std::shared_ptr nv_flinger); ~IApplicationDisplayService() = default; private: void GetRelayService(Kernel::HLERequestContext& ctx); void GetSystemDisplayService(Kernel::HLERequestContext& ctx); void GetManagerDisplayService(Kernel::HLERequestContext& ctx); void OpenDisplay(Kernel::HLERequestContext& ctx); void SetLayerScalingMode(Kernel::HLERequestContext& ctx); void OpenLayer(Kernel::HLERequestContext& ctx); void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx); std::shared_ptr nv_flinger; }; /// Registers all VI services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); } // namespace VI } // namespace Service